Skip to content

Commit d6b57ac

Browse files
transport: finalise the vtable API
- net_posix.c calls recv and send directly rather than wolfIO_Recv and wolfIO_Send, which link only under USE_WOLFSSL_IO. - WolfCertConnectFn and the connect_cb / connect_ctx fields are gone; dial() takes only the transport. - The three config structs hold a WolfCertTransport by value, copied when the connection opens, and wolfcert_transport_fd() replaces wolfcert_transport_is_fd_backed(). - read and write take two timeout_ms modes, 0 and negative. ARCHITECTURE 4.6 also states that honouring len is the transport's responsibility, and that wolfcert_http_session_fd() returns an O_NONBLOCK descriptor. - Makefile.am keeps the conditional test_net entry with check_PROGRAMS.
1 parent 3661868 commit d6b57ac

13 files changed

Lines changed: 296 additions & 267 deletions

File tree

Makefile.am

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ if WOLFCERT_BUILD_TESTS
116116
check_PROGRAMS = \
117117
test_smoke test_keygen test_csr test_store test_http test_transport \
118118
test_parse_negative test_tls_http
119+
if WOLFCERT_HAVE_BUILTIN_TRANSPORT
120+
check_PROGRAMS += test_net
121+
endif
119122

120123
test_smoke_SOURCES = tests/unit/test_smoke.c
121124
test_smoke_LDADD = libwolfcert.la $(WOLFSSL_LIBS)
@@ -125,9 +128,6 @@ test_csr_SOURCES = tests/unit/test_csr.c
125128
test_csr_LDADD = libwolfcert.la $(WOLFSSL_LIBS)
126129
test_store_SOURCES = tests/unit/test_store.c
127130
test_store_LDADD = libwolfcert.la $(WOLFSSL_LIBS)
128-
if WOLFCERT_HAVE_BUILTIN_TRANSPORT
129-
check_PROGRAMS += test_net
130-
endif
131131
test_transport_SOURCES = tests/unit/test_transport.c
132132
test_transport_LDADD = libwolfcert.la $(WOLFSSL_LIBS)
133133

