On Thu, Sep 16, 2021 at 11:00:31PM +0200, Kristaps Dzonsons wrote:
> Hi,
> 
> I'm porting a nonblocking, polling OpenSSL system to libtls.  However, I'm
> not sure how this is non-hackily possible without SSL_pending(3) to detect
> if less data is read with tls_read() than is buffered.
> 
>  writer:
>   tls_write(40)
> 
>  reader:
>   poll(POLLIN, INFTIM) -> POLLIN /* descriptor has a read */
>   tls_read(20) /* 20 bytes read, 20 bytes remain */
>   poll(POLLIN, INFTIM) -> 0 /* data was buffered */
> 
> This introduces tls_pending(3), which calls through to SSL_pending(3), and
> includes a simple example in tls_read(3).
> 
> Beck's tutorial says that "libtls is designed to do the common things you do
> for making TLS connections easy", and I'm not sure my use case meets that
> standard.  If it looks reasonable, however, I can also add the regression
> tests.

In general you should call tls_read() until it retruns TLS_WANT_POLL*.
Then you poll again. So you need to adapt the poll loop a bit but in most
cases this is not hard to do.
 
> Thank you,
> 
> Kristaps

> Index: tls.c
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.c,v
> retrieving revision 1.89
> diff -u -p -r1.89 tls.c
> --- tls.c     1 Feb 2021 15:35:41 -0000       1.89
> +++ tls.c     16 Sep 2021 20:57:32 -0000
> @@ -788,6 +788,16 @@ tls_handshake(struct tls *ctx)
>       return (rv);
>  }
>  
> +size_t
> +tls_pending(const struct tls *ctx)
> +{
> +     
> +     if ((ctx->state & TLS_HANDSHAKE_COMPLETE) != 0)
> +             return 0;
> +
> +     return (size_t)SSL_pending(ctx->ssl_conn);
> +}
> +
>  ssize_t
>  tls_read(struct tls *ctx, void *buf, size_t buflen)
>  {
> Index: tls.h
> ===================================================================
> RCS file: /cvs/src/lib/libtls/tls.h,v
> retrieving revision 1.58
> diff -u -p -r1.58 tls.h
> --- tls.h     22 Jan 2020 06:44:02 -0000      1.58
> +++ tls.h     16 Sep 2021 20:57:32 -0000
> @@ -177,6 +177,7 @@ int tls_connect_socket(struct tls *_ctx,
>  int tls_connect_cbs(struct tls *_ctx, tls_read_cb _read_cb,
>      tls_write_cb _write_cb, void *_cb_arg, const char *_servername);
>  int tls_handshake(struct tls *_ctx);
> +size_t tls_pending(const struct tls *_ctx);
>  ssize_t tls_read(struct tls *_ctx, void *_buf, size_t _buflen);
>  ssize_t tls_write(struct tls *_ctx, const void *_buf, size_t _buflen);
>  int tls_close(struct tls *_ctx);
> Index: man/tls_read.3
> ===================================================================
> RCS file: /cvs/src/lib/libtls/man/tls_read.3,v
> retrieving revision 1.7
> diff -u -p -r1.7 tls_read.3
> --- man/tls_read.3    9 Jul 2019 17:58:33 -0000       1.7
> +++ man/tls_read.3    16 Sep 2021 20:57:32 -0000
> @@ -27,6 +27,7 @@
>  .Nm tls_handshake ,
>  .Nm tls_error ,
>  .Nm tls_close ,
> +.Nm tls_pending ,
>  .Nm tls_reset
>  .Nd use a TLS connection
>  .Sh SYNOPSIS
> @@ -51,6 +52,8 @@
>  .Fn tls_close "struct tls *ctx"
>  .Ft void
>  .Fn tls_reset "struct tls *ctx"
> +.Ft size_t
> +.Fn tls_pending "const struct tls *ctx"
>  .Sh DESCRIPTION
>  .Fn tls_read
>  reads
> @@ -58,6 +61,8 @@ reads
>  bytes of data from the socket into
>  .Fa buf .
>  It returns the amount of data read.
> +.Fn tls_pending
> +returns the number of bytes that may be read without blocking.
>  .Pp
>  .Fn tls_write
>  writes
> @@ -99,6 +104,9 @@ and
>  .Fn tls_write
>  return a size on success or -1 on error.
>  .Pp
> +.Fn tls_pending
> +returns a size or zero if no data is buffered for immediate reading.
> +.Pp
>  .Fn tls_handshake
>  and
>  .Fn tls_close
> @@ -198,6 +206,28 @@ while (len > 0) {
>                       buf += ret;
>                       len -= ret;
>               }
> +     }
> +}
> +\&...
> +.Ed
> +.Pp
> +For non-blocking input, the following example demonstrates how to handle
> +buffered data when the descriptor may have none to read:
> +.Bd -literal -offset indent
> +\&...
> +pfd[0].fd = fd;
> +pfd[0].events = POLLIN;
> +for (;;) {
> +     int timeo;
> +
> +     timeo = tls_pending(tls) ? 0 : INFTIM;
> +     if (poll(pfd, 1, timeo) == -1)
> +             err(1, "poll");
> +     if ((pfd[0].revents & POLLIN) || tls_pending(tls)) {
> +             ssize_t ret;
> +
> +             ret = tls_read(ctx, buf, len);
> +             \&...
>       }
>  }
>  \&...


-- 
:wq Claudio

Reply via email to