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.

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);
+		\&...
 	}
 }
 \&...

Reply via email to