Hi
On 14.09.2016, at 14:21, Brent Cook <[email protected]> wrote:
>
> On 14.09.2016, at 13:37, Brent Cook <[email protected]> wrote:
>
> >
> > Once the expectations of the callbacks are finalized, this needs a good
> > explanation in the manual.
>
> [...]
> Generally, what are the expectations of a callback, what should it return
> and when.
>
I have amended the manpage a little and added an example. Turns out I write a
bit wordy, so feel free to re-word.
The example is also longer than the others, but I think this is necessary…
> A good example section and/or regression test would go a long way. We've
> used nc(1) to test a lot of the other libtls features so far. There also are
> some libtls golang bindings in tree under regress, though I'm not sure how
> up-to-date they are.
ok. I am currently "test-driving" the interface with the SSL plugin for Squeak
that I maintain[1] and
I think I can extract something afterwards.
Best regards
-Tobias
[1]:
https://github.com/OpenSmalltalk/opensmalltalk-vm/blob/libtls/platforms/unix/plugins/SqueakSSL/sqUnixLibreSSL.c
diff --git src/lib/libtls/tls_init.3 src/lib/libtls/tls_init.3
index 12dc99a..bbf9e0d 100644
--- src/lib/libtls/tls_init.3
+++ src/lib/libtls/tls_init.3
@@ -189,13 +189,13 @@
.Ft "int"
.Fn tls_connect_socket "struct tls *ctx" "int s" "const char *servername"
.Ft "int"
-.Fn tls_connect_cbs "struct tls *ctx" "ssize_t (*tls_read_cb)(struct tls *ctx,
void *buf, size_t buflen, void *cb_arg)" "ssize_t (*tls_write_cb)(struct tls
*ctx, const void *buf, size_t buflen, void *cb_arg)" "void *cb_arg" "const char
*servername"
+.Fn tls_connect_cbs "struct tls *ctx" "tls_read_cb read_cb" "tls_write_cb
write_cb" "void *cb_arg" "const char *servername"
.Ft "int"
.Fn tls_accept_fds "struct tls *tls" "struct tls **cctx" "int fd_read" "int
fd_write"
.Ft "int"
.Fn tls_accept_socket "struct tls *tls" "struct tls **cctx" "int socket"
.Ft "int"
-.Fn tls_accept_cbs "struct tls *ctx" "struct tls **cctx" "ssize_t
(*tls_read_cb)(struct *ctx, void *buf, size_t buflen, void *cb_arg)" "ssize_t
(*tls_write_cb)(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg)"
"void *cb_arg"
+.Fn tls_accept_cbs "struct tls *ctx" "struct tls **cctx" "tls_read_cb read_cb"
"tls_write_cb write_cb" "void *cb_arg"
.Ft "int"
.Fn tls_handshake "struct tls *ctx"
.Ft "ssize_t"
@@ -204,6 +204,10 @@
.Fn tls_write "struct tls *ctx" "const void *buf" "size_t buflen"
.Ft "int"
.Fn tls_close "struct tls *ctx"
+.Ft typedef ssize_t
+.Fn (*tls_read_cb) "void *ctx" "void *buf" "size_t buflen" "void *cb_arg"
+.Ft typedef ssize_t
+.Fn (*tls_write_cb) "void *ctx" "const void *buf" "size_t buflen" "void
*cb_arg"
.Sh DESCRIPTION
The
.Nm tls
@@ -564,6 +568,35 @@ connects a client context to a pair of existing file
descriptors.
.Fn tls_connect_socket
connects a client context to an already established socket connection.
.It
+.Fn tls_connect_cbs
+connects a client context to a custom peer, with the data transfer handled by a
+read and a write callback provided by the caller. The
+.Fa read_cb
+callback should do what is necessary to read from the peer and write resulting
+data to its
+.Fa buf .
+Likewise, the
+.Fa write_cb
+callback should do what is necessary to write the data from its
+.Fa buf
+to the peer. If the callbacks represent non-blocking communication or if there
+is more data to be read or written, respectively, than stated by
+.Fa buflen ,
+the callbacks should return
+.Dv TLS_WANT_POLLOUT
+for more data
+.Em for
+the peer or
+.DV TLS_WANT_POLLIN
+for more data
+.Em from
+the peer. The callbacks can be passed arbitrary data in
+.Fa cb_arg .
+This will be what was passed to
+.Fn tls_connect_cbs
+in its
+.Fa cb_arg .
+.It
.Fn tls_accept_fds
creates a new context suitable for reading and writing on an existing pair of
file descriptors and returns it in
@@ -578,6 +611,40 @@ established socket connection and returns it in
A configured server context should be passed in
.Fa ctx .
.It
+.Fn tls_accept_cbs
+creates a new context suitable for reading from and writing to a peer and
+returns it in
+.Fa *cctx .
+The data transfer for
+.Fa *cctx
+is handled by a read and a write callback provided by the
+caller. The
+.Fa read_cb
+callback should do what is necessary to read from the peer and write resulting
+data to its
+.Fa buf .
+Likewise, the
+.Fa write_cb
+callback should do what is necessary to write the data from its
+.Fa buf
+to the peer. If the callbacks represent non-blocking communication or if there
+is more data to be read or written, respectively, than stated by
+.Fa buflen ,
+the callbacks should return
+.Dv TLS_WANT_POLLOUT
+for more data
+.Em for
+the peer or
+.DV TLS_WANT_POLLIN
+for more data
+.Em from
+the peer. The callbacks can be passed arbitrary data in
+.Fa cb_arg .
+This will be what was passed to
+.Fn tls_accept_cbs
+in its
+.Fa cb_arg .
+.It
.Fn tls_handshake
performs the TLS handshake.
It is only necessary to call this function if you need to guarantee that the
@@ -708,6 +775,47 @@ while (len > 0) {
}
\&...
.Ed
+.Pp
+The following example demonstrates how to use callbacks to wrap communication
+in a client:
+.Bd -literal -offset indent
+\&...
+ssize_t
+rcb(struct tls *ctx, void *buf, size_t buflen, void *cb_arg)
+{
+ int fd = (int)cb_arg;
+ ssize_t result = read(fd, buf, buflen);
+ if (result <= 0)
+ return TLS_WANT_POLLIN;
+ return result;
+}
+
+ssize_t
+wcb(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg)
+{
+ int fd = (int)cb_arg;
+ ssize_t result = write(fd, buf, buflen);
+ if (result <= 0)
+ return TLS_WANT_POLLOUT;
+ return result;
+}
+\&...
+int socketfd = socket(...);
+int ok = tls_connect_cbs(ctx, rcb, wcb, /* cb_arg */ (void*)socketfd,
servername);
+\&...
+while (len > 0) {
+ ssize_t ret;
+
+ ret = tls_write(ctx, buf, len);
+ if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT)
+ continue;
+ if (ret < 0)
+ err(1, "tls_write: %s", tls_error(ctx));
+ buf += ret;
+ len -= ret;
+}
+\&...
+.Ed
.Sh ERRORS
The
.Fn tls_config_error