docs/ARCHITECTURE.md

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ typedef struct WolfCertTransport {
422422
```
423423

424424
Set it on `WolfCertServerCfg.transport` (or `WolfCertHttpRequest` /
425-
`WolfCertHttpSessionCfg`). Leaving it `NULL` selects the built-in POSIX
425+
`WolfCertHttpSessionCfg`). Leaving it zeroed selects the built-in POSIX
426426
instance in `src/net_posix.c`, which is an ordinary implementation of this
427427
same vtable rather than a privileged path.
428428

@@ -440,16 +440,27 @@ The contract:
440440
above zero bounds the whole connect attempt. Zero or less imposes no limit
441441
of wolfCert's, leaving the stack's own default.
442442
- **`read` / `write`'s `timeout_ms` carries the blocking mode**, and means
443-
something different from `connect`'s. wolfCert passes only two values.
443+
something different from `connect`'s. It takes two values and no others.
444444
`0` asks the call never to block: return `WOLFCERT_ERR_WANT_READ` or
445-
`WOLFCERT_ERR_WANT_WRITE` rather than wait. `-1` asks it to block until
446-
bytes move.
445+
`WOLFCERT_ERR_WANT_WRITE` rather than wait. A negative value asks it to
446+
block until bytes move. If your stack has its own receive or send timeout,
447+
implement the negative case with a call that lets it apply, rather than an
448+
unbounded wait around a non-blocking transfer: the second shape silently
449+
discards whatever the application configured.
450+
- **Never write more than `len` bytes.** wolfCert rejects a count larger than
451+
it asked for, but that only keeps the overrun out of its own buffers - the
452+
write into yours has already happened, so honouring `len` is the transport's
453+
responsibility and exceeding it is undefined.
447454
- **`disconnect` runs exactly once per successful `connect`**, on every error
448455
path included. A failed `connect` is never paired with one.
449456
- **`ctx` is transport-wide** (the stack instance, say), distinct from the
450-
per-connection handle. The transport struct must outlive its connections.
457+
per-connection handle. Whatever it points at must outlive the connection.
458+
- **The struct itself need not.** Opening a connection copies it, so the config
459+
may be a temporary — and a later change to your copy has no effect on a
460+
connection already open.
451461
- **All four callbacks are required.** An incomplete vtable is rejected with
452-
`WOLFCERT_ERR_BAD_ARG` before anything is dialled.
462+
`WOLFCERT_ERR_BAD_ARG` before anything is dialled, and so is a half-filled
463+
one: only a wholly zeroed `transport` asks for the built-in instance.
453464

454465
TLS needs no extra work from the transport. wolfCert registers its own
455466
wolfSSL CBIO pair against the open connection, so records flow through the
@@ -459,15 +470,10 @@ same `read`/`write` as plain HTTP:
459470
wolfSSL_read/write -> wolfcert_cbio_recv/send -> t->read / t->write -> your stack
460471
```
461472

462-
`WolfCertServerCfg.connect_cb` is the deprecated predecessor: it yields a
463-
socket descriptor rather than an opaque handle, which is exactly what a
464-
non-socket stack cannot supply. It still works, adapted internally onto the
465-
POSIX byte path, but setting both it and `transport` is `WOLFCERT_ERR_BAD_ARG`.
466-
467473
Building with `WOLFCERT_ENABLE_BUILTIN_TRANSPORT=OFF` (CMake) or
468474
`--disable-builtin-transport` (autoconf) drops `src/net_posix.c` from the
469475
library entirely, so a target with no sockets links no socket code. A config
470-
that then leaves `transport` NULL fails with `WOLFCERT_ERR_BAD_ARG`.
476+
that then leaves `transport` zeroed fails with `WOLFCERT_ERR_BAD_ARG`.
471477

472478
### 4.7 Putting it together
473479

src/est/est_client.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,6 @@ static void fill_common(const WolfCertServerCfg* srv, WolfCertHttpRequest* req)
6464
req->client_cert_len = srv->client_cert_len;
6565
req->client_key = srv->client_key;
6666
req->client_key_len = srv->client_key_len;
67-
req->connect_cb = srv->connect_cb;
68-
req->connect_ctx = srv->connect_ctx;
6967
req->transport = srv->transport;
7068
}
7169

@@ -494,8 +492,6 @@ static int est_session_open_common(const WolfCertServerCfg* srv, int nonblocking
494492
.client_key_len = srv->client_key_len,
495493
.allow_post_handshake_auth = srv->proto_opts.est.allow_post_handshake_auth,
496494
.nonblocking = nonblocking,
497-
.connect_cb = srv->connect_cb,
498-
.connect_ctx = srv->connect_ctx,
499495
.transport = srv->transport,
500496
.heap = heap,
501497
};

src/http.c

Lines changed: 41 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -314,58 +314,45 @@ static int basic_auth_header(const char* user, const char* pass,
314314
/* ---- TCP + TLS I/O ------------------------------------------------------ */
315315

316316
typedef struct {
317-
const WolfCertTransport* t;
317+
WolfCertTransport t;
318318
void* handle;
319319
WOLFSSL* ssl;
320320
int io_timeout_ms; /* 0 nonblocking, < 0 unbounded */
321321
unsigned int connected : 1;
322322
} WolfCertConn;
323323

324-
/* Open a connection and attach the transport that owns it. An explicit
325-
* transport wins; a legacy connect_cb is dialled here and adapted, since it
326-
* yields a descriptor rather than opening through a vtable. */
324+
/* Open a connection and take a copy of the transport that owns it. */
327325
static int dial(WolfCertConn* c, const char* host, int port, int timeout_ms,
328-
const WolfCertTransport* transport,
329-
WolfCertConnectFn connect_cb, void* connect_ctx)
326+
const WolfCertTransport* transport)
330327
{
331-
const WolfCertTransport* t = transport;
328+
int cbs;
332329
int rc;
333330

334-
#ifndef WOLFCERT_HAVE_BUILTIN_TRANSPORT
335-
(void)connect_cb;
336-
(void)connect_ctx;
331+
cbs = (transport->connect != NULL) + (transport->read != NULL) +
332+
(transport->write != NULL) + (transport->disconnect != NULL);
337333

338-
if (t == NULL)
334+
if (cbs == 4) {
335+
c->t = *transport;
336+
}
337+
else if (cbs != 0 || transport->ctx != NULL) {
339338
return WOLFCERT_ERR(WOLFCERT_ERR_BAD_ARG, "http",
340-
"this build has no built-in transport");
341-
#else
342-
if (t == NULL && connect_cb != NULL) {
343-
rc = wolfcert_legacy_connect(connect_cb, connect_ctx, host, port,
344-
timeout_ms, &c->handle);
345-
if (rc != WOLFCERT_OK)
346-
return rc;
347-
348-
c->t = &wolfcert_legacy_transport;
349-
c->connected = 1;
350-
return WOLFCERT_OK;
339+
"transport must set all four callbacks, or nothing at all to take "
340+
"the built-in one");
351341
}
352-
353-
if (t == NULL)
354-
t = &wolfcert_posix_transport;
355-
#endif
356-
357-
/* Validate the whole vtable */
358-
if (t->connect == NULL || t->read == NULL || t->write == NULL ||
359-
t->disconnect == NULL)
342+
else {
343+
#ifdef WOLFCERT_HAVE_BUILTIN_TRANSPORT
344+
c->t = wolfcert_posix_transport;
345+
#else
360346
return WOLFCERT_ERR(WOLFCERT_ERR_BAD_ARG, "http",
361-
"transport must supply connect, read, write and disconnect");
347+
"this build has no built-in transport");
348+
#endif
349+
}
362350

363-
rc = t->connect(t->ctx, host, port, timeout_ms, &c->handle);
351+
rc = c->t.connect(c->t.ctx, host, port, timeout_ms, &c->handle);
364352
if (rc != WOLFCERT_OK)
365353
return rc < 0 ? rc : WOLFCERT_ERR(WOLFCERT_ERR_IO, "http",
366354
"transport connect returned %d, not 0 or a WOLFCERT_ERR_*", rc);
367355

368-
c->t = t;
369356
c->connected = 1;
370357
return WOLFCERT_OK;
371358
}
@@ -374,7 +361,7 @@ static int dial(WolfCertConn* c, const char* host, int port, int timeout_ms,
374361
static void conn_close(WolfCertConn* c)
375362
{
376363
if (c->connected) {
377-
(void)c->t->disconnect(c->t->ctx, c->handle);
364+
(void)c->t.disconnect(c->t.ctx, c->handle);
378365
c->connected = 0;
379366
}
380367
}
@@ -440,8 +427,8 @@ static int conn_write(WolfCertConn* c, const void* buf, size_t len)
440427
w = wolfSSL_write(c->ssl, p + n, (int)(len - n));
441428
}
442429
else {
443-
w = c->t->write(c->t->ctx, c->handle, p + n, len - n,
444-
c->io_timeout_ms);
430+
w = c->t.write(c->t.ctx, c->handle, p + n, len - n,
431+
c->io_timeout_ms);
445432
if (w > 0 && (size_t)w > len - n)
446433
return WOLFCERT_ERR_IO;
447434
}
@@ -467,8 +454,8 @@ static int wolfcert_cbio_recv(WOLFSSL* ssl, char* buf, int sz, void* ctx)
467454
if (c == NULL || sz <= 0)
468455
return WOLFSSL_CBIO_ERR_GENERAL;
469456

470-
r = c->t->read(c->t->ctx, c->handle, (uint8_t*)buf, (size_t)sz,
471-
c->io_timeout_ms);
457+
r = c->t.read(c->t.ctx, c->handle, (uint8_t*)buf, (size_t)sz,
458+
c->io_timeout_ms);
472459
if (r > sz)
473460
return WOLFSSL_CBIO_ERR_GENERAL;
474461
if (r > 0)
@@ -499,8 +486,8 @@ static int wolfcert_cbio_send(WOLFSSL* ssl, char* buf, int sz, void* ctx)
499486
if (c == NULL || sz <= 0)
500487
return WOLFSSL_CBIO_ERR_GENERAL;
501488

502-
r = c->t->write(c->t->ctx, c->handle, (const uint8_t*)buf, (size_t)sz,
503-
c->io_timeout_ms);
489+
r = c->t.write(c->t.ctx, c->handle, (const uint8_t*)buf, (size_t)sz,
490+
c->io_timeout_ms);
504491
if (r > sz)
505492
return WOLFSSL_CBIO_ERR_GENERAL;
506493
if (r > 0)
@@ -524,10 +511,9 @@ static int conn_read(WolfCertConn* c, void* buf, size_t len)
524511
int r;
525512

526513
if (c->ssl == NULL) {
527-
r = c->t->read(c->t->ctx, c->handle, (uint8_t*)buf, len,
528-
c->io_timeout_ms);
529-
/* A 0 spins the read-until-close loop; a count above len means the
530-
* transport already overran the buffer. Neither is passed on. */
514+
r = c->t.read(c->t.ctx, c->handle, (uint8_t*)buf, len,
515+
c->io_timeout_ms);
516+
/* Turn a 0 into a close, and refuse a count larger than len. */
531517
if (r == 0)
532518
return WOLFCERT_ERR_CONN_CLOSED;
533519
if (r > 0 && (size_t)r > len)
@@ -1167,10 +1153,6 @@ int wolfcert_http_request(const WolfCertHttpRequest* req, WolfCertHttpResponse*
11671153
if (req == NULL || resp == NULL || req->url == NULL || req->method == NULL)
11681154
return WOLFCERT_ERR_BAD_ARG;
11691155

1170-
if (req->connect_cb != NULL && req->transport != NULL)
1171-
return WOLFCERT_ERR(WOLFCERT_ERR_BAD_ARG, "http",
1172-
"set either connect_cb or transport, not both");
1173-
11741156
memset(resp, 0, sizeof(*resp));
11751157
void* heap = req->heap ? req->heap : wolfcert_default_heap();
11761158
resp->heap = heap;
@@ -1182,12 +1164,12 @@ int wolfcert_http_request(const WolfCertHttpRequest* req, WolfCertHttpResponse*
11821164
if (rc != WOLFCERT_OK)
11831165
return rc;
11841166

1185-
WolfCertConn c = { 0 };
1167+
WolfCertConn c;
11861168
WOLFSSL_CTX* ctx = NULL;
11871169

1170+
memset(&c, 0, sizeof(c));
11881171
c.io_timeout_ms = -1;
1189-
rc = dial(&c, u.host, u.port, req->timeout_ms, req->transport,
1190-
req->connect_cb, req->connect_ctx);
1172+
rc = dial(&c, u.host, u.port, req->timeout_ms, &req->transport);
11911173
if (rc != WOLFCERT_OK) {
11921174
wolfcert_http_url_free(&u);
11931175
return rc;
@@ -1243,10 +1225,6 @@ int wolfcert_http_session_open(const WolfCertHttpSessionCfg* cfg,
12431225
if (cfg == NULL || cfg->base_url == NULL || out == NULL)
12441226
return WOLFCERT_ERR_BAD_ARG;
12451227

1246-
if (cfg->connect_cb != NULL && cfg->transport != NULL)
1247-
return WOLFCERT_ERR(WOLFCERT_ERR_BAD_ARG, "http",
1248-
"set either connect_cb or transport, not both");
1249-
12501228
void* heap = cfg->heap ? cfg->heap : wolfcert_default_heap();
12511229

12521230
WolfCertHttpSession* s = (WolfCertHttpSession*)WOLFCERT_XMALLOC(sizeof(*s), heap);
@@ -1266,7 +1244,7 @@ int wolfcert_http_session_open(const WolfCertHttpSessionCfg* cfg,
12661244

12671245
s->conn.io_timeout_ms = cfg->nonblocking ? 0 : -1;
12681246
rc = dial(&s->conn, s->base.host, s->base.port, cfg->timeout_ms,
1269-
cfg->transport, cfg->connect_cb, cfg->connect_ctx);
1247+
&cfg->transport);
12701248
if (rc != WOLFCERT_OK) {
12711249
wolfcert_http_session_close(s);
12721250
return rc;
@@ -1320,12 +1298,10 @@ int wolfcert_http_session_fd(const WolfCertHttpSession* s)
13201298
#ifdef WOLFCERT_HAVE_BUILTIN_TRANSPORT
13211299
if (s == NULL || !s->conn.connected)
13221300
return -1;
1323-
if (!wolfcert_transport_is_fd_backed(s->conn.t))
1324-
return -1;
13251301

1326-
return (int)(intptr_t)s->conn.handle;
1302+
return wolfcert_transport_fd(&s->conn.t, s->conn.handle);
13271303
#else
1328-
(void)s; /* no fd-backed transport exists in this build */
1304+
(void)s; /* no descriptor-backed transport exists in this build */
13291305
return -1;
13301306
#endif
13311307
}
@@ -1457,8 +1433,8 @@ static int nb_write(WolfCertConn* c, const uint8_t* buf, size_t len, size_t* off
14571433
return WOLFCERT_ERR_IO;
14581434
}
14591435

1460-
int r = c->t->write(c->t->ctx, c->handle, buf + *off, len - *off,
1461-
c->io_timeout_ms);
1436+
int r = c->t.write(c->t.ctx, c->handle, buf + *off, len - *off,
1437+
c->io_timeout_ms);
14621438
if (r > 0 && (size_t)r > len - *off)
14631439
return WOLFCERT_ERR_IO;
14641440
if (r > 0) {
@@ -1539,9 +1515,9 @@ static int nb_read_some(WolfCertHttpSession* s, int* ended)
15391515
return WOLFCERT_ERR_IO;
15401516
}
15411517

1542-
int r = s->conn.t->read(s->conn.t->ctx, s->conn.handle,
1543-
s->sm_rx + s->sm_rx_len,
1544-
WOLFCERT_HTTP_READ_CHUNK, s->conn.io_timeout_ms);
1518+
int r = s->conn.t.read(s->conn.t.ctx, s->conn.handle,
1519+
s->sm_rx + s->sm_rx_len,
1520+
WOLFCERT_HTTP_READ_CHUNK, s->conn.io_timeout_ms);
15451521
if (r > 0) {
15461522
if ((size_t)r > WOLFCERT_HTTP_READ_CHUNK)
15471523
return WOLFCERT_ERR_IO;

src/internal.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -311,14 +311,11 @@ WOLFCERT_TEST_VIS void wolfcert_hex_encode(const uint8_t* in, size_t in_len,
311311
WOLFCERT_TEST_VIS int wolfcert_parse_ip(const char* s, uint8_t out[16],
312312
size_t* out_len);
313313

314-
/* Built-in POSIX transport, and the adapter used when a config still sets the
315-
* deprecated connect_cb. Both are fd-backed, which session_fd() relies on. */
314+
/* Built-in POSIX transport. */
316315
extern const WolfCertTransport wolfcert_posix_transport;
317-
extern const WolfCertTransport wolfcert_legacy_transport;
318-
int wolfcert_transport_is_fd_backed(const WolfCertTransport* t);
319-
int wolfcert_legacy_connect(WolfCertConnectFn cb, void* cb_ctx,
320-
const char* host, int port, int timeout_ms,
321-
void** conn);
316+
/* The descriptor behind a wolfcert_posix_transport connection; -1 for a
317+
* handle any other transport minted. */
318+
int wolfcert_transport_fd(const WolfCertTransport* t, void* conn);
322319

323320
int wolfcert_pem_cert_to_der(const uint8_t* pem, size_t pem_len,
324321
WolfCertBuffer* out_der, void* heap);

0 commit comments

Comments
 (0)