diff options
| author | Garrett D'Amore <garrett@damore.org> | 2018-01-24 17:38:16 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2018-02-01 16:11:38 -0800 |
| commit | 3dae30ed5e543dc73fc993334ef56b9b157b9b3c (patch) | |
| tree | d7e294b5d544aa18e8fc8749abfe605a05fa4bd7 | |
| parent | 5914e40c2ff7fcf346c90705785f3fb7650a9fdc (diff) | |
| download | nng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.tar.gz nng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.tar.bz2 nng-3dae30ed5e543dc73fc993334ef56b9b157b9b3c.zip | |
fixes #173 Define public HTTP server API
This introduces enough of the HTTP API to support fully server
applications, including creation of websocket style protocols,
pluggable handlers, and so forth.
We have also introduced scatter/gather I/O (rudimentary) for
aios, and made other enhancements to the AIO framework. The
internals of the AIOs themselves are now fully private, and we
have eliminated the aio->a_addr member, with plans to remove the
pipe and possibly message members as well.
A few other minor issues were found and fixed as well.
The HTTP API includes request, response, and connection objects,
which can be used with both servers and clients. It also defines
the HTTP server and handler objects, which support server applications.
Support for client applications will require a client object to be
exposed, and that should be happening shortly.
None of this is "documented" yet, bug again, we will follow up shortly.
69 files changed, 3534 insertions, 2311 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index f3f39241..439001d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,6 +105,12 @@ if (NNG_ENABLE_TLS) set(NNG_SUPP_TLS ON) endif() +option (NNG_ENABLE_HTTP "Enable HTTP API" ON) +if (NNG_ENABLE_HTTP) + set(NNG_SUPP_HTTP ON) +endif() +mark_as_advanced(NNG_ENABLE_HTTP) + option (NNG_PROTO_BUS0 "Enable BUSv0 protocol." ON) if (NNG_PROTO_BUS0) add_definitions (-DNNG_HAVE_BUS0) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7bf3937..48262751 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -149,6 +149,8 @@ add_subdirectory(transport/zerotier) include_directories(AFTER SYSTEM ${PROJECT_SOURCE_DIR}/src ${NNG_REQUIRED_INCLUDES}) +add_definitions(${NNG_DEFINES}) + # Provide same folder structure in IDE as on disk foreach (f ${NNG_SOURCES}) # Get the path of the file relative to source directory diff --git a/src/core/aio.c b/src/core/aio.c index a036a606..341b218e 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -54,6 +54,57 @@ static nni_list nni_aio_expire_aios; // if it comes back nonzero (NNG_ESTATE) then it must simply discard the // request and return. +// An nni_aio is an async I/O handle. +struct nng_aio { + int a_result; // Result code (nng_errno) + size_t a_count; // Bytes transferred (I/O only) + nni_time a_expire; // Absolute timeout + nni_duration a_timeout; // Relative timeout + + // These fields are private to the aio framework. + nni_cv a_cv; + unsigned a_fini : 1; // shutting down (no new operations) + unsigned a_done : 1; // operation has completed + unsigned a_pend : 1; // completion routine pending + unsigned a_active : 1; // aio was started + unsigned a_expiring : 1; // expiration callback in progress + unsigned a_waiting : 1; // a thread is waiting for this to finish + unsigned a_synch : 1; // run completion synchronously + nni_task a_task; + + // Read/write operations. + nni_iov *a_iov; + int a_niov; + nni_iov a_iovinl[4]; // inline IOVs - when the IOV list is short + nni_iov *a_iovalloc; // dynamically allocated IOVs + int a_niovalloc; // number of allocated IOVs + + // Message operations. + nni_msg *a_msg; + + // Connect/accept operations. + void *a_pipe; // opaque pipe handle + + // User scratch data. Consumers may store values here, which + // must be preserved by providers and the framework. + void *a_user_data[4]; + + // Operation inputs & outputs. Up to 4 inputs and 4 outputs may be + // specified. The semantics of these will vary, and depend on the + // specific operation. + void *a_inputs[4]; + void *a_outputs[4]; + + // Provider-use fields. + nni_aio_cancelfn a_prov_cancel; + void * a_prov_data; + nni_list_node a_prov_node; + void * a_prov_extra[4]; // Extra data used by provider + + // Expire node. + nni_list_node a_expire_node; +}; + static void nni_aio_expire_add(nni_aio *); int @@ -88,7 +139,7 @@ nni_aio_fini(nni_aio *aio) nni_cv_fini(&aio->a_cv); if (aio->a_niovalloc > 0) { - NNI_FREE_STRUCTS(aio->a_iov, aio->a_niovalloc); + NNI_FREE_STRUCTS(aio->a_iovalloc, aio->a_niovalloc); } NNI_FREE_STRUCT(aio); @@ -96,21 +147,27 @@ nni_aio_fini(nni_aio *aio) } int -nni_aio_set_iov(nni_aio *aio, int niov, nng_iov *iov) +nni_aio_set_iov(nni_aio *aio, int niov, const nni_iov *iov) { - if ((niov > 4) && (niov > aio->a_niovalloc)) { + if ((niov > NNI_NUM_ELEMENTS(aio->a_iovinl)) && + (niov > aio->a_niovalloc)) { nni_iov *newiov = NNI_ALLOC_STRUCTS(newiov, niov); if (newiov == NULL) { return (NNG_ENOMEM); } if (aio->a_niovalloc > 0) { - NNI_FREE_STRUCTS(aio->a_iov, aio->a_niovalloc); + NNI_FREE_STRUCTS(aio->a_iovalloc, aio->a_niovalloc); } aio->a_iov = newiov; + aio->a_iovalloc = newiov; aio->a_niovalloc = niov; } - - memcpy(aio->a_iov, iov, niov * sizeof(nng_iov)); + if (niov <= NNI_NUM_ELEMENTS(aio->a_iovinl)) { + aio->a_iov = aio->a_iovinl; + } else { + aio->a_iov = aio->a_iovalloc; + } + memcpy(aio->a_iov, iov, niov * sizeof(nni_iov)); aio->a_niov = niov; return (0); } @@ -136,7 +193,7 @@ nni_aio_stop(nni_aio *aio) aio->a_fini = 1; nni_mtx_unlock(&nni_aio_lk); - nni_aio_cancel(aio, NNG_ECANCELED); + nni_aio_abort(aio, NNG_ECANCELED); nni_aio_wait(aio); } @@ -293,10 +350,10 @@ nni_aio_start(nni_aio *aio, nni_aio_cancelfn cancelfn, void *data) return (0); } -// nni_aio_cancel is called by a consumer which guarantees that the aio +// nni_aio_abort is called by a consumer which guarantees that the aio // is still valid. void -nni_aio_cancel(nni_aio *aio, int rv) +nni_aio_abort(nni_aio *aio, int rv) { nni_aio_cancelfn cancelfn; @@ -502,6 +559,81 @@ nni_aio_expire_loop(void *arg) } } +void * +nni_aio_get_prov_data(nni_aio *aio) +{ + return (aio->a_prov_data); +} + +void +nni_aio_set_prov_data(nni_aio *aio, void *data) +{ + aio->a_prov_data = data; +} + +void * +nni_aio_get_prov_extra(nni_aio *aio, unsigned index) +{ + return (aio->a_prov_extra[index]); +} + +void +nni_aio_set_prov_extra(nni_aio *aio, unsigned index, void *data) +{ + aio->a_prov_extra[index] = data; +} + +void +nni_aio_get_iov(nni_aio *aio, int *niovp, nni_iov **iovp) +{ + *niovp = aio->a_niov; + *iovp = aio->a_iov; +} + +void +nni_aio_normalize_timeout(nni_aio *aio, nng_duration dur) +{ + if (aio->a_timeout == NNG_DURATION_DEFAULT) { + aio->a_timeout = dur; + } +} + +void +nni_aio_bump_count(nni_aio *aio, size_t n) +{ + aio->a_count += n; +} + +size_t +nni_aio_iov_count(nni_aio *aio) +{ + size_t resid = 0; + + for (int i = 0; i < aio->a_niov; i++) { + resid += aio->a_iov[i].iov_len; + } + return (resid); +} + +size_t +nni_aio_iov_advance(nni_aio *aio, size_t n) +{ + size_t resid = n; + while (n) { + NNI_ASSERT(aio->a_niov != 0); + if (aio->a_iov[0].iov_len > n) { + aio->a_iov[0].iov_len -= n; + NNI_INCPTR(aio->a_iov[0].iov_buf, n); + return (0); // we used all of "n" + } + resid -= aio->a_iov[0].iov_len; + n -= aio->a_iov[0].iov_len; + aio->a_iov = &aio->a_iov[1]; + aio->a_niov--; + } + return (resid); // we might not have used all of n for this iov +} + void nni_aio_sys_fini(void) { diff --git a/src/core/aio.h b/src/core/aio.h index 33fe07cb..34f4a56b 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -20,59 +20,6 @@ typedef struct nni_aio_ops nni_aio_ops; typedef void (*nni_aio_cancelfn)(nni_aio *, int); -// An nni_aio is an async I/O handle. -struct nni_aio { - int a_result; // Result code (nng_errno) - size_t a_count; // Bytes transferred (I/O only) - nni_time a_expire; // Absolute timeout - nni_duration a_timeout; // Relative timeout - - // These fields are private to the aio framework. - nni_cv a_cv; - unsigned a_fini : 1; // shutting down (no new operations) - unsigned a_done : 1; // operation has completed - unsigned a_pend : 1; // completion routine pending - unsigned a_active : 1; // aio was started - unsigned a_expiring : 1; // expiration callback in progress - unsigned a_waiting : 1; // a thread is waiting for this to finish - unsigned a_synch : 1; // run completion synchronously - nni_task a_task; - - // Read/write operations. - nni_iov *a_iov; - int a_niov; - nni_iov a_iovinl[4]; // inline IOVs - when the IOV list is short - int a_niovalloc; // number of allocated IOVs - - // Message operations. - nni_msg *a_msg; - - // Connect/accept operations. - void *a_pipe; // opaque pipe handle - - // Resolver operations. - nni_sockaddr *a_addr; - - // User scratch data. Consumers may store values here, which - // must be preserved by providers and the framework. - void *a_user_data[4]; - - // Operation inputs & outputs. Up to 4 inputs and 4 outputs may be - // specified. The semantics of these will vary, and depend on the - // specific operation. - void *a_inputs[4]; - void *a_outputs[4]; - - // Provider-use fields. - nni_aio_cancelfn a_prov_cancel; - void * a_prov_data; - nni_list_node a_prov_node; - void * a_prov_extra[4]; // Extra data used by provider - - // Expire node. - nni_list_node a_expire_node; -}; - // nni_aio_init initializes an aio object. The callback is called with // the supplied argument when the operation is complete. If NULL is // supplied for the callback, then nni_aio_wake is used in its place, @@ -128,11 +75,6 @@ extern void nni_aio_set_output(nni_aio *, int, void *); // nni_get_output returns an output previously stored on the AIO. extern void *nni_aio_get_output(nni_aio *, int); -// nni_aio_set_iov sets an IOV (scatter/gather vector) on the AIO. -// Up to 4 may be set without any possibility of failure, more than that -// may require an allocation and hence fail due to NNG_ENOMEM. -extern int nni_aio_set_iov(nni_aio *, int, nng_iov *); - // XXX: These should be refactored in terms of generic inputs and outputs. extern void nni_aio_set_msg(nni_aio *, nni_msg *); extern nni_msg *nni_aio_get_msg(nni_aio *); @@ -152,11 +94,6 @@ extern void * nni_aio_get_pipe(nni_aio *); // completion callback. void nni_aio_set_synch(nni_aio *); -// nni_aio_set_timeout sets the timeout (relative) when the AIO will -// be canceled. The cancelation does not happen until after nni_aio_start -// is called. -extern void nni_aio_set_timeout(nni_aio *, nni_duration); - // nni_aio_result returns the result code (0 on success, or an NNG errno) // for the operation. It is only valid to call this when the operation is // complete (such as when the callback is executed or after nni_aio_wait @@ -192,19 +129,30 @@ extern void nni_aio_finish_error(nni_aio *, int); extern void nni_aio_finish_pipe(nni_aio *, void *); extern void nni_aio_finish_msg(nni_aio *, nni_msg *); -// nni_aio_cancel is used to cancel an operation. Any pending I/O or +// nni_aio_abort is used to abort an operation. Any pending I/O or // timeouts are canceled if possible, and the callback will be returned // with the indicated result (NNG_ECLOSED or NNG_ECANCELED is recommended.) -extern void nni_aio_cancel(nni_aio *, int rv); - -extern int nni_aio_start(nni_aio *, nni_aio_cancelfn, void *); - -// nni_aio_stop is used to abort all further operations on the AIO. -// When this is executed, no further operations or callbacks will be -// executed, and if callbacks or I/O is in progress this will block -// until they are either canceled or aborted. (Question: why not just -// nni_fini?) -// extern void nni_aio_stop(nni_aio *); +extern void nni_aio_abort(nni_aio *, int rv); + +extern int nni_aio_start(nni_aio *, nni_aio_cancelfn, void *); +extern void *nni_aio_get_prov_data(nni_aio *); +extern void nni_aio_set_prov_data(nni_aio *, void *); +extern void *nni_aio_get_prov_extra(nni_aio *, unsigned); +extern void nni_aio_set_prov_extra(nni_aio *, unsigned, void *); +// nni_aio_advance_iov moves up the iov, reflecting that some I/O as +// been performed. It returns the amount of data remaining in the argument; +// i.e. if the count refers to more data than the iov can support, then +// the result will be left over count. +extern size_t nni_aio_iov_advance(nni_aio *, size_t); +// nni_aio_iov_count returns the number of bytes referenced by the aio's iov. +extern size_t nni_aio_iov_count(nni_aio *); + +extern int nni_aio_set_iov(nni_aio *, int, const nni_iov *); + +extern void nni_aio_set_timeout(nni_aio *, nng_duration); +extern void nni_aio_get_iov(nni_aio *, int *, nni_iov **); +extern void nni_aio_normalize_timeout(nni_aio *, nng_duration); +extern void nni_aio_bump_count(nni_aio *, size_t); extern int nni_aio_sys_init(void); extern void nni_aio_sys_fini(void); diff --git a/src/core/defs.h b/src/core/defs.h index fbf074b4..dbbccf58 100644 --- a/src/core/defs.h +++ b/src/core/defs.h @@ -30,12 +30,14 @@ #define NNI_NUM_ELEMENTS(x) (sizeof(x) / sizeof((x)[0])) // These types are common but have names shared with user space. +// Internal code should use these names when possible. typedef struct nng_msg nni_msg; typedef struct nng_sockaddr nni_sockaddr; typedef struct nng_event nni_event; typedef struct nng_notify nni_notify; typedef struct nng_url nni_url; typedef struct nng_iov nni_iov; +typedef struct nng_aio nni_aio; // These are our own names. typedef struct nni_socket nni_sock; @@ -62,8 +64,6 @@ typedef int nni_signal; // Wakeup channel. typedef uint64_t nni_time; // Abs. time (ms). typedef int32_t nni_duration; // Rel. time (ms). -typedef struct nni_aio nni_aio; - typedef void (*nni_cb)(void *); // Notify descriptor. diff --git a/src/core/device.c b/src/core/device.c index e6b75897..0eaec30e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.com> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -38,7 +38,7 @@ typedef struct nni_device_pair nni_device_pair; static void nni_device_cancel(nni_aio *aio, int rv) { - nni_device_data *dd = aio->a_prov_data; + nni_device_data *dd = nni_aio_get_prov_data(aio); // cancellation is the only path to shutting it down. nni_mtx_lock(&dd->mtx); @@ -63,7 +63,7 @@ nni_device_cb(void *arg) if ((rv = nni_aio_result(aio)) != 0) { p->state = NNI_DEVICE_STATE_FINI; - nni_aio_cancel(p->user, rv); + nni_aio_abort(p->user, rv); return; } diff --git a/src/core/endpt.c b/src/core/endpt.c index cfabcc87..4a2c3097 100644 --- a/src/core/endpt.c +++ b/src/core/endpt.c @@ -249,10 +249,10 @@ nni_ep_shutdown(nni_ep *ep) nni_mtx_unlock(&ep->ep_mtx); // Abort any remaining in-flight operations. - nni_aio_cancel(ep->ep_acc_aio, NNG_ECLOSED); - nni_aio_cancel(ep->ep_con_aio, NNG_ECLOSED); - nni_aio_cancel(ep->ep_con_syn, NNG_ECLOSED); - nni_aio_cancel(ep->ep_tmo_aio, NNG_ECLOSED); + nni_aio_abort(ep->ep_acc_aio, NNG_ECLOSED); + nni_aio_abort(ep->ep_con_aio, NNG_ECLOSED); + nni_aio_abort(ep->ep_con_syn, NNG_ECLOSED); + nni_aio_abort(ep->ep_tmo_aio, NNG_ECLOSED); // Stop the underlying transport. ep->ep_ops.ep_close(ep->ep_data); @@ -296,7 +296,7 @@ nni_ep_close(nni_ep *ep) static void nni_ep_tmo_cancel(nni_aio *aio, int rv) { - nni_ep *ep = aio->a_prov_data; + nni_ep *ep = nni_aio_get_prov_data(aio); // The only way this ever gets "finished", is via cancellation. if (ep != NULL) { nni_mtx_lock(&ep->ep_mtx); diff --git a/src/core/msgqueue.c b/src/core/msgqueue.c index 10bffaa4..de4708fe 100644 --- a/src/core/msgqueue.c +++ b/src/core/msgqueue.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -338,7 +338,7 @@ nni_msgq_set_cb(nni_msgq *mq, nni_msgq_cb fn, void *arg) static void nni_msgq_cancel(nni_aio *aio, int rv) { - nni_msgq *mq = aio->a_prov_data; + nni_msgq *mq = nni_aio_get_prov_data(aio); nni_mtx_lock(&mq->mq_lock); if (nni_aio_list_active(aio)) { diff --git a/src/core/msgqueue.h b/src/core/msgqueue.h index ececf372..9cc650e0 100644 --- a/src/core/msgqueue.h +++ b/src/core/msgqueue.h @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/core/pipe.c b/src/core/pipe.c index 66e7ae87..daee3834 100644 --- a/src/core/pipe.c +++ b/src/core/pipe.c @@ -201,7 +201,7 @@ nni_pipe_close(nni_pipe *p) nni_mtx_unlock(&p->p_mtx); // abort any pending negotiation/start process. - nni_aio_cancel(p->p_start_aio, NNG_ECLOSED); + nni_aio_abort(p->p_start_aio, NNG_ECLOSED); } void @@ -274,11 +274,11 @@ nni_pipe_create(nni_ep *ep, void *tdata) nni_mtx_init(&p->p_mtx); nni_cv_init(&p->p_cv, &nni_pipe_lk); - nni_aio_init(&p->p_start_aio, nni_pipe_start_cb, p); - - nni_mtx_lock(&nni_pipe_lk); - rv = nni_idhash_alloc(nni_pipes, &p->p_id, p); - nni_mtx_unlock(&nni_pipe_lk); + if ((rv = nni_aio_init(&p->p_start_aio, nni_pipe_start_cb, p)) == 0) { + nni_mtx_lock(&nni_pipe_lk); + rv = nni_idhash_alloc(nni_pipes, &p->p_id, p); + nni_mtx_unlock(&nni_pipe_lk); + } if ((rv != 0) || ((rv = nni_ep_pipe_add(ep, p)) != 0) || ((rv = nni_sock_pipe_add(sock, p)) != 0)) { diff --git a/src/core/pipe.h b/src/core/pipe.h index 54629810..32871335 100644 --- a/src/core/pipe.h +++ b/src/core/pipe.h @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/core/protocol.h b/src/core/protocol.h index 39bde059..47ddfd3f 100644 --- a/src/core/protocol.h +++ b/src/core/protocol.h @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/core/socket.c b/src/core/socket.c index 409e4f66..bf97ef8d 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -126,7 +126,8 @@ nni_sock_getopt_fd(nni_sock *s, int flag, void *val, size_t *szp) cb = nni_sock_can_recv_cb; break; default: - nni_panic("default case!"); + // This should never occur. + return (NNG_EINVAL); } // If we already inited this, just give back the same file descriptor. @@ -772,25 +773,17 @@ nni_sock_closeall(void) } } -static void -nni_sock_normalize_expiration(nni_aio *aio, nni_duration def) -{ - if (aio->a_timeout == (nni_duration) -2) { - aio->a_timeout = def; - } -} - void nni_sock_send(nni_sock *sock, nni_aio *aio) { - nni_sock_normalize_expiration(aio, sock->s_sndtimeo); + nni_aio_normalize_timeout(aio, sock->s_sndtimeo); sock->s_sock_ops.sock_send(sock->s_data, aio); } void nni_sock_recv(nni_sock *sock, nni_aio *aio) { - nni_sock_normalize_expiration(aio, sock->s_rcvtimeo); + nni_aio_normalize_timeout(aio, sock->s_rcvtimeo); sock->s_sock_ops.sock_recv(sock->s_data, aio); } @@ -872,7 +865,6 @@ nni_sock_setopt(nni_sock *s, const char *name, const void *val, size_t size) { int rv = NNG_ENOTSUP; nni_ep * ep; - int commits = 0; nni_sockopt * optv; nni_sockopt * oldv = NULL; const nni_socket_option * sso; diff --git a/src/core/socket.h b/src/core/socket.h index 37c67436..30561d49 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -39,7 +39,7 @@ extern uint32_t nni_sock_id(nni_sock *); // a pipe could wind up orphaned. extern int nni_sock_pipe_add(nni_sock *, nni_pipe *); extern void nni_sock_pipe_remove(nni_sock *, nni_pipe *); -extern int nni_sock_pipe_start(nni_sock *, nni_pipe *p); +extern int nni_sock_pipe_start(nni_sock *, nni_pipe *p); extern int nni_sock_ep_add(nni_sock *, nni_ep *); extern void nni_sock_ep_remove(nni_sock *, nni_ep *); diff --git a/src/core/transport.c b/src/core/transport.c index 38f88c4d..b48c7da6 100644 --- a/src/core/transport.c +++ b/src/core/transport.c @@ -38,7 +38,6 @@ nni_tran_register(const nni_tran *tran) { nni_transport *t; int rv; - size_t sz; // Its entirely possible that we are called before any sockets // are opened. Make sure we are initialized. This has to be diff --git a/src/core/url.c b/src/core/url.c index 3d8898bd..88a0cf0a 100644 --- a/src/core/url.c +++ b/src/core/url.c @@ -225,7 +225,7 @@ static struct { // clang-format on }; -static const char * +const char * nni_url_default_port(const char *scheme) { const char *s; @@ -255,7 +255,6 @@ nni_url_parse(nni_url **urlp, const char *raw) { nni_url * url; size_t len; - int outlen; const char *s; char c; int rv; @@ -480,4 +479,4 @@ nni_url_clone(nni_url **dstp, const nni_url *src) #undef URL_COPYSTR *dstp = dst; return (0); -}
\ No newline at end of file +} diff --git a/src/core/url.h b/src/core/url.h index 27aec445..b3407277 100644 --- a/src/core/url.h +++ b/src/core/url.h @@ -27,5 +27,6 @@ struct nni_url { extern int nni_url_parse(nni_url **, const char *path); extern void nni_url_free(nni_url *); extern int nni_url_clone(nni_url **, const nni_url *); +extern const char *nni_url_default_port(const char *); #endif // CORE_URL_H @@ -9,6 +9,7 @@ // #include "core/nng_impl.h" +#include "supplemental/http/http.h" // This file provides the "public" API. This is a thin wrapper around // internal API functions. We use the public prefix instead of internal, @@ -179,9 +180,8 @@ nng_sendmsg(nng_socket sid, nng_msg *msg, int flags) } void -nng_recv_aio(nng_socket sid, nng_aio *ap) +nng_recv_aio(nng_socket sid, nng_aio *aio) { - nni_aio * aio = (nni_aio *) ap; nni_sock *sock; int rv; @@ -194,9 +194,8 @@ nng_recv_aio(nng_socket sid, nng_aio *ap) } void -nng_send_aio(nng_socket sid, nng_aio *ap) +nng_send_aio(nng_socket sid, nng_aio *aio) { - nni_aio * aio = (nni_aio *) ap; nni_sock *sock; int rv; @@ -1019,73 +1018,87 @@ nng_msg_getopt(nng_msg *msg, int opt, void *ptr, size_t *szp) int nng_aio_alloc(nng_aio **app, void (*cb)(void *), void *arg) { - nni_aio *aio; + nng_aio *aio; int rv; if ((rv = nni_init()) != 0) { return (rv); } if ((rv = nni_aio_init(&aio, (nni_cb) cb, arg)) == 0) { - *app = (nng_aio *) aio; + nng_aio_set_timeout(aio, NNG_DURATION_DEFAULT); + *app = aio; } - aio->a_timeout = NNG_DURATION_DEFAULT; return (rv); } void -nng_aio_free(nng_aio *ap) +nng_aio_free(nng_aio *aio) { - nni_aio_fini((nni_aio *) ap); + nni_aio_fini(aio); } int -nng_aio_result(nng_aio *ap) +nng_aio_result(nng_aio *aio) { - return (nni_aio_result((nni_aio *) ap)); + return (nni_aio_result(aio)); +} + +size_t +nng_aio_count(nng_aio *aio) +{ + return (nni_aio_count(aio)); } void -nng_aio_stop(nng_aio *ap) +nng_aio_stop(nng_aio *aio) { - nni_aio_stop((nni_aio *) ap); + nni_aio_stop(aio); } void -nng_aio_wait(nng_aio *ap) +nng_aio_wait(nng_aio *aio) { - nni_aio_wait((nni_aio *) ap); + nni_aio_wait(aio); } void -nng_aio_cancel(nng_aio *ap) +nng_aio_cancel(nng_aio *aio) { - nni_aio_cancel((nni_aio *) ap, NNG_ECANCELED); + nni_aio_abort(aio, NNG_ECANCELED); } void -nng_aio_set_msg(nng_aio *ap, nng_msg *msg) +nng_aio_set_msg(nng_aio *aio, nng_msg *msg) { - nni_aio_set_msg((nni_aio *) ap, msg); + nni_aio_set_msg(aio, msg); } nng_msg * -nng_aio_get_msg(nng_aio *ap) +nng_aio_get_msg(nng_aio *aio) { - return ((nng_msg *) (nni_aio_get_msg((nni_aio *) ap))); + return (nni_aio_get_msg(aio)); } void -nng_aio_set_timeout(nng_aio *ap, nng_duration dur) +nng_aio_set_timeout(nng_aio *aio, nni_duration when) +{ + nni_aio_set_timeout(aio, when); +} + +int +nng_aio_set_iov(nng_aio *aio, int niov, nng_iov *iov) { - // Durations here are relative, since we have no notion of a - // common clock.. - nni_aio_set_timeout((nni_aio *) ap, dur); + return (nni_aio_set_iov(aio, niov, iov)); } int -nng_aio_set_iov(nng_aio *ap, int niov, nng_iov *iov) +nng_aio_set_input(nng_aio *aio, unsigned index, void *arg) { - return (nni_aio_set_iov((nni_aio *) ap, niov, iov)); + if (index > 3) { + return (NNG_EINVAL); + } + nni_aio_set_input(aio, index, arg); + return (0); } #if 0 @@ -1199,4 +1212,4 @@ int nng_url_clone(nng_url **dstp, const nng_url *src) { return (nni_url_clone(dstp, src)); -}
\ No newline at end of file +} @@ -252,6 +252,11 @@ NNG_DECL void nng_free(void *, size_t); // support asynchronous operations. They contain the completion callback, and // a pointer to consumer data. This is similar to how overlapped I/O // works in Windows, when used with a completion callback. +// +// AIO structures can carry up to 4 distinct input values, and up to +// 4 distinct output values, and up to 4 distinct "private state" values. +// The meaning of the inputs and the outputs are determined by the +// I/O functions being called. // nng_aio_alloc allocates a new AIO, and associated the completion // callback and its opaque argument. If NULL is supplied for the @@ -277,11 +282,20 @@ NNG_DECL void nng_aio_stop(nng_aio *); // failure. NNG_DECL int nng_aio_result(nng_aio *); +// nng_aio_count returns the number of bytes transferred for certain +// I/O operations. This is meaningless for other operations (e.g. +// DNS lookups or TCP connection setup). +NNG_DECL size_t nng_aio_count(nng_aio *); + // nng_aio_cancel attempts to cancel any in-progress I/O operation. // The AIO callback will still be executed, but if the cancellation is // successful then the status will be NNG_ECANCELED. NNG_DECL void nng_aio_cancel(nng_aio *); +// nng_aio_abort is like nng_aio_cancel, but allows for a different +// error result to be returned. +NNG_DECL void nng_aio_abort(nng_aio *, int); + // nng_aio_wait waits synchronously for any pending operation to complete. // It also waits for the callback to have completed execution. Therefore, // the caller of this function must not hold any locks acquired by the @@ -296,6 +310,26 @@ NNG_DECL void nng_aio_set_msg(nng_aio *, nng_msg *); // receive operation. NNG_DECL nng_msg *nng_aio_get_msg(nng_aio *); +// nng_aio_set_input sets an input parameter at the given index. +NNG_DECL int nng_aio_set_input(nng_aio *, unsigned, void *); + +// nng_aio_get_input retrieves the input parameter at the given index. +NNG_DECL void *nng_aio_get_input(nng_aio *, unsigned); + +// nng_aio_set_output sets an output result at the given index. +NNG_DECL int nng_aio_set_output(nng_aio *, unsigned, void *); + +// nng_aio_get_output retrieves the output result at the given index. +NNG_DECL void *nng_aio_get_output(nng_aio *, unsigned); + +// nng_aio_set_data sets an opaque data at the given index. The intention +// is to allow consumers to pass additional state for use in callback +// functions. +NNG_DECL int nng_aio_set_data(nng_aio *, unsigned, void *); + +// nng_aio_get_data retrieves the data that was previously stored. +NNG_DECL void *nng_aio_get_output(nng_aio *, unsigned); + // nng_aio_set_timeout sets a timeout on the AIO. This should be called for // operations that should time out after a period. The timeout should be // either a positive number of milliseconds, or NNG_DURATION_INFINITE to @@ -751,6 +785,405 @@ NNG_DECL void nng_url_free(nng_url *); // nng_url_clone clones a URL structure. NNG_DECL int nng_url_clone(nng_url **, const nng_url *); +// HTTP API. Only present if HTTP support compiled into the library. +// Functions will return NNG_ENOTSUP (or NULL or 0 as appropriate) +// if the library lacks support for HTTP. + +// HTTP status codes. This list is not exhaustive. +enum nng_http_status { + NNG_HTTP_STATUS_CONTINUE = 100, + NNG_HTTP_STATUS_SWITCHING = 101, + NNG_HTTP_STATUS_PROCESSING = 102, + NNG_HTTP_STATUS_OK = 200, + NNG_HTTP_STATUS_CREATED = 201, + NNG_HTTP_STATUS_ACCEPTED = 202, + NNG_HTTP_STATUS_NOT_AUTHORITATIVE = 203, + NNG_HTTP_STATUS_NO_CONTENT = 204, + NNG_HTTP_STATUS_RESET_CONTENT = 205, + NNG_HTTP_STATUS_PARTIAL_CONTENT = 206, + NNG_HTTP_STATUS_MULTI_STATUS = 207, + NNG_HTTP_STATUS_ALREADY_REPORTED = 208, + NNG_HTTP_STATUS_IM_USED = 226, + NNG_HTTP_STATUS_MULTIPLE_CHOICES = 300, + NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY = 301, + NNG_HTTP_STATUS_FOUND = 302, + NNG_HTTP_STATUS_SEE_OTHER = 303, + NNG_HTTP_STATUS_NOT_MODIFIED = 304, + NNG_HTTP_STATUS_USE_PROXY = 305, + NNG_HTTP_STATUS_TEMPORARY_REDIRECT = 307, + NNG_HTTP_STATUS_PERMANENT_REDIRECT = 308, + NNG_HTTP_STATUS_BAD_REQUEST = 400, + NNG_HTTP_STATUS_UNAUTHORIZED = 401, + NNG_HTTP_STATUS_PAYMENT_REQUIRED = 402, + NNG_HTTP_STATUS_FORBIDDEN = 403, + NNG_HTTP_STATUS_NOT_FOUND = 404, + NNG_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, + NNG_HTTP_STATUS_NOT_ACCEPTABLE = 406, + NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED = 407, + NNG_HTTP_STATUS_REQUEST_TIMEOUT = 408, + NNG_HTTP_STATUS_CONFLICT = 409, + NNG_HTTP_STATUS_GONE = 410, + NNG_HTTP_STATUS_LENGTH_REQUIRED = 411, + NNG_HTTP_STATUS_PRECONDITION_FAILED = 412, + NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, + NNG_HTTP_STATUS_ENTITY_TOO_LONG = 414, + NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, + NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, + NNG_HTTP_STATUS_EXPECTATION_FAILED = 417, + NNG_HTTP_STATUS_TEAPOT = 418, + NNG_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, + NNG_HTTP_STATUS_LOCKED = 423, + NNG_HTTP_STATUS_FAILED_DEPENDENCY = 424, + NNG_HTTP_STATUS_UPGRADE_REQUIRED = 426, + NNG_HTTP_STATUS_PRECONDITION_REQUIRED = 428, + NNG_HTTP_STATUS_TOO_MANY_REQUESTS = 429, + NNG_HTTP_STATUS_HEADERS_TOO_LARGE = 431, + NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS = 451, + NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, + NNG_HTTP_STATUS_NOT_IMPLEMENTED = 501, + NNG_HTTP_STATUS_BAD_GATEWAY = 502, + NNG_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, + NNG_HTTP_STATUS_GATEWAY_TIMEOUT = 504, + NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP = 505, + NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, + NNG_HTTP_STATUS_INSUFFICIENT_STORAGE = 507, + NNG_HTTP_STATUS_LOOP_DETECTED = 508, + NNG_HTTP_STATUS_NOT_EXTENDED = 510, + NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED = 511, +}; + +// nng_http_req represents an HTTP request. +typedef struct nng_http_req nng_http_req; + +// nng_http_req_alloc creates a vanilla HTTP request object. The object is +// initialized with the given URL object for an HTTP/1.1 GET request by +// default. It also adds the Host: header required for HTTP/1.1. If the +// url is NULL, then the uri and Host: header are uninitialized, and will +// need to be set explicitly. +NNG_DECL int nng_http_req_alloc(nng_http_req **, const nng_url *); + +// nng_http_req_free frees an HTTP request object. +NNG_DECL void nng_http_req_free(nng_http_req *); + +// nng_http_req_get_method returns the method. +NNG_DECL const char *nng_http_req_get_method(nng_http_req *); + +// nng_http_req_get_version returns the version, usually HTTP/1.1. +NNG_DECL const char *nng_http_req_get_version(nng_http_req *); + +// nng_http_req_get_uri returns the "abs-uri", which is URL without +// the scheme, host, or port. +NNG_DECL const char *nng_http_req_get_uri(nng_http_req *); + +// nng_http_req_set_header sets an HTTP header, replacing any previous value +// that might have been present. +NNG_DECL int nng_http_req_set_header( + nng_http_req *, const char *, const char *); + +// nng_http_req_add_header adds an HTTP header, without disrupting any other +// with the same name that might have been present. +NNG_DECL int nng_http_req_add_header( + nng_http_req *, const char *, const char *); + +// nng_http_req_del_header deletes all occurrences of a named header. +NNG_DECL int nng_http_req_del_header(nng_http_req *, const char *); + +// nng_http_req_get_header looks up a header with the named, returns NULL +// if not found. +NNG_DECL const char *nng_http_req_get_header(nng_http_req *, const char *); + +// nng_http_req_set_method is used to change the method of a request. +// The method should be an upper case HTTP method, like POST, or DELETE. +// Null sets the default ("GET"). +NNG_DECL int nng_http_req_set_method(nng_http_req *, const char *); + +// nng_http_req_set_version is used to change the version of a request. +// Normally the version is "HTTP/1.1". Note that the framework does +// not support HTTP/2 at all. Null sets the default ("HTTP/1.1"). +NNG_DECL int nng_http_req_set_version(nng_http_req *, const char *); + +// nng_http_req_set_uri is used to change the URI of a request. This +// should be an "abs-uri", that is a path, plus query and fragment if +// needed. The scheme, host, and port don't belong here. The URI should +// start with a leading '/' per HTTP. +NNG_DECL int nng_http_req_set_uri(nng_http_req *, const char *); + +// nng_http_req_set_data adds entity data to the request. The +// data object must persist (so only really useful for static data). +// The content-length header is updated as well, but the caller should +// probably set the content-type header. +NNG_DECL int nng_http_req_set_data(nng_http_req *, const void *, size_t); + +// nng_http_req_copy_data adds entity data to the response. A private +// copy of the data is made (will be freed with the request). +// The content-length header is updated as well, but the caller should +// probably set the content-type header. +NNG_DECL int nng_http_req_copy_data(nng_http_req *, const void *, size_t); + +// nng_http_res represents an HTTP response. +typedef struct nng_http_res nng_http_res; + +// nng_http_res_alloc creates a vanilla HTTP response object. The object is +// initialized for an HTTP/1.1 200 OK response by default. +NNG_DECL int nng_http_res_alloc(nng_http_res **); + +// nng_http_res_alloc_error creates an error HTTP response object. The object +// is initialized for an HTTP/1.1 response, and contains an associated +// generic HTML error page. +NNG_DECL int nng_http_res_alloc_error(nng_http_res **, uint16_t); + +// nng_http_res_free frees an HTTP response object. +NNG_DECL void nng_http_res_free(nng_http_res *); + +// nng_http_res_get_status returns the HTTP status code from the server. +NNG_DECL uint16_t nng_http_res_get_status(nng_http_res *); + +// nng_http_res_set_status sets the HTTP status code. +NNG_DECL int nng_http_res_set_status(nng_http_res *, uint16_t); + +// nng_http_res_get_reason returns the human readable status message +// that the server responds (or responded) with. +NNG_DECL const char *nng_http_res_get_reason(nng_http_res *); + +// nng_http_res_set_rason sets the human readable status message. +// NULL means that a default reason is used based on the status code. +NNG_DECL int nng_http_res_set_reason(nng_http_res *, const char *); + +// nng_http_res_set_header sets an HTTP header, replacing any previous value +// that might have been present. +NNG_DECL int nng_http_res_set_header( + nng_http_res *, const char *, const char *); + +// nng_http_res_add_header adds an HTTP header, without disrupting any other +// with the same name that might have been present. +NNG_DECL int nng_http_res_add_header( + nng_http_res *, const char *, const char *); + +// nng_http_res_del_header deletes all occurrences of a named header. +NNG_DECL int nng_http_res_del_header(nng_http_res *, const char *); + +// nng_http_res_get_header looks up a header with the named, returns NULL +// if not found. +NNG_DECL const char *nng_http_res_get_header(nng_http_res *, const char *); + +// nng_http_res_set_version is used to change the version of a response. +// Normally the version is "HTTP/1.1". Note that the framework does +// not support HTTP/2 at all. NULL sets the default ("HTTP/1.1"). +NNG_DECL int nng_http_res_set_version(nng_http_res *, const char *); + +// nng_http_res_get_version returns the version, usually HTTP/1.1. +NNG_DECL const char *nng_http_res_get_version(nng_http_res *); + +// nng_http_res_set_data adds entity data to the response. The +// data object must persist (so only really useful for static data). +// The content-length header is updated as well, but the caller should +// probably set the content-type header. +NNG_DECL int nng_http_res_set_data(nng_http_res *, const void *, size_t); + +// nng_http_res_copy_data adds entity data to the response. A private +// copy of the data is made (will be freed with the request). +// The content-length header is updated as well, but the caller should +// probably set the content-type header. +NNG_DECL int nng_http_res_copy_data(nng_http_res *, const void *, size_t); + +// An nng_http_conn represents an underlyinjg "connection". It may be +// a TCP channel, or a TLS channel, but the main thing is that this is +// normally only used for exchanging HTTP requests and responses. +typedef struct nng_http_conn nng_http_conn; + +// nng_http_conn_close closes the underlying channel. Applications should +// not use this channel after this operation is performed. +NNG_DECL void nng_http_conn_close(nng_http_conn *); + +// nng_http_conn_read attempts to read data from the connection. This +// completes as soon as at least one byte is read; it does not wait +// for the entire aio to be filled. +NNG_DECL void nng_http_conn_read(nng_http_conn *, nng_aio *); + +// nng_http_conn_read_all is like nng_http_conn_read, but it does not +// finish until either all the requested data is read, or an error occurs. +NNG_DECL void nng_http_conn_read_all(nng_http_conn *, nng_aio *); + +// nng_http_conn_write attempts to write data, but it can write less +// than the amount requested. (It completes as soon as at least one +// byte is written.) +NNG_DECL void nng_http_conn_write(nng_http_conn *, nng_aio *); + +// nng_http_conn_write_all is like nng_http_conn_write, but it does not +// finish until either all the requested data is written, or an error occurs. +NNG_DECL void nng_http_conn_write_all(nng_http_conn *, nng_aio *); + +// nng_http_conn_write_req writes the entire request. It will also write any +// data that has been attached. +NNG_DECL void nng_http_conn_write_req( + nng_http_conn *, nng_http_req *, nng_aio *); + +// nng_http_conn_write_res writes the entire response. It will also write any +// data that has been attached. +NNG_DECL void nng_http_conn_write_res( + nng_http_conn *, nng_http_res *, nng_aio *); + +// nng_http_conn_read_req reads an entire request, EXCEPT for any entity +// data. The caller is responsible for processing the headers in the request +// and reading any submitted entity data itself. +NNG_DECL void nng_http_conn_read_req( + nng_http_conn *, nng_http_req *, nng_aio *); + +// nng_http_conn_read_res reads an entire response, EXCEPT for any entity +// data. The caller is responsible for processing the headers in the response +// and reading any submitted entity data itself. +NNG_DECL void nng_http_conn_read_res( + nng_http_conn *, nng_http_res *, nng_aio *); + +// nng_http_handler is a handler used on the server side to handle HTTP +// requests coming into a specific URL. +typedef struct nng_http_handler nng_http_handler; + +// nng_http_handler_alloc creates a server handler object, for the supplied +// absolute URI (path only) with the callback. By default the handler +// is assumed to handle only GET requests (and implictly HEAD requests +// as well.) +// +// Note that methods which modify a handler cannot be called while the handler +// is registered with the server, and that a handler can only be registered +// once per server. +// +// The callback function will receive the following arguments (via +// nng_aio_get_input(): nng_http_request *, nng_http_handler *, and +// nng_http_conn *. The first is a request object, for convenience. +// The second is the handler, from which the callback can obtain any other +// data it has set. The final is the http connection, which can be used +// to hijack the session. +// +// Upon completion, the handler should store an nng_http_res * as the +// first output using nng_aio_set_output. If it does not do so, or supplies +// NULL, then it must send a response itself. +// +// The callback should return 0 in most circumstances; if it returns anything +// other than 0 then the connection is terminated (after possibly sending +// a 500 error response to the client.) +NNG_DECL int nng_http_handler_alloc( + nng_http_handler **, const char *, void (*)(nng_aio *)); + +// nng_http_handler_free frees the handler. This actually just drops a +// reference count on the handler, as it may be in use by an existing +// server. The server will also call this when it is destroyed. +NNG_DECL void nng_http_handler_free(nng_http_handler *); + +// nng_http_handler_alloc_file creates a "file" based handler, that +// serves up static content from the given file path. The content-type +// supplied is determined from the file name using a simple built-in map. +NNG_DECL int nng_http_handler_alloc_file( + nng_http_handler **, const char *, const char *); + +// nng_http_handler_alloc_static creates a static-content handler. +// The last argument is the content-type, which may be NULL (in which case +// "application/octet-stream" is assumed.) +NNG_DECL int nng_http_handler_alloc_static( + nng_http_handler **, const char *, const void *, size_t, const char *); + +// nng_http_handler_alloc_file creates a "directory" based handler, that +// serves up static content from the given directory tree. Directories +// that contain an index.html or index.htm file use that file for the +// directory content, otherwise a suitable error page is returned (the server +// does not generate index pages automatically.) The content-type for +// files is determined from the file name using a simple built-in map. +NNG_DECL int nng_http_handler_alloc_directory( + nng_http_handler **, const char *, const char *); + +// nng_http_handler_set_method sets the method that the handler will be +// called for. By default this is GET. If NULL is supplied for the +// method, then the handler is executed regardless of method, and must +// inspect the method itself. +NNG_DECL int nng_http_handler_set_method(nng_http_handler *, const char *); + +// nng_http_handler_set_host sets the Host: that the handler will be +// called for (to allow for virtual hosts). If the value is NULL (the +// default, then the Host: header is not considered when matching the +// handler.) Note that the Host: header must match *exactly* (except +// that case is not considered.) +NNG_DECL int nng_http_handler_set_host(nng_http_handler *, const char *); + +// nng_http_handler_set_tree indicates that the handler is being registered +// for a heirarchical tree, rather than just a single path, so it will be +// called for all child paths supplied. By default the handler is only +// called for an exact path match. +NNG_DECL int nng_http_handler_set_tree(nng_http_handler *); + +// nng_http_handler_set_data is used to store additional data, along with +// a possible clean up routine. (The clean up is a custom deallocator and +// will be called with the supplied data as an argument, when the handler +// is being deallocated.) +NNG_DECL int nng_http_handler_set_data( + nng_http_handler *, void *, void (*)(void *)); + +// nng_http_handler_get_data returns the data that was previously stored. +NNG_DECL void *nng_http_handler_get_data(nng_http_handler *); + +// nng_http_server is a handle to an HTTP server instance. Servers +// only serve a single port / address at this time. + +typedef struct nng_http_server nng_http_server; + +// nng_http_server_hold gets a server structure, using the address determined +// from the URL. If a server already exists, then a hold is placed on it, and +// that instance is returned. If no such server exists, then a new instance +// is created. +NNG_DECL int nng_http_server_hold(nng_http_server **, const nng_url *); + +// nng_http_server_release releases the hold on the server. If this is the +// last instance of the server, then it is shutdown and resources are freed. +NNG_DECL void nng_http_server_release(nng_http_server *); + +// nng_http_server_start starts the server handling HTTP. Once this is +// called, it will not be possible to change certain parameters (such as +// any TLS configuration). +NNG_DECL int nng_http_server_start(nng_http_server *); + +// nng_http_server_stop stops the server. No new client connections are +// accepted after this returns. +NNG_DECL void nng_http_server_stop(nng_http_server *); + +// nng_http_server_add_handler registers a handler on the server. +// This function will return NNG_EADDRINUSE if a conflicting handler +// is already registered (i.e. a handler with the same value for Host, +// Method, and URL.) +NNG_DECL int nng_http_server_add_handler( + nng_http_server *, nng_http_handler *); + +// nni_http_del_handler removes the given handler. The caller is +// responsible for finalizing it afterwards. If the handler was not found +// (not registered), NNG_ENOENT is returned. In this case it is unsafe +// to make assumptions about the validity of the handler. +NNG_DECL int nng_http_server_del_handler( + nng_http_server *, nng_http_handler *); + +// nng_http_server_set_tls adds a TLS configuration to the server, +// and enables the use of it. This returns NNG_EBUSY if the server is +// already started. This wipes out the entire TLS configuration on the +// server client, so the caller must have configured it reasonably. +// This API is not recommended unless the caller needs complete control +// over the TLS configuration. +NNG_DECL int nng_http_server_set_tls(nng_http_server *, nng_tls_config *); + +// nng_http_server_get_tls obtains the TLS configuration if one is present, +// or returns NNG_EINVAL. The TLS configuration is invalidated if the +// nng_http_server_set_tls function is called, so be careful. +NNG_DECL int nng_http_server_get_tls(nng_http_server *, nng_tls_config **); + +// nng_http_hijack is intended to be called by a handler that wishes to +// take over the processing of the HTTP session -- usually to change protocols +// (such as in the case of websocket). The caller is responsible for the +// final disposal of the associated nng_http_conn. Also, this completely +// disassociates the http session from the server, so the server may be +// stopped or destroyed without affecting the hijacked session. Note also +// that the hijacker will need to issue any HTTP reply itself. Finally, +// when a session is hijacked, the caller is also responsible for disposing +// of the request structure. (Some hijackers may keep the request for +// further processing.) + +NNG_DECL int nng_http_hijack(nng_http_conn *); + #ifdef __cplusplus } #endif diff --git a/src/platform/posix/posix_aio.h b/src/platform/posix/posix_aio.h index fe677591..ebc2eb99 100644 --- a/src/platform/posix/posix_aio.h +++ b/src/platform/posix/posix_aio.h @@ -1,5 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/platform/posix/posix_epdesc.c b/src/platform/posix/posix_epdesc.c index 7b168679..931ed052 100644 --- a/src/platform/posix/posix_epdesc.c +++ b/src/platform/posix/posix_epdesc.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -47,13 +47,12 @@ struct nni_posix_epdesc { static void nni_posix_epdesc_cancel(nni_aio *aio, int rv) { - nni_posix_epdesc *ed = aio->a_prov_data; + nni_posix_epdesc *ed = nni_aio_get_prov_data(aio); NNI_ASSERT(rv != 0); nni_mtx_lock(&ed->mtx); if (nni_aio_list_active(aio)) { nni_aio_list_remove(aio); - NNI_ASSERT(aio->a_pipe == NULL); nni_aio_finish_error(aio, rv); } nni_mtx_unlock(&ed->mtx); @@ -318,7 +317,7 @@ nni_posix_epdesc_accept(nni_posix_epdesc *ed, nni_aio *aio) // connection is ready for us. There isn't anything else for us to // do really, as that will have been done in listen. nni_mtx_lock(&ed->mtx); - aio->a_pipe = NULL; + nni_aio_set_pipe(aio, NULL); // If we can't start, it means that the AIO was stopped. if ((rv = nni_aio_start(aio, nni_posix_epdesc_cancel, ed)) != 0) { nni_mtx_unlock(&ed->mtx); @@ -344,7 +343,7 @@ nni_posix_epdesc_connect(nni_posix_epdesc *ed, nni_aio *aio) int fd; nni_mtx_lock(&ed->mtx); - aio->a_pipe = NULL; + nni_aio_set_pipe(aio, NULL); // If we can't start, it means that the AIO was stopped. if ((rv = nni_aio_start(aio, nni_posix_epdesc_cancel, ed)) != 0) { nni_mtx_unlock(&ed->mtx); diff --git a/src/platform/posix/posix_ipc.c b/src/platform/posix/posix_ipc.c index f0a9a973..fc312736 100644 --- a/src/platform/posix/posix_ipc.c +++ b/src/platform/posix/posix_ipc.c @@ -1,5 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/platform/posix/posix_pipedesc.c b/src/platform/posix/posix_pipedesc.c index 6ae0d752..23d69e51 100644 --- a/src/platform/posix/posix_pipedesc.c +++ b/src/platform/posix/posix_pipedesc.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -39,7 +39,7 @@ static void nni_posix_pipedesc_finish(nni_aio *aio, int rv) { nni_aio_list_remove(aio); - nni_aio_finish(aio, rv, aio->a_count); + nni_aio_finish(aio, rv, nni_aio_count(aio)); } static void @@ -66,21 +66,23 @@ nni_posix_pipedesc_doclose(nni_posix_pipedesc *pd) static void nni_posix_pipedesc_dowrite(nni_posix_pipedesc *pd) { - int n; - struct iovec iovec[4]; - nni_aio * aio; - int niov; + nni_aio *aio; while ((aio = nni_list_first(&pd->writeq)) != NULL) { - int i; - for (niov = 0, i = 0; i < aio->a_niov; i++) { - iovec[niov].iov_len = aio->a_iov[i].iov_len; - iovec[niov].iov_base = aio->a_iov[i].iov_buf; - niov++; - } - if (niov == 0) { - nni_posix_pipedesc_finish(aio, NNG_EINVAL); - continue; + int i; + int n; + struct iovec iovec[4]; + int niov; + int naiov; + nni_iov * aiov; + + nni_aio_get_iov(aio, &naiov, &aiov); + for (niov = 0, i = 0; i < naiov; i++) { + if (aiov[i].iov_len > 0) { + iovec[niov].iov_len = aiov[i].iov_len; + iovec[niov].iov_base = aiov[i].iov_buf; + niov++; + } } n = writev(pd->node.fd, iovec, niov); @@ -95,8 +97,7 @@ nni_posix_pipedesc_dowrite(nni_posix_pipedesc *pd) return; } - aio->a_count += n; - + nni_aio_bump_count(aio, n); // We completed the entire operation on this aioq. nni_posix_pipedesc_finish(aio, 0); @@ -108,24 +109,24 @@ nni_posix_pipedesc_dowrite(nni_posix_pipedesc *pd) static void nni_posix_pipedesc_doread(nni_posix_pipedesc *pd) { - int n; - struct iovec iovec[4]; - nni_aio * aio; - int niov; + nni_aio *aio; while ((aio = nni_list_first(&pd->readq)) != NULL) { - int i; - for (i = 0, niov = 0; i < aio->a_niov; i++) { - if (aio->a_iov[i].iov_len != 0) { - iovec[niov].iov_len = aio->a_iov[i].iov_len; - iovec[niov].iov_base = aio->a_iov[i].iov_buf; + int i; + int n; + struct iovec iovec[4]; + int niov; + int naiov; + nni_iov * aiov; + + nni_aio_get_iov(aio, &naiov, &aiov); + for (niov = 0, i = 0; i < naiov; i++) { + if (aiov[i].iov_len != 0) { + iovec[niov].iov_len = aiov[i].iov_len; + iovec[niov].iov_base = aiov[i].iov_buf; niov++; } } - if (niov == 0) { - nni_posix_pipedesc_finish(aio, NNG_EINVAL); - continue; - } n = readv(pd->node.fd, iovec, niov); if (n < 0) { @@ -146,7 +147,7 @@ nni_posix_pipedesc_doread(nni_posix_pipedesc *pd) return; } - aio->a_count += n; + nni_aio_bump_count(aio, n); // We completed the entire operation on this aioq. nni_posix_pipedesc_finish(aio, 0); @@ -198,7 +199,7 @@ nni_posix_pipedesc_close(nni_posix_pipedesc *pd) static void nni_posix_pipedesc_cancel(nni_aio *aio, int rv) { - nni_posix_pipedesc *pd = aio->a_prov_data; + nni_posix_pipedesc *pd = nni_aio_get_prov_data(aio); nni_mtx_lock(&pd->mtx); if (nni_aio_list_active(aio)) { diff --git a/src/platform/posix/posix_resolv_gai.c b/src/platform/posix/posix_resolv_gai.c index be1d2c6b..f2f8a9fc 100644 --- a/src/platform/posix/posix_resolv_gai.c +++ b/src/platform/posix/posix_resolv_gai.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -54,11 +54,16 @@ struct nni_posix_resolv_item { static void nni_posix_resolv_finish(nni_posix_resolv_item *item, int rv) { - nni_aio *aio = item->aio; - - aio->a_prov_data = NULL; - nni_aio_finish(aio, rv, 0); - NNI_FREE_STRUCT(item); + nni_aio *aio; + + if ((aio = item->aio) != NULL) { + if (nni_aio_get_prov_data(aio) == item) { + nni_aio_set_prov_data(aio, NULL); + item->aio = NULL; + nni_aio_finish(aio, rv, 0); + NNI_FREE_STRUCT(item); + } + } } static void @@ -67,11 +72,12 @@ nni_posix_resolv_cancel(nni_aio *aio, int rv) nni_posix_resolv_item *item; nni_mtx_lock(&nni_posix_resolv_mtx); - if ((item = aio->a_prov_data) == NULL) { + if ((item = nni_aio_get_prov_data(aio)) == NULL) { nni_mtx_unlock(&nni_posix_resolv_mtx); return; } - aio->a_prov_data = NULL; + nni_aio_set_prov_data(aio, NULL); + item->aio = NULL; nni_mtx_unlock(&nni_posix_resolv_mtx); nni_task_cancel(&item->task); NNI_FREE_STRUCT(item); @@ -161,7 +167,7 @@ nni_posix_resolv_task(void *arg) if (probe != NULL) { struct sockaddr_in * sin; struct sockaddr_in6 *sin6; - nng_sockaddr * sa = aio->a_addr; + nng_sockaddr * sa = nni_aio_get_input(aio, 0); switch (probe->ai_addr->sa_family) { case AF_INET: diff --git a/src/platform/posix/posix_tcp.c b/src/platform/posix/posix_tcp.c index 69d7e7ce..79e241a3 100644 --- a/src/platform/posix/posix_tcp.c +++ b/src/platform/posix/posix_tcp.c @@ -1,5 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/platform/posix/posix_udp.c b/src/platform/posix/posix_udp.c index 31ef76f6..e01f6883 100644 --- a/src/platform/posix/posix_udp.c +++ b/src/platform/posix/posix_udp.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -62,16 +62,20 @@ nni_posix_udp_dorecv(nni_plat_udp *udp) nni_list *q = &udp->udp_recvq; // While we're able to recv, do so. while ((aio = nni_list_first(q)) != NULL) { - struct iovec iov[4]; // never have more than 4 + struct iovec iov[4]; int niov; + nni_iov * aiov; struct sockaddr_storage ss; + nng_sockaddr * sa; struct msghdr hdr; int rv = 0; int cnt = 0; - for (niov = 0; niov < aio->a_niov; niov++) { - iov[niov].iov_base = aio->a_iov[niov].iov_buf; - iov[niov].iov_len = aio->a_iov[niov].iov_len; + nni_aio_get_iov(aio, &niov, &aiov); + + for (int i = 0; i < niov; i++) { + iov[i].iov_base = aiov[i].iov_buf; + iov[i].iov_len = aiov[i].iov_len; } hdr.msg_iov = iov; hdr.msg_iovlen = niov; @@ -88,11 +92,11 @@ nni_posix_udp_dorecv(nni_plat_udp *udp) return; } rv = nni_plat_errno(errno); - } else if (aio->a_addr != NULL) { + } else if ((sa = nni_aio_get_input(aio, 0)) != NULL) { // We need to store the address information. // It is incumbent on the AIO submitter to supply // storage for the address. - nni_posix_sockaddr2nn(aio->a_addr, (void *) &ss); + nni_posix_sockaddr2nn(sa, (void *) &ss); } nni_list_remove(q, aio); nni_aio_finish(aio, rv, cnt); @@ -109,19 +113,25 @@ nni_posix_udp_dosend(nni_plat_udp *udp) // While we're able to send, do so. while ((aio = nni_list_first(q)) != NULL) { struct sockaddr_storage ss; - struct msghdr hdr; - struct iovec iov[4]; - int niov; - int len; - int rv = 0; - int cnt = 0; - if ((len = nni_posix_nn2sockaddr(&ss, aio->a_addr)) < 0) { + int len; + int rv = 0; + int cnt = 0; + + len = nni_posix_nn2sockaddr(&ss, nni_aio_get_input(aio, 0)); + if (len < 0) { rv = NNG_EADDRINVAL; } else { - for (niov = 0; niov < aio->a_niov; niov++) { - iov[niov].iov_base = aio->a_iov[niov].iov_buf; - iov[niov].iov_len = aio->a_iov[niov].iov_len; + struct msghdr hdr; + struct iovec iov[4]; + int niov; + nni_iov * aiov; + + nni_aio_get_iov(aio, &niov, &aiov); + + for (int i = 0; i < niov; i++) { + iov[i].iov_base = aiov[i].iov_buf; + iov[i].iov_len = aiov[i].iov_len; } hdr.msg_iov = iov; hdr.msg_iovlen = niov; @@ -253,7 +263,7 @@ nni_plat_udp_close(nni_plat_udp *udp) void nni_plat_udp_cancel(nni_aio *aio, int rv) { - nni_plat_udp *udp = aio->a_prov_data; + nni_plat_udp *udp = nni_aio_get_prov_data(aio); nni_mtx_lock(&udp->udp_mtx); if (nni_aio_list_active(aio)) { diff --git a/src/platform/windows/win_iocp.c b/src/platform/windows/win_iocp.c index 0f9348d6..1189433a 100644 --- a/src/platform/windows/win_iocp.c +++ b/src/platform/windows/win_iocp.c @@ -89,7 +89,7 @@ nni_win_iocp_handler(void *arg) static void nni_win_event_cancel(nni_aio *aio, int rv) { - nni_win_event *evt = aio->a_prov_data; + nni_win_event *evt = nni_aio_get_prov_data(aio); nni_mtx_lock(&evt->mtx); if (aio == evt->active) { diff --git a/src/platform/windows/win_ipc.c b/src/platform/windows/win_ipc.c index 68a6ea2c..022a18ea 100644 --- a/src/platform/windows/win_ipc.c +++ b/src/platform/windows/win_ipc.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -60,9 +60,10 @@ nni_win_ipc_pipe_start(nni_win_event *evt, nni_aio *aio) int rv; nni_plat_ipc_pipe *pipe = evt->ptr; int idx; + int naiov; + nni_iov * aiov; NNI_ASSERT(aio != NULL); - NNI_ASSERT(aio->a_niov > 0); if (pipe->p == INVALID_HANDLE_VALUE) { evt->status = NNG_ECLOSED; @@ -70,18 +71,19 @@ nni_win_ipc_pipe_start(nni_win_event *evt, nni_aio *aio) return (1); } + nni_aio_get_iov(aio, &naiov, &aiov); idx = 0; - while ((idx < aio->a_niov) && (aio->a_iov[idx].iov_len == 0)) { + while ((idx < naiov) && (aiov[idx].iov_len == 0)) { idx++; } - NNI_ASSERT(idx < aio->a_niov); + NNI_ASSERT(idx < naiov); // Now start a transfer. We assume that only one send can be // outstanding on a pipe at a time. This is important to avoid // scrambling the data anyway. Note that Windows named pipes do // not appear to support scatter/gather, so we have to process // each element in turn. - buf = aio->a_iov[idx].iov_buf; - len = (DWORD) aio->a_iov[idx].iov_len; + buf = aiov[idx].iov_buf; + len = (DWORD) aiov[idx].iov_len; NNI_ASSERT(buf != NULL); NNI_ASSERT(len != 0); @@ -152,8 +154,6 @@ nni_win_ipc_pipe_init(nni_plat_ipc_pipe **pipep, HANDLE p) void nni_plat_ipc_pipe_send(nni_plat_ipc_pipe *pipe, nni_aio *aio) { - NNI_ASSERT(aio->a_niov > 0); - NNI_ASSERT(aio->a_iov[0].iov_len > 0); nni_win_event_submit(&pipe->snd_ev, aio); } @@ -198,7 +198,7 @@ nni_plat_ipc_ep_init(nni_plat_ipc_ep **epp, const nni_sockaddr *sa, int mode) if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - ZeroMemory(ep, sizeof(ep)); + ZeroMemory(ep, sizeof(*ep)); ep->mode = mode; NNI_LIST_NODE_INIT(&ep->node); @@ -465,7 +465,7 @@ static void nni_win_ipc_conn_cancel(nni_aio *aio, int rv) { nni_win_ipc_conn_work *w = &nni_win_ipc_connecter; - nni_plat_ipc_ep * ep = aio->a_prov_data; + nni_plat_ipc_ep * ep = nni_aio_get_prov_data(aio); nni_mtx_lock(&w->mtx); if (aio == ep->con_aio) { diff --git a/src/platform/windows/win_resolv.c b/src/platform/windows/win_resolv.c index 331a2a56..6ee55d16 100644 --- a/src/platform/windows/win_resolv.c +++ b/src/platform/windows/win_resolv.c @@ -47,7 +47,7 @@ nni_win_resolv_finish(nni_win_resolv_item *item, int rv) { nni_aio *aio = item->aio; - aio->a_prov_data = NULL; + nni_aio_set_prov_data(aio, NULL); nni_aio_finish(aio, rv, 0); NNI_FREE_STRUCT(item); } @@ -58,11 +58,11 @@ nni_win_resolv_cancel(nni_aio *aio, int rv) nni_win_resolv_item *item; nni_mtx_lock(&nni_win_resolv_mtx); - if ((item = aio->a_prov_data) == NULL) { + if ((item = nni_aio_get_prov_data(aio)) == NULL) { nni_mtx_unlock(&nni_win_resolv_mtx); return; } - aio->a_prov_data = NULL; + nni_aio_set_prov_data(aio, NULL); nni_mtx_unlock(&nni_win_resolv_mtx); nni_task_cancel(&item->task); NNI_FREE_STRUCT(item); @@ -141,7 +141,7 @@ nni_win_resolv_task(void *arg) if (probe != NULL) { struct sockaddr_in * sin; struct sockaddr_in6 *sin6; - nng_sockaddr * sa = aio->a_addr; + nni_sockaddr * sa = nni_aio_get_input(aio, 0); switch (probe->ai_addr->sa_family) { case AF_INET: diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c index 93cead91..c9935719 100644 --- a/src/platform/windows/win_tcp.c +++ b/src/platform/windows/win_tcp.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -101,22 +101,21 @@ nni_win_tcp_pipe_start(nni_win_event *evt, nni_aio *aio) { int rv; SOCKET s; - WSABUF iov[4]; + WSABUF iov[4]; // XXX: consider _alloca() DWORD niov; DWORD flags; nni_plat_tcp_pipe *pipe = evt->ptr; int i; + int naiov; + nni_iov * aiov; - NNI_ASSERT(aio->a_niov > 0); - NNI_ASSERT(aio->a_niov <= 4); - NNI_ASSERT(aio->a_iov[0].iov_len > 0); - NNI_ASSERT(aio->a_iov[0].iov_buf != NULL); + nni_aio_get_iov(aio, &naiov, &aiov); // Put the AIOs in Windows form. - for (niov = 0, i = 0; i < aio->a_niov; i++) { - if (aio->a_iov[i].iov_len != 0) { - iov[niov].buf = aio->a_iov[i].iov_buf; - iov[niov].len = (ULONG) aio->a_iov[i].iov_len; + for (niov = 0, i = 0; i < naiov; i++) { + if (aiov[i].iov_len != 0) { + iov[niov].buf = aiov[i].iov_buf; + iov[niov].len = (ULONG) aiov[i].iov_len; niov++; } } @@ -265,7 +264,7 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, if ((ep = NNI_ALLOC_STRUCT(ep)) == NULL) { return (NNG_ENOMEM); } - ZeroMemory(ep, sizeof(ep)); + ZeroMemory(ep, sizeof(*ep)); ep->s = INVALID_SOCKET; @@ -509,7 +508,7 @@ nni_win_tcp_acc_start(nni_win_event *evt, nni_aio *aio) void nni_plat_tcp_ep_accept(nni_plat_tcp_ep *ep, nni_aio *aio) { - aio->a_pipe = NULL; + nni_aio_set_pipe(aio, NULL); nni_win_event_submit(&ep->acc_ev, aio); } @@ -559,8 +558,7 @@ nni_win_tcp_con_finish(nni_win_event *evt, nni_aio *aio) len = sizeof(pipe->sockname); (void) getsockname(s, (SOCKADDR *) &pipe->sockname, &len); - aio->a_pipe = pipe; - nni_aio_finish(aio, 0, 0); + nni_aio_finish_pipe(aio, pipe); } static int @@ -630,7 +628,7 @@ nni_win_tcp_con_start(nni_win_event *evt, nni_aio *aio) extern void nni_plat_tcp_ep_connect(nni_plat_tcp_ep *ep, nni_aio *aio) { - aio->a_pipe = NULL; + nni_aio_set_pipe(aio, NULL); nni_win_event_submit(&ep->con_ev, aio); } diff --git a/src/platform/windows/win_udp.c b/src/platform/windows/win_udp.c index 678b4ae7..ba947719 100644 --- a/src/platform/windows/win_udp.c +++ b/src/platform/windows/win_udp.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -134,10 +134,11 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) { int rv; SOCKET s; - WSABUF iov[4]; - DWORD niov; + WSABUF iov[4]; // XXX: consider _alloca DWORD flags; nni_plat_udp *u = evt->ptr; + nni_iov * aiov; + int naiov; if ((s = u->s) == INVALID_SOCKET) { evt->status = NNG_ECLOSED; @@ -146,17 +147,12 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) } u->rxsalen = sizeof(SOCKADDR_STORAGE); - NNI_ASSERT(aio->a_niov > 0); - NNI_ASSERT(aio->a_niov <= 4); - NNI_ASSERT(aio->a_iov[0].iov_len > 0); - NNI_ASSERT(aio->a_iov[0].iov_buf != NULL); - - niov = aio->a_niov; + nni_aio_get_iov(aio, &naiov, &aiov); // Put the AIOs in Windows form. - for (int i = 0; i < aio->a_niov; i++) { - iov[i].buf = aio->a_iov[i].iov_buf; - iov[i].len = (ULONG) aio->a_iov[i].iov_len; + for (int i = 0; i < naiov; i++) { + iov[i].buf = aiov[i].iov_buf; + iov[i].len = (ULONG) aiov[i].iov_len; } // Note that the IOVs for the event were prepared on entry @@ -165,7 +161,7 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) evt->count = 0; flags = 0; - rv = WSARecvFrom(u->s, iov, niov, NULL, &flags, + rv = WSARecvFrom(u->s, iov, (DWORD) naiov, NULL, &flags, (struct sockaddr *) &u->rxsa, &u->rxsalen, &evt->olpd, NULL); if ((rv == SOCKET_ERROR) && @@ -188,9 +184,11 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) int rv; SOCKET s; WSABUF iov[4]; - DWORD niov; + int naiov; + nni_iov * aiov; nni_plat_udp *u = evt->ptr; int salen; + nni_sockaddr *sa; if ((s = u->s) == INVALID_SOCKET) { evt->status = NNG_ECLOSED; @@ -198,24 +196,19 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) return (1); } - if ((salen = nni_win_nn2sockaddr(&u->txsa, aio->a_addr)) < 0) { + sa = nni_aio_get_input(aio, 0); + + if ((salen = nni_win_nn2sockaddr(&u->txsa, sa)) < 0) { evt->status = NNG_EADDRINVAL; evt->count = 0; return (1); } - NNI_ASSERT(aio->a_addr != NULL); - NNI_ASSERT(aio->a_niov > 0); - NNI_ASSERT(aio->a_niov <= 4); - NNI_ASSERT(aio->a_iov[0].iov_len > 0); - NNI_ASSERT(aio->a_iov[0].iov_buf != NULL); - - niov = aio->a_niov; - + nni_aio_get_iov(aio, &naiov, &aiov); // Put the AIOs in Windows form. - for (int i = 0; i < aio->a_niov; i++) { - iov[i].buf = aio->a_iov[i].iov_buf; - iov[i].len = (ULONG) aio->a_iov[i].iov_len; + for (int i = 0; i < naiov; i++) { + iov[i].buf = aiov[i].iov_buf; + iov[i].len = (ULONG) aiov[i].iov_len; } // Note that the IOVs for the event were prepared on entry @@ -223,8 +216,8 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) evt->count = 0; - rv = WSASendTo(u->s, iov, niov, NULL, 0, (struct sockaddr *) &u->txsa, - salen, &evt->olpd, NULL); + rv = WSASendTo(u->s, iov, (DWORD) naiov, NULL, 0, + (struct sockaddr *) &u->txsa, salen, &evt->olpd, NULL); if ((rv == SOCKET_ERROR) && ((rv = GetLastError()) != ERROR_IO_PENDING)) { @@ -257,9 +250,10 @@ nni_win_udp_finish_rx(nni_win_event *evt, nni_aio *aio) cnt = evt->count; if ((rv = evt->status) == 0) { + nni_sockaddr *sa; // convert address from Windows form... - if (aio->a_addr != NULL) { - if (nni_win_sockaddr2nn(aio->a_addr, &u->rxsa) != 0) { + if ((sa = nni_aio_get_input(aio, 0)) != NULL) { + if (nni_win_sockaddr2nn(sa, &u->rxsa) != 0) { rv = NNG_EADDRINVAL; cnt = 0; } diff --git a/src/protocol/bus0/bus.c b/src/protocol/bus0/bus.c index 3e15000b..1176bf01 100644 --- a/src/protocol/bus0/bus.c +++ b/src/protocol/bus0/bus.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -31,7 +31,6 @@ static void bus0_sock_send(void *, nni_aio *); static void bus0_sock_recv(void *, nni_aio *); static void bus0_pipe_getq(bus0_pipe *); -static void bus0_pipe_send(bus0_pipe *); static void bus0_pipe_recv(bus0_pipe *); static void bus0_sock_getq_cb(void *); @@ -110,7 +109,7 @@ bus0_sock_close(void *arg) { bus0_sock *s = arg; - nni_aio_cancel(s->aio_getq, NNG_ECLOSED); + nni_aio_abort(s->aio_getq, NNG_ECLOSED); } static void diff --git a/src/protocol/pair0/pair.c b/src/protocol/pair0/pair.c index bac405b8..10498c0a 100644 --- a/src/protocol/pair0/pair.c +++ b/src/protocol/pair0/pair.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -191,7 +191,6 @@ static void pair0_getq_cb(void *arg) { pair0_pipe *p = arg; - pair0_sock *s = p->psock; if (nni_aio_result(p->aio_getq) != 0) { nni_pipe_stop(p->npipe); diff --git a/src/protocol/pipeline0/pull.c b/src/protocol/pipeline0/pull.c index 8c16cb17..44eb87f9 100644 --- a/src/protocol/pipeline0/pull.c +++ b/src/protocol/pipeline0/pull.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/protocol/pipeline0/push.c b/src/protocol/pipeline0/push.c index 3dd83fe0..2829e2aa 100644 --- a/src/protocol/pipeline0/push.c +++ b/src/protocol/pipeline0/push.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/protocol/pubsub0/pub.c b/src/protocol/pubsub0/pub.c index f4a33b77..285f40ca 100644 --- a/src/protocol/pubsub0/pub.c +++ b/src/protocol/pubsub0/pub.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -105,7 +105,7 @@ pub0_sock_close(void *arg) { pub0_sock *s = arg; - nni_aio_cancel(s->aio_getq, NNG_ECLOSED); + nni_aio_abort(s->aio_getq, NNG_ECLOSED); } static void diff --git a/src/protocol/pubsub0/sub.c b/src/protocol/pubsub0/sub.c index 6c504d75..a756e326 100644 --- a/src/protocol/pubsub0/sub.c +++ b/src/protocol/pubsub0/sub.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/src/protocol/reqrep0/rep.c b/src/protocol/reqrep0/rep.c index ee8e4277..f1a3a409 100644 --- a/src/protocol/reqrep0/rep.c +++ b/src/protocol/reqrep0/rep.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -116,7 +116,7 @@ rep0_sock_close(void *arg) { rep0_sock *s = arg; - nni_aio_cancel(s->aio_getq, NNG_ECLOSED); + nni_aio_abort(s->aio_getq, NNG_ECLOSED); } static void diff --git a/src/protocol/reqrep0/req.c b/src/protocol/reqrep0/req.c index 94c7f1a0..2a641933 100644 --- a/src/protocol/reqrep0/req.c +++ b/src/protocol/reqrep0/req.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -71,7 +71,6 @@ struct req0_pipe { nni_mtx mtx; }; -static void req0_resender(void *); static void req0_getq_cb(void *); static void req0_sendraw_cb(void *); static void req0_sendcooked_cb(void *); @@ -312,7 +311,6 @@ static void req0_getq_cb(void *arg) { req0_pipe *p = arg; - req0_sock *s = p->req; // We should be in RAW mode. Cooked mode traffic bypasses // the upper write queue entirely, and should never end up here. diff --git a/src/protocol/survey0/respond.c b/src/protocol/survey0/respond.c index 73e919c3..2f0514a9 100644 --- a/src/protocol/survey0/respond.c +++ b/src/protocol/survey0/respond.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -116,7 +116,7 @@ resp0_sock_close(void *arg) { resp0_sock *s = arg; - nni_aio_cancel(s->aio_getq, NNG_ECLOSED); + nni_aio_abort(s->aio_getq, NNG_ECLOSED); } static void diff --git a/src/protocol/survey0/survey.c b/src/protocol/survey0/survey.c index 3944a105..b8f10f0e 100644 --- a/src/protocol/survey0/survey.c +++ b/src/protocol/survey0/survey.c @@ -118,7 +118,7 @@ surv0_sock_close(void *arg) surv0_sock *s = arg; nni_timer_cancel(&s->timer); - nni_aio_cancel(s->aio_getq, NNG_ECLOSED); + nni_aio_abort(s->aio_getq, NNG_ECLOSED); } static void diff --git a/src/supplemental/http/CMakeLists.txt b/src/supplemental/http/CMakeLists.txt index 2c8d6a68..9cfbd14a 100644 --- a/src/supplemental/http/CMakeLists.txt +++ b/src/supplemental/http/CMakeLists.txt @@ -9,11 +9,18 @@ # if (NNG_SUPP_HTTP) -set(HTTP_SOURCES - supplemental/http/http.c - supplemental/http/http_msg.c - supplemental/http/server.c - supplemental/http/client.c - supplemental/http/http.h) + set(HTTP_DEFINES -DNNG_SUPP_HTTP) + set(HTTP_SOURCES + supplemental/http/http.h + supplemental/http/http_client.c + supplemental/http/http_conn.c + supplemental/http/http_msg.c + supplemental/http/http_public.c + supplemental/http/http_server.c) +else() + set(HTTP_SOURCES + supplemental/http/http.h + supplemental/http/http_public.c) endif() +set(NNG_DEFINES ${NNG_DEFINES} ${HTTP_DEFINES} PARENT_SCOPE) set(NNG_SOURCES ${NNG_SOURCES} ${HTTP_SOURCES} PARENT_SCOPE) diff --git a/src/supplemental/http/http.c b/src/supplemental/http/http.c deleted file mode 100644 index 2ba5b274..00000000 --- a/src/supplemental/http/http.c +++ /dev/null @@ -1,740 +0,0 @@ -// -// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> -// Copyright 2018 Capitar IT Group BV <info@capitar.com> -// -// This software is supplied under the terms of the MIT License, a -// copy of which should be located in the distribution where this -// file was obtained (LICENSE.txt). A copy of the license may also be -// found online at https://opensource.org/licenses/MIT. -// - -#include <stdbool.h> -#include <string.h> - -#include "core/nng_impl.h" -#include "supplemental/tls/tls.h" - -#include "http.h" - -// We insist that individual headers fit in 8K. -// If you need more than that, you need something we can't do. -#define HTTP_BUFSIZE 8192 - -// types of reads -enum read_flavor { - HTTP_RD_RAW, - HTTP_RD_FULL, - HTTP_RD_REQ, - HTTP_RD_RES, -}; - -enum write_flavor { - HTTP_WR_RAW, - HTTP_WR_FULL, - HTTP_WR_REQ, - HTTP_WR_RES, -}; - -typedef struct nni_http_tran { - void (*h_read)(void *, nni_aio *); - void (*h_write)(void *, nni_aio *); - int (*h_sock_addr)(void *, nni_sockaddr *); - int (*h_peer_addr)(void *, nni_sockaddr *); - bool (*h_verified)(void *); - void (*h_close)(void *); - void (*h_fini)(void *); -} nni_http_tran; - -#define SET_RD_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f)) -#define GET_RD_FLAVOR(aio) (int) ((intptr_t) aio->a_prov_extra[0]) -#define SET_WR_FLAVOR(aio, f) (aio)->a_prov_extra[0] = ((void *) (intptr_t)(f)) -#define GET_WR_FLAVOR(aio) (int) ((intptr_t) aio->a_prov_extra[0]) - -struct nni_http { - void *sock; - void (*rd)(void *, nni_aio *); - void (*wr)(void *, nni_aio *); - int (*sock_addr)(void *, nni_sockaddr *); - int (*peer_addr)(void *, nni_sockaddr *); - bool (*verified)(void *); - void (*close)(void *); - void (*fini)(void *); - - bool closed; - - nni_list rdq; // high level http read requests - nni_list wrq; // high level http write requests - - nni_aio *rd_uaio; // user aio for read - nni_aio *wr_uaio; // user aio for write - nni_aio *rd_aio; // bottom half read operations - nni_aio *wr_aio; // bottom half write operations - - nni_mtx mtx; - - uint8_t *rd_buf; - size_t rd_get; - size_t rd_put; - size_t rd_bufsz; -}; - -static void -http_close(nni_http *http) -{ - // Call with lock held. - nni_aio *aio; - - if (http->closed) { - return; - } - - http->closed = true; - if (nni_list_first(&http->wrq)) { - nni_aio_cancel(http->wr_aio, NNG_ECLOSED); - // Abort all operations except the one in flight. - while ((aio = nni_list_last(&http->wrq)) != - nni_list_first(&http->wrq)) { - nni_aio_list_remove(aio); - nni_aio_finish_error(aio, NNG_ECLOSED); - } - } - if (nni_list_first(&http->rdq)) { - nni_aio_cancel(http->rd_aio, NNG_ECLOSED); - while ((aio = nni_list_last(&http->rdq)) != - nni_list_first(&http->rdq)) { - nni_aio_list_remove(aio); - nni_aio_finish_error(aio, NNG_ECLOSED); - } - } - - if (http->sock != NULL) { - http->close(http->sock); - } -} - -void -nni_http_close(nni_http *http) -{ - nni_mtx_lock(&http->mtx); - http_close(http); - nni_mtx_unlock(&http->mtx); -} - -// http_rd_buf attempts to satisfy the read from data in the buffer. -static int -http_rd_buf(nni_http *http, nni_aio *aio) -{ - size_t cnt = http->rd_put - http->rd_get; - size_t n; - uint8_t *rbuf = http->rd_buf; - int i; - int rv; - bool raw = false; - - rbuf += http->rd_get; - - switch (GET_RD_FLAVOR(aio)) { - case HTTP_RD_RAW: - raw = true; // FALLTHROUGH - case HTTP_RD_FULL: - for (i = 0; (aio->a_niov != 0) && (cnt != 0); i++) { - // Pull up data from the buffer if possible. - n = aio->a_iov[0].iov_len; - if (n > cnt) { - n = cnt; - } - memcpy(aio->a_iov[0].iov_buf, rbuf, n); - aio->a_iov[0].iov_len -= n; - NNI_INCPTR(aio->a_iov[0].iov_buf, n); - http->rd_get += n; - rbuf += n; - aio->a_count += n; - cnt -= n; - - if (aio->a_iov[0].iov_len == 0) { - aio->a_niov--; - for (i = 0; i < aio->a_niov; i++) { - aio->a_iov[i] = aio->a_iov[i + 1]; - } - } - } - - if ((aio->a_niov == 0) || (raw && (aio->a_count != 0))) { - // Finished the read. (We are finished if we either - // got *all* the data, or we got *some* data for - // a raw read.) - return (0); - } - - // No more data left in the buffer, so use a physio. - // (Note that we get here if we either have not completed - // a full transaction on a FULL read, or were not even able - // to get *any* data for a partial RAW read.) - for (i = 0; i < aio->a_niov; i++) { - http->rd_aio->a_iov[i] = aio->a_iov[i]; - } - nni_aio_set_data(http->rd_aio, 1, NULL); - http->rd_aio->a_niov = aio->a_niov; - http->rd(http->sock, http->rd_aio); - return (NNG_EAGAIN); - - case HTTP_RD_REQ: - rv = nni_http_req_parse(aio->a_prov_extra[1], rbuf, cnt, &n); - http->rd_get += n; - if (http->rd_get == http->rd_put) { - http->rd_get = http->rd_put = 0; - } - if (rv == NNG_EAGAIN) { - http->rd_aio->a_niov = 1; - http->rd_aio->a_iov[0].iov_buf = - http->rd_buf + http->rd_put; - http->rd_aio->a_iov[0].iov_len = - http->rd_bufsz - http->rd_put; - nni_aio_set_data(http->rd_aio, 1, aio); - http->rd(http->sock, http->rd_aio); - } - return (rv); - - case HTTP_RD_RES: - rv = nni_http_res_parse(aio->a_prov_extra[1], rbuf, cnt, &n); - http->rd_get += n; - if (http->rd_get == http->rd_put) { - http->rd_get = http->rd_put = 0; - } - if (rv == NNG_EAGAIN) { - http->rd_aio->a_niov = 1; - http->rd_aio->a_iov[0].iov_buf = - http->rd_buf + http->rd_put; - http->rd_aio->a_iov[0].iov_len = - http->rd_bufsz - http->rd_put; - nni_aio_set_data(http->rd_aio, 1, aio); - http->rd(http->sock, http->rd_aio); - } - return (rv); - } - return (NNG_EINVAL); -} - -static void -http_rd_start(nni_http *http) -{ - for (;;) { - nni_aio *aio; - int rv; - - if ((aio = http->rd_uaio) == NULL) { - if ((aio = nni_list_first(&http->rdq)) == NULL) { - // No more stuff waiting for read. - return; - } - nni_list_remove(&http->rdq, aio); - http->rd_uaio = aio; - } - - if (http->closed) { - rv = NNG_ECLOSED; - } else { - rv = http_rd_buf(http, aio); - } - switch (rv) { - case NNG_EAGAIN: - return; - case 0: - http->rd_uaio = NULL; - nni_aio_finish(aio, 0, aio->a_count); - break; - default: - http->rd_uaio = NULL; - nni_aio_finish_error(aio, rv); - http_close(http); - break; - } - } -} - -static void -http_rd_cb(void *arg) -{ - nni_http *http = arg; - nni_aio * aio = http->rd_aio; - nni_aio * uaio; - size_t cnt; - int rv; - - nni_mtx_lock(&http->mtx); - - if ((rv = nni_aio_result(aio)) != 0) { - if ((uaio = http->rd_uaio) != NULL) { - http->rd_uaio = NULL; - nni_aio_finish_error(uaio, rv); - } - http_close(http); - nni_mtx_unlock(&http->mtx); - return; - } - - cnt = nni_aio_count(aio); - - // If we were reading into the buffer, then advance location(s). - if ((uaio = nni_aio_get_data(aio, 1)) != NULL) { - http->rd_put += cnt; - NNI_ASSERT(http->rd_put <= http->rd_bufsz); - http_rd_start(http); - nni_mtx_unlock(&http->mtx); - return; - } - - // Otherwise we are completing a USER request, and there should - // be no data left in the user buffer. - NNI_ASSERT(http->rd_get == http->rd_put); - - if ((uaio = http->rd_uaio) == NULL) { - // This indicates that a read request was canceled. This - // can occur only when shutting down, really. - nni_mtx_unlock(&http->mtx); - return; - } - - for (int i = 0; (uaio->a_niov != 0) && (cnt != 0); i++) { - // Pull up data from the buffer if possible. - size_t n = uaio->a_iov[0].iov_len; - if (n > cnt) { - n = cnt; - } - uaio->a_iov[0].iov_len -= n; - NNI_INCPTR(uaio->a_iov[0].iov_buf, n); - uaio->a_count += n; - cnt -= n; - - if (uaio->a_iov[0].iov_len == 0) { - uaio->a_niov--; - for (i = 0; i < uaio->a_niov; i++) { - uaio->a_iov[i] = uaio->a_iov[i + 1]; - } - } - } - - // Resubmit the start. This will attempt to consume data - // from the read buffer (there won't be any), and then either - // complete the I/O (for HTTP_RD_RAW, or if there is nothing left), - // or submit another physio. - http_rd_start(http); - nni_mtx_unlock(&http->mtx); -} - -static void -http_rd_cancel(nni_aio *aio, int rv) -{ - nni_http *http = aio->a_prov_data; - - nni_mtx_lock(&http->mtx); - if (aio == http->rd_uaio) { - http->rd_uaio = NULL; - nni_aio_cancel(http->rd_aio, rv); - nni_aio_finish_error(aio, rv); - } else if (nni_aio_list_active(aio)) { - nni_aio_list_remove(aio); - nni_aio_finish_error(aio, rv); - } - nni_mtx_unlock(&http->mtx); -} - -static void -http_rd_submit(nni_http *http, nni_aio *aio) -{ - if (nni_aio_start(aio, http_rd_cancel, http) != 0) { - return; - } - if (http->closed) { - nni_aio_finish_error(aio, NNG_ECLOSED); - return; - } - nni_list_append(&http->rdq, aio); - if (http->rd_uaio == NULL) { - http_rd_start(http); - } -} - -static void -http_wr_start(nni_http *http) -{ - nni_aio *aio; - - if ((aio = http->wr_uaio) == NULL) { - if ((aio = nni_list_first(&http->wrq)) == NULL) { - // No more stuff waiting for read. - return; - } - nni_list_remove(&http->wrq, aio); - http->wr_uaio = aio; - } - - for (int i = 0; i < aio->a_niov; i++) { - http->wr_aio->a_iov[i] = aio->a_iov[i]; - } - http->wr_aio->a_niov = aio->a_niov; - http->wr(http->sock, http->wr_aio); -} - -static void -http_wr_cb(void *arg) -{ - nni_http *http = arg; - nni_aio * aio = http->wr_aio; - nni_aio * uaio; - int rv; - size_t n; - - nni_mtx_lock(&http->mtx); - - uaio = http->wr_uaio; - - if ((rv = nni_aio_result(aio)) != 0) { - // We failed to complete the aio. - if (uaio != NULL) { - http->wr_uaio = NULL; - nni_aio_finish_error(uaio, rv); - } - http_close(http); - nni_mtx_unlock(&http->mtx); - return; - } - - if (uaio == NULL) { - // Write canceled? This happens pretty much only during - // shutdown/close, so we don't want to resume writing. - // The stream is probably corrupted at this point anyway. - nni_mtx_unlock(&http->mtx); - return; - } - - n = nni_aio_count(aio); - uaio->a_count += n; - if (GET_WR_FLAVOR(uaio) == HTTP_WR_RAW) { - // For raw data, we just send partial completion - // notices to the consumer. - goto done; - } - while (n) { - NNI_ASSERT(aio->a_niov != 0); - - if (aio->a_iov[0].iov_len > n) { - aio->a_iov[0].iov_len -= n; - NNI_INCPTR(aio->a_iov[0].iov_buf, n); - break; - } - n -= aio->a_iov[0].iov_len; - for (int i = 0; i < aio->a_niov; i++) { - aio->a_iov[i] = aio->a_iov[i + 1]; - } - aio->a_niov--; - } - if ((aio->a_niov != 0) && (aio->a_iov[0].iov_len != 0)) { - // We have more to transmit - start another and leave - // (we will get called again when it is done). - http->wr(http->sock, aio); - nni_mtx_unlock(&http->mtx); - return; - } - -done: - http->wr_uaio = NULL; - nni_aio_finish(uaio, 0, uaio->a_count); - - // Start next write if another is ready. - http_wr_start(http); - - nni_mtx_unlock(&http->mtx); -} - -static void -http_wr_cancel(nni_aio *aio, int rv) -{ - nni_http *http = aio->a_prov_data; - - nni_mtx_lock(&http->mtx); - if (aio == http->wr_uaio) { - http->wr_uaio = NULL; - nni_aio_cancel(http->wr_aio, rv); - nni_aio_finish_error(aio, rv); - } else if (nni_aio_list_active(aio)) { - nni_aio_list_remove(aio); - nni_aio_finish_error(aio, rv); - } - nni_mtx_unlock(&http->mtx); -} - -static void -http_wr_submit(nni_http *http, nni_aio *aio) -{ - if (nni_aio_start(aio, http_wr_cancel, http) != 0) { - return; - } - if (http->closed) { - nni_aio_finish_error(aio, NNG_ECLOSED); - return; - } - nni_list_append(&http->wrq, aio); - if (http->wr_uaio == NULL) { - http_wr_start(http); - } -} - -void -nni_http_read_req(nni_http *http, nni_http_req *req, nni_aio *aio) -{ - SET_RD_FLAVOR(aio, HTTP_RD_REQ); - aio->a_prov_extra[1] = req; - - nni_mtx_lock(&http->mtx); - http_rd_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_read_res(nni_http *http, nni_http_res *res, nni_aio *aio) -{ - SET_RD_FLAVOR(aio, HTTP_RD_RES); - aio->a_prov_extra[1] = res; - - nni_mtx_lock(&http->mtx); - http_rd_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_read_full(nni_http *http, nni_aio *aio) -{ - aio->a_count = 0; - SET_RD_FLAVOR(aio, HTTP_RD_FULL); - aio->a_prov_extra[1] = NULL; - - nni_mtx_lock(&http->mtx); - http_rd_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_read(nni_http *http, nni_aio *aio) -{ - SET_RD_FLAVOR(aio, HTTP_RD_RAW); - aio->a_prov_extra[1] = NULL; - - nni_mtx_lock(&http->mtx); - http_rd_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_write_req(nni_http *http, nni_http_req *req, nni_aio *aio) -{ - int rv; - void * buf; - size_t bufsz; - - if ((rv = nni_http_req_get_buf(req, &buf, &bufsz)) != 0) { - nni_aio_finish_error(aio, rv); - return; - } - aio->a_niov = 1; - aio->a_iov[0].iov_len = bufsz; - aio->a_iov[0].iov_buf = buf; - SET_WR_FLAVOR(aio, HTTP_WR_REQ); - - nni_mtx_lock(&http->mtx); - http_wr_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_write_res(nni_http *http, nni_http_res *res, nni_aio *aio) -{ - int rv; - void * buf; - size_t bufsz; - - if ((rv = nni_http_res_get_buf(res, &buf, &bufsz)) != 0) { - nni_aio_finish_error(aio, rv); - return; - } - aio->a_niov = 1; - aio->a_iov[0].iov_len = bufsz; - aio->a_iov[0].iov_buf = buf; - SET_WR_FLAVOR(aio, HTTP_WR_RES); - - nni_mtx_lock(&http->mtx); - http_wr_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -// Writer. As with nni_http_conn_write, this is used to write data on -// a connection that has been "upgraded" (e.g. transformed to -// websocket). It is an error to perform other HTTP exchanges on an -// connection after this method is called. (This mostly exists to -// support websocket.) -void -nni_http_write(nni_http *http, nni_aio *aio) -{ - SET_WR_FLAVOR(aio, HTTP_WR_RAW); - - nni_mtx_lock(&http->mtx); - http_wr_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -void -nni_http_write_full(nni_http *http, nni_aio *aio) -{ - SET_WR_FLAVOR(aio, HTTP_WR_FULL); - - nni_mtx_lock(&http->mtx); - http_wr_submit(http, aio); - nni_mtx_unlock(&http->mtx); -} - -int -nni_http_sock_addr(nni_http *http, nni_sockaddr *sa) -{ - int rv; - nni_mtx_lock(&http->mtx); - rv = http->closed ? NNG_ECLOSED : http->sock_addr(http->sock, sa); - nni_mtx_unlock(&http->mtx); - return (rv); -} - -int -nni_http_peer_addr(nni_http *http, nni_sockaddr *sa) -{ - int rv; - nni_mtx_lock(&http->mtx); - rv = http->closed ? NNG_ECLOSED : http->peer_addr(http->sock, sa); - nni_mtx_unlock(&http->mtx); - return (rv); -} - -bool -nni_http_tls_verified(nni_http *http) -{ - bool rv; - - nni_mtx_lock(&http->mtx); - rv = http->closed ? false : http->verified(http->sock); - nni_mtx_unlock(&http->mtx); - return (rv); -} - -void -nni_http_fini(nni_http *http) -{ - nni_mtx_lock(&http->mtx); - http_close(http); - if ((http->sock != NULL) && (http->fini != NULL)) { - http->fini(http->sock); - http->sock = NULL; - } - nni_mtx_unlock(&http->mtx); - nni_aio_stop(http->wr_aio); - nni_aio_stop(http->rd_aio); - nni_aio_fini(http->wr_aio); - nni_aio_fini(http->rd_aio); - nni_free(http->rd_buf, http->rd_bufsz); - nni_mtx_fini(&http->mtx); - NNI_FREE_STRUCT(http); -} - -static int -http_init(nni_http **httpp, nni_http_tran *tran, void *data) -{ - nni_http *http; - int rv; - - if ((http = NNI_ALLOC_STRUCT(http)) == NULL) { - return (NNG_ENOMEM); - } - http->rd_bufsz = HTTP_BUFSIZE; - if ((http->rd_buf = nni_alloc(http->rd_bufsz)) == NULL) { - NNI_FREE_STRUCT(http); - return (NNG_ENOMEM); - } - nni_mtx_init(&http->mtx); - nni_aio_list_init(&http->rdq); - nni_aio_list_init(&http->wrq); - - http->sock = data; - http->rd_bufsz = HTTP_BUFSIZE; - http->rd = tran->h_read; - http->wr = tran->h_write; - http->close = tran->h_close; - http->fini = tran->h_fini; - http->sock_addr = tran->h_sock_addr; - http->peer_addr = tran->h_peer_addr; - http->verified = tran->h_verified; - - if (((rv = nni_aio_init(&http->wr_aio, http_wr_cb, http)) != 0) || - ((rv = nni_aio_init(&http->rd_aio, http_rd_cb, http)) != 0)) { - nni_http_fini(http); - return (rv); - } - - *httpp = http; - - return (0); -} - -static bool -nni_http_verified_tcp(void *arg) -{ - NNI_ARG_UNUSED(arg); - return (false); -} - -static nni_http_tran http_tcp_ops = { - .h_read = (void *) nni_plat_tcp_pipe_recv, - .h_write = (void *) nni_plat_tcp_pipe_send, - .h_close = (void *) nni_plat_tcp_pipe_close, - .h_fini = (void *) nni_plat_tcp_pipe_fini, - .h_sock_addr = (void *) nni_plat_tcp_pipe_sockname, - .h_peer_addr = (void *) nni_plat_tcp_pipe_peername, - .h_verified = nni_http_verified_tcp, -}; - -int -nni_http_init_tcp(nni_http **hpp, void *tcp) -{ - return (http_init(hpp, &http_tcp_ops, tcp)); -} - -#ifdef NNG_SUPP_TLS -static nni_http_tran http_tls_ops = { - .h_read = (void *) nni_tls_recv, - .h_write = (void *) nni_tls_send, - .h_close = (void *) nni_tls_close, - .h_fini = (void *) nni_tls_fini, - .h_sock_addr = (void *) nni_tls_sockname, - .h_peer_addr = (void *) nni_tls_peername, - .h_verified = (void *) nni_tls_verified, -}; - -int -nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp) -{ - nni_tls *tls; - int rv; - - if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) { - nni_plat_tcp_pipe_fini(tcp); - return (rv); - } - - return (http_init(hpp, &http_tls_ops, tls)); -} -#else -int -nni_http_init_tls(nni_http **hpp, nng_tls_config *cfg, void *tcp) -{ - NNI_ARG_UNUSED(hpp); - NNI_ARG_UNUSED(cfg); - nni_plat_tcp_pipe_fini(tcp); - return (NNG_ENOTSUP); -} -#endif // NNG_SUPP_TLS
\ No newline at end of file diff --git a/src/supplemental/http/http.h b/src/supplemental/http/http.h index 93a94049..e44ddc76 100644 --- a/src/supplemental/http/http.h +++ b/src/supplemental/http/http.h @@ -11,113 +11,34 @@ #ifndef NNG_SUPPLEMENTAL_HTTP_HTTP_H #define NNG_SUPPLEMENTAL_HTTP_HTTP_H -#include <stdbool.h> - -typedef struct nni_http_res nni_http_res; -typedef struct nni_http_entity nni_http_entity; +#include "core/nng_impl.h" -typedef struct nni_http_req nni_http_req; +#include <stdbool.h> -extern int nni_http_req_init(nni_http_req **); -extern void nni_http_req_fini(nni_http_req *); -extern void nni_http_req_reset(nni_http_req *); -extern int nni_http_req_set_header(nni_http_req *, const char *, const char *); -extern int nni_http_req_add_header(nni_http_req *, const char *, const char *); -extern int nni_http_req_del_header(nni_http_req *, const char *); -extern int nni_http_req_get_buf(nni_http_req *, void **, size_t *); -extern int nni_http_req_set_method(nni_http_req *, const char *); -extern int nni_http_req_set_version(nni_http_req *, const char *); -extern int nni_http_req_set_uri(nni_http_req *, const char *); -extern const char *nni_http_req_get_header(nni_http_req *, const char *); -extern const char *nni_http_req_get_header(nni_http_req *, const char *); -extern const char *nni_http_req_get_version(nni_http_req *); -extern const char *nni_http_req_get_uri(nni_http_req *); -extern const char *nni_http_req_get_method(nni_http_req *); +typedef struct nng_http_req nni_http_req; +typedef struct nng_http_res nni_http_res; +typedef struct nng_http_conn nni_http_conn; +typedef struct nng_http_handler nni_http_handler; +typedef struct nng_http_server nni_http_server; + +// These functions are private to the internal framework, and really should +// not be used elsewhere. +extern int nni_http_req_init(nni_http_req **); +extern void nni_http_req_reset(nni_http_req *); +extern int nni_http_req_get_buf(nni_http_req *, void **, size_t *); extern int nni_http_req_parse(nni_http_req *, void *, size_t, size_t *); extern char *nni_http_req_headers(nni_http_req *); +extern void nni_http_req_get_data(nni_http_req *, void **, size_t *); -extern int nni_http_res_init(nni_http_res **); -extern void nni_http_res_fini(nni_http_res *); -extern void nni_http_res_reset(nni_http_res *); -extern int nni_http_res_get_buf(nni_http_res *, void **, size_t *); -extern int nni_http_res_set_header(nni_http_res *, const char *, const char *); -extern int nni_http_res_add_header(nni_http_res *, const char *, const char *); -extern int nni_http_res_del_header(nni_http_res *, const char *); -extern int nni_http_res_set_version(nni_http_res *, const char *); -extern int nni_http_res_set_status(nni_http_res *, int, const char *); -extern const char *nni_http_res_get_header(nni_http_res *, const char *); -extern const char *nni_http_res_get_version(nni_http_res *); -extern const char *nni_http_res_get_reason(nni_http_res *); -extern int nni_http_res_get_status(nni_http_res *); +extern void nni_http_res_reset(nni_http_res *); +extern int nni_http_res_get_buf(nni_http_res *, void **, size_t *); extern int nni_http_res_parse(nni_http_res *, void *, size_t, size_t *); -extern int nni_http_res_set_data(nni_http_res *, const void *, size_t); -extern int nni_http_res_copy_data(nni_http_res *, const void *, size_t); -extern int nni_http_res_alloc_data(nni_http_res *, size_t); extern void nni_http_res_get_data(nni_http_res *, void **, size_t *); -extern int nni_http_res_init_error(nni_http_res **, uint16_t); extern char *nni_http_res_headers(nni_http_res *); -// HTTP status codes. This list is not exhaustive. -enum { NNI_HTTP_STATUS_CONTINUE = 100, - NNI_HTTP_STATUS_SWITCHING = 101, - NNI_HTTP_STATUS_PROCESSING = 102, - NNI_HTTP_STATUS_OK = 200, - NNI_HTTP_STATUS_CREATED = 201, - NNI_HTTP_STATUS_ACCEPTED = 202, - NNI_HTTP_STATUS_NOT_AUTHORITATIVE = 203, - NNI_HTTP_STATUS_NO_CONTENT = 204, - NNI_HTTP_STATUS_RESET_CONTENT = 205, - NNI_HTTP_STATUS_PARTIAL_CONTENT = 206, - NNI_HTTP_STATUS_MULTI_STATUS = 207, - NNI_HTTP_STATUS_ALREADY_REPORTED = 208, - NNI_HTTP_STATUS_IM_USED = 226, - NNI_HTTP_STATUS_MULTIPLE_CHOICES = 300, - NNI_HTTP_STATUS_STATUS_MOVED_PERMANENTLY = 301, - NNI_HTTP_STATUS_FOUND = 302, - NNI_HTTP_STATUS_SEE_OTHER = 303, - NNI_HTTP_STATUS_NOT_MODIFIED = 304, - NNI_HTTP_STATUS_USE_PROXY = 305, - NNI_HTTP_STATUS_TEMPORARY_REDIRECT = 307, - NNI_HTTP_STATUS_PERMANENT_REDIRECT = 308, - NNI_HTTP_STATUS_BAD_REQUEST = 400, - NNI_HTTP_STATUS_UNAUTHORIZED = 401, - NNI_HTTP_STATUS_PAYMENT_REQUIRED = 402, - NNI_HTTP_STATUS_FORBIDDEN = 403, - NNI_HTTP_STATUS_NOT_FOUND = 404, - NNI_HTTP_STATUS_METHOD_NOT_ALLOWED = 405, - NNI_HTTP_STATUS_NOT_ACCEPTABLE = 406, - NNI_HTTP_STATUS_PROXY_AUTH_REQUIRED = 407, - NNI_HTTP_STATUS_REQUEST_TIMEOUT = 408, - NNI_HTTP_STATUS_CONFLICT = 409, - NNI_HTTP_STATUS_GONE = 410, - NNI_HTTP_STATUS_LENGTH_REQUIRED = 411, - NNI_HTTP_STATUS_PRECONDITION_FAILED = 412, - NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, - NNI_HTTP_STATUS_URI_TOO_LONG = 414, - NNI_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, - NNI_HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, - NNI_HTTP_STATUS_EXPECTATION_FAILED = 417, - NNI_HTTP_STATUS_TEAPOT = 418, - NNI_HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, - NNI_HTTP_STATUS_LOCKED = 423, - NNI_HTTP_STATUS_FAILED_DEPENDENCY = 424, - NNI_HTTP_STATUS_UPGRADE_REQUIRED = 426, - NNI_HTTP_STATUS_PRECONDITION_REQUIRED = 428, - NNI_HTTP_STATUS_TOO_MANY_REQUESTS = 429, - NNI_HTTP_STATUS_HEADERS_TOO_LARGE = 431, - NNI_HTTP_STATUS_UNAVAIL_LEGAL_REASONS = 451, - NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, - NNI_HTTP_STATUS_NOT_IMPLEMENTED = 501, - NNI_HTTP_STATUS_BAD_GATEWAY = 502, - NNI_HTTP_STATUS_SERVICE_UNAVAILABLE = 503, - NNI_HTTP_STATUS_GATEWAY_TIMEOUT = 504, - NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP = 505, - NNI_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, - NNI_HTTP_STATUS_INSUFFICIENT_STORAGE = 507, - NNI_HTTP_STATUS_LOOP_DETECTED = 508, - NNI_HTTP_STATUS_NOT_EXTENDED = 510, - NNI_HTTP_STATUS_NETWORK_AUTH_REQUIRED = 511, -}; +// Private to the server. (Used to support session hijacking.) +extern void nni_http_conn_set_ctx(nni_http_conn *, void *); +extern void *nni_http_conn_get_ctx(nni_http_conn *); // An HTTP connection is a connection over which messages are exchanged. // Generally, clients send request messages, and then read responses. @@ -132,39 +53,65 @@ enum { NNI_HTTP_STATUS_CONTINUE = 100, // // Any error on the connection, including cancellation of a request, is fatal // the connection. -typedef struct nni_http nni_http; // These initialization functions create stream for HTTP transactions. // They should only be used by the server or client HTTP implementations, // and are not for use by other code. -extern int nni_http_init_tcp(nni_http **, void *); -extern int nni_http_init_tls(nni_http **, nng_tls_config *, void *); +extern int nni_http_conn_init_tcp(nni_http_conn **, void *); +extern int nni_http_conn_init_tls(nni_http_conn **, nng_tls_config *, void *); -extern void nni_http_close(nni_http *); -extern void nni_http_fini(nni_http *); +extern void nni_http_conn_close(nni_http_conn *); +extern void nni_http_conn_fini(nni_http_conn *); // Reading messages -- the caller must supply a preinitialized (but otherwise // idle) message. We recommend the caller store this in the aio's user data. // Note that the iovs of the aio's are clobbered by these methods -- callers // must not use them for any other purpose. -extern void nni_http_write_req(nni_http *, nni_http_req *, nni_aio *); -extern void nni_http_write_res(nni_http *, nni_http_res *, nni_aio *); -extern void nni_http_read_req(nni_http *, nni_http_req *, nni_aio *); -extern void nni_http_read_res(nni_http *, nni_http_res *, nni_aio *); +extern int nni_http_req_alloc(nni_http_req **, const nni_url *); +extern int nni_http_res_alloc(nni_http_res **); +extern int nni_http_res_alloc_error(nni_http_res **, uint16_t); +extern void nni_http_req_free(nni_http_req *); +extern void nni_http_res_free(nni_http_res *); +extern void nni_http_write_req(nni_http_conn *, nni_http_req *, nni_aio *); +extern void nni_http_write_res(nni_http_conn *, nni_http_res *, nni_aio *); +extern void nni_http_read_req(nni_http_conn *, nni_http_req *, nni_aio *); +extern void nni_http_read_res(nni_http_conn *, nni_http_res *, nni_aio *); + +extern const char *nni_http_req_get_header(nni_http_req *, const char *); +extern const char *nni_http_res_get_header(nni_http_res *, const char *); +extern int nni_http_req_add_header(nni_http_req *, const char *, const char *); +extern int nni_http_res_add_header(nni_http_res *, const char *, const char *); +extern int nni_http_req_set_header(nni_http_req *, const char *, const char *); +extern int nni_http_res_set_header(nni_http_res *, const char *, const char *); +extern int nni_http_req_del_header(nni_http_req *, const char *); +extern int nni_http_res_del_header(nni_http_res *, const char *); +extern int nni_http_req_copy_data(nni_http_req *, const void *, size_t); +extern int nni_http_res_copy_data(nni_http_res *, const void *, size_t); +extern int nni_http_req_set_data(nni_http_req *, const void *, size_t); +extern int nni_http_res_set_data(nni_http_res *, const void *, size_t); +extern const char *nni_http_req_get_method(nni_http_req *); +extern const char *nni_http_req_get_version(nni_http_req *); +extern const char *nni_http_req_get_uri(nni_http_req *); +extern int nni_http_req_set_method(nni_http_req *, const char *); +extern int nni_http_req_set_version(nni_http_req *, const char *); +extern int nni_http_req_set_uri(nni_http_req *, const char *); +extern uint16_t nni_http_res_get_status(nni_http_res *); +extern int nni_http_res_set_status(nni_http_res *, uint16_t); +extern const char *nni_http_res_get_version(nni_http_res *); +extern int nni_http_res_set_version(nni_http_res *, const char *); +extern const char *nni_http_res_get_reason(nni_http_res *); +extern int nni_http_res_set_reason(nni_http_res *, const char *); -extern void nni_http_read(nni_http *, nni_aio *); -extern void nni_http_read_full(nni_http *, nni_aio *); -extern void nni_http_write(nni_http *, nni_aio *); -extern void nni_http_write_full(nni_http *, nni_aio *); -extern int nni_http_sock_addr(nni_http *, nni_sockaddr *); -extern int nni_http_peer_addr(nni_http *, nni_sockaddr *); +extern void nni_http_read(nni_http_conn *, nni_aio *); +extern void nni_http_read_full(nni_http_conn *, nni_aio *); +extern void nni_http_write(nni_http_conn *, nni_aio *); +extern void nni_http_write_full(nni_http_conn *, nni_aio *); +extern int nni_http_sock_addr(nni_http_conn *, nni_sockaddr *); +extern int nni_http_peer_addr(nni_http_conn *, nni_sockaddr *); // nni_tls_http_verified returns true if the peer has been verified using TLS. -extern bool nni_http_tls_verified(nni_http *); - -typedef struct nni_http_server nni_http_server; -typedef struct nni_http_handler nni_http_handler; +extern bool nni_http_tls_verified(nni_http_conn *); // nni_http_server will look for an existing server with the same // name and port, or create one if one does not exist. The servers @@ -174,7 +121,7 @@ typedef struct nni_http_handler nni_http_handler; // a restricted binding is required, we recommend using a URL consisting // of an empty host name, such as http:// or https:// -- this would // convert to binding to the default port on all interfaces on the host. -extern int nni_http_server_init(nni_http_server **, nni_url *); +extern int nni_http_server_init(nni_http_server **, const nni_url *); // nni_http_server_fini drops the reference count on the server, and // if this was the last reference, closes down the server and frees @@ -188,8 +135,10 @@ extern void nni_http_server_fini(nni_http_server *); extern int nni_http_server_add_handler(nni_http_server *, nni_http_handler *); // nni_http_del_handler removes the given handler. The caller is -// responsible for finalizing it afterwards. -extern void nni_http_server_del_handler(nni_http_server *, nni_http_handler *); +// responsible for finalizing it afterwards. If the handler was not found +// (not registered), NNG_ENOENT is returned. In this case it is unsafe +// to make assumptions about the validity of the handler. +extern int nni_http_server_del_handler(nni_http_server *, nni_http_handler *); // nni_http_server_set_tls adds a TLS configuration to the server, // and enables the use of it. This returns NNG_EBUSY if the server is @@ -212,10 +161,6 @@ extern int nni_http_server_start(nni_http_server *); // associated with a callback will complete their callback, and then close. extern void nni_http_server_stop(nni_http_server *); -// nni_http_ctx is the context associated with a particular request -// arriving at the server, and is tied to an underlying nni_http channel. -typedef struct nni_http_ctx nni_http_ctx; - // nni_http_hijack is intended to be called by a handler that wishes to // take over the processing of the HTTP session -- usually to change protocols // (such as in the case of websocket). The caller is responsible for obtaining @@ -226,12 +171,7 @@ typedef struct nni_http_ctx nni_http_ctx; // when a session is hijacked, the caller is also responsible for disposing // of the request structure. (Some hijackers may keep the request for // further processing.) -extern int nni_http_hijack(nni_http_ctx *); - -// nni_http_ctx_stream obtains the underlying nni_http channel for the -// context. This is used by hijackers, as well as anything that needs -// to handle sending its own replies on the channel. -extern int nni_http_ctx_stream(nni_http_ctx *, nni_http **); +extern int nni_http_hijack(nni_http_conn *); // nni_http_handler_init creates a server handler object, for the supplied // URI (path only) with the callback. @@ -241,7 +181,7 @@ extern int nni_http_ctx_stream(nni_http_ctx *, nni_http **); // once per server. // // The callback function will receive the following arguments (via -// nni_aio_get_input(): nni_http_request *, nni_http_handler *, and +// nng_aio_get_input(): nni_http_request *, nni_http_handler *, and // nni_http_context_t *. The first is a request object, for convenience. // The second is the handler, from which the callback can obtain any other // data it has set. The final is the http context, from which its possible @@ -255,12 +195,12 @@ extern int nni_http_handler_init_file( nni_http_handler **, const char *, const char *); // nni_http_handler_init_file_ctype is like nni_http_handler_init_file, but -// provides for settign the Content-Type explicitly (last argument). +// provides for setting the Content-Type explicitly (last argument). extern int nni_http_handler_init_file_ctype( nni_http_handler **, const char *, const char *, const char *); // nni_http_handler_init_directory arranges to serve up an entire -// directory tree. The content types are determined from the builtin +// directory tree. The content types are determined from the built-in // content type list. Actual directories are required to contain a // file called index.html or index.htm. We do not generate directory // listings for security reasons. @@ -277,17 +217,10 @@ extern int nni_http_handler_init_static( // calls this for any handlers still registered with it if it is destroyed. extern void nni_http_handler_fini(nni_http_handler *); -// nni_http_handler_set_dtor sets a callback that is executed when -// the handler is torn down. The argument to the destructor is the -// handler itself. This function is called by the nni_http_handler_fini -// function. -extern int nni_http_handler_set_dtor( - nni_http_handler *, void (*)(nni_http_handler *)); - // nni_http_handler_set_tree marks the handler as servicing the entire // tree (e.g. a directory), rather than just a leaf node. The handler // will probably need to inspect the URL of the request. -extern int nni_http_handler_set_tree(nni_http_handler *, bool); +extern int nni_http_handler_set_tree(nni_http_handler *); // nni_http_handler_set_host limits the handler to only being called for // the given Host: field. This can be used to set up multiple virtual @@ -312,14 +245,17 @@ extern int nni_http_handler_set_method(nni_http_handler *, const char *); // nni_http_handler_set_data sets an opaque data element on the handler, // which will be available to the callback via nni_http_handler_get_data. -// Note that indices used should be small, to minimize array allocations. -// This can fail with NNG_ENOMEM if storage cannot be allocated. -extern int nni_http_handler_set_data(nni_http_handler *, void *, unsigned); +// The callback is an optional destructor, and will be called with the +// data as its argument, when the handler is being destroyed. +extern int nni_http_handler_set_data(nni_http_handler *, void *, nni_cb); // nni_http_handler_get_data returns the data that was previously stored // at that index. It returns NULL if no data was set, or an invalid index // is supplied. -extern void *nni_http_handler_get_data(nni_http_handler *, unsigned); +extern void *nni_http_handler_get_data(nni_http_handler *); + +// nni_http_handler_get_uri returns the URI set on the handler. +extern const char *nni_http_handler_get_uri(nni_http_handler *); // Client stuff. diff --git a/src/supplemental/http/client.c b/src/supplemental/http/http_client.c index 4c54a708..345e5947 100644 --- a/src/supplemental/http/client.c +++ b/src/supplemental/http/http_client.c @@ -40,7 +40,7 @@ http_conn_done(void *arg) nni_aio * aio; int rv; nni_plat_tcp_pipe *p; - nni_http * http; + nni_http_conn * conn; nni_mtx_lock(&c->mtx); rv = nni_aio_result(c->connaio); @@ -61,9 +61,9 @@ http_conn_done(void *arg) } if (c->tls != NULL) { - rv = nni_http_init_tls(&http, c->tls, p); + rv = nni_http_conn_init_tls(&conn, c->tls, p); } else { - rv = nni_http_init_tcp(&http, p); + rv = nni_http_conn_init_tcp(&conn, p); } if (rv != 0) { nni_aio_finish_error(aio, rv); @@ -71,7 +71,7 @@ http_conn_done(void *arg) return; } - nni_aio_set_output(aio, 0, http); + nni_aio_set_output(aio, 0, conn); nni_aio_finish(aio, 0, 0); if (!nni_list_empty(&c->aios)) { @@ -124,9 +124,9 @@ nni_http_client_init(nni_http_client **cp, nni_url *url) if ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) { return (rv); } - aio->a_addr = &sa; - host = (strlen(url->u_hostname) != 0) ? url->u_hostname : NULL; - port = (strlen(url->u_port) != 0) ? url->u_port : NULL; + nni_aio_set_input(aio, 0, &sa); + host = (strlen(url->u_hostname) != 0) ? url->u_hostname : NULL; + port = (strlen(url->u_port) != 0) ? url->u_port : NULL; nni_plat_tcp_resolv(host, port, NNG_AF_UNSPEC, false, aio); nni_aio_wait(aio); rv = nni_aio_result(aio); @@ -221,14 +221,14 @@ nni_http_client_get_tls(nni_http_client *c, nng_tls_config **tlsp) static void http_connect_cancel(nni_aio *aio, int rv) { - nni_http_client *c = aio->a_prov_data; + nni_http_client *c = nni_aio_get_prov_data(aio); nni_mtx_lock(&c->mtx); if (nni_aio_list_active(aio)) { nni_aio_list_remove(aio); nni_aio_finish_error(aio, rv); } if (nni_list_empty(&c->aios)) { - nni_aio_cancel(c->connaio, rv); + nni_aio_abort(c->connaio, rv); } nni_mtx_unlock(&c->mtx); } @@ -245,4 +245,4 @@ nni_http_client_connect(nni_http_client *c, nni_aio *aio) http_conn_start(c); } nni_mtx_unlock(&c->mtx); -}
\ No newline at end of file +} diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c new file mode 100644 index 00000000..484d2242 --- /dev/null +++ b/src/supplemental/http/http_conn.c @@ -0,0 +1,765 @@ +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include <stdbool.h> +#include <string.h> + +#include "core/nng_impl.h" +#include "supplemental/tls/tls.h" + +#include "http.h" + +// We insist that individual headers fit in 8K. +// If you need more than that, you need something we can't do. +#define HTTP_BUFSIZE 8192 + +// types of reads +enum read_flavor { + HTTP_RD_RAW, + HTTP_RD_FULL, + HTTP_RD_REQ, + HTTP_RD_RES, +}; + +enum write_flavor { + HTTP_WR_RAW, + HTTP_WR_FULL, + HTTP_WR_REQ, + HTTP_WR_RES, +}; + +typedef struct nni_http_tran { + void (*h_read)(void *, nni_aio *); + void (*h_write)(void *, nni_aio *); + int (*h_sock_addr)(void *, nni_sockaddr *); + int (*h_peer_addr)(void *, nni_sockaddr *); + bool (*h_verified)(void *); + void (*h_close)(void *); + void (*h_fini)(void *); +} nni_http_tran; + +#define SET_RD_FLAVOR(aio, f) \ + nni_aio_set_prov_extra(aio, 0, ((void *) (intptr_t)(f))) +#define GET_RD_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0)) +#define SET_WR_FLAVOR(aio, f) \ + nni_aio_set_prov_extra(aio, 0, ((void *) (intptr_t)(f))) +#define GET_WR_FLAVOR(aio) (int) ((intptr_t) nni_aio_get_prov_extra(aio, 0)) + +struct nng_http_conn { + void *sock; + void (*rd)(void *, nni_aio *); + void (*wr)(void *, nni_aio *); + int (*sock_addr)(void *, nni_sockaddr *); + int (*peer_addr)(void *, nni_sockaddr *); + bool (*verified)(void *); + void (*close)(void *); + void (*fini)(void *); + + void *ctx; + bool closed; + + nni_list rdq; // high level http read requests + nni_list wrq; // high level http write requests + + nni_aio *rd_uaio; // user aio for read + nni_aio *wr_uaio; // user aio for write + nni_aio *rd_aio; // bottom half read operations + nni_aio *wr_aio; // bottom half write operations + + nni_mtx mtx; + + uint8_t *rd_buf; + size_t rd_get; + size_t rd_put; + size_t rd_bufsz; +}; + +void +nni_http_conn_set_ctx(nni_http_conn *conn, void *ctx) +{ + conn->ctx = ctx; +} + +void * +nni_http_conn_get_ctx(nni_http_conn *conn) +{ + return (conn->ctx); +} + +static void +http_close(nni_http_conn *conn) +{ + // Call with lock held. + nni_aio *aio; + + if (conn->closed) { + return; + } + + conn->closed = true; + if (nni_list_first(&conn->wrq)) { + nni_aio_abort(conn->wr_aio, NNG_ECLOSED); + // Abort all operations except the one in flight. + while ((aio = nni_list_last(&conn->wrq)) != + nni_list_first(&conn->wrq)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + } + if (nni_list_first(&conn->rdq)) { + nni_aio_abort(conn->rd_aio, NNG_ECLOSED); + while ((aio = nni_list_last(&conn->rdq)) != + nni_list_first(&conn->rdq)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, NNG_ECLOSED); + } + } + + if (conn->sock != NULL) { + conn->close(conn->sock); + } +} + +void +nni_http_conn_close(nni_http_conn *conn) +{ + nni_mtx_lock(&conn->mtx); + http_close(conn); + nni_mtx_unlock(&conn->mtx); +} + +// http_rd_buf attempts to satisfy the read from data in the buffer. +static int +http_rd_buf(nni_http_conn *conn, nni_aio *aio) +{ + size_t cnt = conn->rd_put - conn->rd_get; + size_t n; + uint8_t *rbuf = conn->rd_buf; + int rv; + bool raw = false; + nni_iov *iov; + int niov; + + rbuf += conn->rd_get; + + switch (GET_RD_FLAVOR(aio)) { + case HTTP_RD_RAW: + raw = true; // FALLTHROUGH + case HTTP_RD_FULL: + nni_aio_get_iov(aio, &niov, &iov); + while ((niov != 0) && (cnt != 0)) { + // Pull up data from the buffer if possible. + n = iov[0].iov_len; + if (n > cnt) { + n = cnt; + } + memcpy(iov[0].iov_buf, rbuf, n); + iov[0].iov_len -= n; + NNI_INCPTR(iov[0].iov_buf, n); + conn->rd_get += n; + rbuf += n; + nni_aio_bump_count(aio, n); + cnt -= n; + + if (iov[0].iov_len == 0) { + niov--; + iov = &iov[1]; + } + } + + nni_aio_set_iov(aio, niov, iov); + + if ((niov == 0) || (raw && (nni_aio_count(aio) != 0))) { + // Finished the read. (We are finished if we either + // got *all* the data, or we got *some* data for + // a raw read.) + return (0); + } + + // No more data left in the buffer, so use a physio. + // (Note that we get here if we either have not completed + // a full transaction on a FULL read, or were not even able + // to get *any* data for a partial RAW read.) + nni_aio_set_data(conn->rd_aio, 1, NULL); + nni_aio_set_iov(conn->rd_aio, niov, iov); + conn->rd(conn->sock, conn->rd_aio); + return (NNG_EAGAIN); + + case HTTP_RD_REQ: + rv = nni_http_req_parse( + nni_aio_get_prov_extra(aio, 1), rbuf, cnt, &n); + conn->rd_get += n; + if (conn->rd_get == conn->rd_put) { + conn->rd_get = conn->rd_put = 0; + } + if (rv == NNG_EAGAIN) { + nni_iov iov; + iov.iov_buf = conn->rd_buf + conn->rd_put; + iov.iov_len = conn->rd_bufsz - conn->rd_put; + nni_aio_set_iov(conn->rd_aio, 1, &iov); + nni_aio_set_data(conn->rd_aio, 1, aio); + conn->rd(conn->sock, conn->rd_aio); + } + return (rv); + + case HTTP_RD_RES: + rv = nni_http_res_parse( + nni_aio_get_prov_extra(aio, 1), rbuf, cnt, &n); + conn->rd_get += n; + if (conn->rd_get == conn->rd_put) { + conn->rd_get = conn->rd_put = 0; + } + if (rv == NNG_EAGAIN) { + nni_iov iov; + iov.iov_buf = conn->rd_buf + conn->rd_put; + iov.iov_len = conn->rd_bufsz - conn->rd_put; + nni_aio_set_iov(conn->rd_aio, 1, &iov); + nni_aio_set_data(conn->rd_aio, 1, aio); + conn->rd(conn->sock, conn->rd_aio); + } + return (rv); + } + return (NNG_EINVAL); +} + +static void +http_rd_start(nni_http_conn *conn) +{ + for (;;) { + nni_aio *aio; + int rv; + + if ((aio = conn->rd_uaio) == NULL) { + if ((aio = nni_list_first(&conn->rdq)) == NULL) { + // No more stuff waiting for read. + return; + } + nni_list_remove(&conn->rdq, aio); + conn->rd_uaio = aio; + } + + if (conn->closed) { + rv = NNG_ECLOSED; + } else { + rv = http_rd_buf(conn, aio); + } + switch (rv) { + case NNG_EAGAIN: + return; + case 0: + conn->rd_uaio = NULL; + nni_aio_finish(aio, 0, nni_aio_count(aio)); + break; + default: + conn->rd_uaio = NULL; + nni_aio_finish_error(aio, rv); + http_close(conn); + break; + } + } +} + +static void +http_rd_cb(void *arg) +{ + nni_http_conn *conn = arg; + nni_aio * aio = conn->rd_aio; + nni_aio * uaio; + size_t cnt; + int rv; + int niov; + nni_iov * iov; + + nni_mtx_lock(&conn->mtx); + + if ((rv = nni_aio_result(aio)) != 0) { + if ((uaio = conn->rd_uaio) != NULL) { + conn->rd_uaio = NULL; + nni_aio_finish_error(uaio, rv); + } + http_close(conn); + nni_mtx_unlock(&conn->mtx); + return; + } + + cnt = nni_aio_count(aio); + + // If we were reading into the buffer, then advance location(s). + if ((uaio = nni_aio_get_data(aio, 1)) != NULL) { + conn->rd_put += cnt; + NNI_ASSERT(conn->rd_put <= conn->rd_bufsz); + http_rd_start(conn); + nni_mtx_unlock(&conn->mtx); + return; + } + + // Otherwise we are completing a USER request, and there should + // be no data left in the user buffer. + NNI_ASSERT(conn->rd_get == conn->rd_put); + + if ((uaio = conn->rd_uaio) == NULL) { + // This indicates that a read request was canceled. This + // can occur only when shutting down, really. + nni_mtx_unlock(&conn->mtx); + return; + } + + nni_aio_get_iov(uaio, &niov, &iov); + + while ((niov != 0) && (cnt != 0)) { + // Pull up data from the buffer if possible. + size_t n = iov[0].iov_len; + if (n > cnt) { + n = cnt; + } + iov[0].iov_len -= n; + NNI_INCPTR(iov[0].iov_buf, n); + nni_aio_bump_count(uaio, n); + cnt -= n; + + if (iov[0].iov_len == 0) { + niov--; + iov = &iov[1]; + } + } + nni_aio_set_iov(uaio, niov, iov); + + // Resubmit the start. This will attempt to consume data + // from the read buffer (there won't be any), and then either + // complete the I/O (for HTTP_RD_RAW, or if there is nothing left), + // or submit another physio. + http_rd_start(conn); + nni_mtx_unlock(&conn->mtx); +} + +static void +http_rd_cancel(nni_aio *aio, int rv) +{ + nni_http_conn *conn = nni_aio_get_prov_data(aio); + + nni_mtx_lock(&conn->mtx); + if (aio == conn->rd_uaio) { + conn->rd_uaio = NULL; + nni_aio_abort(conn->rd_aio, rv); + nni_aio_finish_error(aio, rv); + } else if (nni_aio_list_active(aio)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&conn->mtx); +} + +static void +http_rd_submit(nni_http_conn *conn, nni_aio *aio) +{ + if (nni_aio_start(aio, http_rd_cancel, conn) != 0) { + return; + } + if (conn->closed) { + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + nni_list_append(&conn->rdq, aio); + if (conn->rd_uaio == NULL) { + http_rd_start(conn); + } +} + +static void +http_wr_start(nni_http_conn *conn) +{ + nni_aio *aio; + nni_iov *iov; + int niov; + + if ((aio = conn->wr_uaio) == NULL) { + if ((aio = nni_list_first(&conn->wrq)) == NULL) { + // No more stuff waiting for read. + return; + } + nni_list_remove(&conn->wrq, aio); + conn->wr_uaio = aio; + } + + nni_aio_get_iov(aio, &niov, &iov); + nni_aio_set_iov(conn->wr_aio, niov, iov); + conn->wr(conn->sock, conn->wr_aio); +} + +static void +http_wr_cb(void *arg) +{ + nni_http_conn *conn = arg; + nni_aio * aio = conn->wr_aio; + nni_aio * uaio; + int rv; + size_t n; + int niov; + nni_iov * iov; + + nni_mtx_lock(&conn->mtx); + + uaio = conn->wr_uaio; + + if ((rv = nni_aio_result(aio)) != 0) { + // We failed to complete the aio. + if (uaio != NULL) { + conn->wr_uaio = NULL; + nni_aio_finish_error(uaio, rv); + } + http_close(conn); + nni_mtx_unlock(&conn->mtx); + return; + } + + if (uaio == NULL) { + // Write canceled? This happens pretty much only during + // shutdown/close, so we don't want to resume writing. + // The stream is probably corrupted at this point anyway. + nni_mtx_unlock(&conn->mtx); + return; + } + + n = nni_aio_count(aio); + nni_aio_bump_count(uaio, n); + + if (GET_WR_FLAVOR(uaio) == HTTP_WR_RAW) { + // For raw data, we just send partial completion + // notices to the consumer. + goto done; + } + nni_aio_iov_advance(aio, n); + if (nni_aio_iov_count(aio) > 0) { + // We have more to transmit - start another and leave + // (we will get called again when it is done). + conn->wr(conn->sock, aio); + nni_mtx_unlock(&conn->mtx); + return; + } + +done: + conn->wr_uaio = NULL; + nni_aio_finish(uaio, 0, nni_aio_count(uaio)); + + // Start next write if another is ready. + http_wr_start(conn); + + nni_mtx_unlock(&conn->mtx); +} + +static void +http_wr_cancel(nni_aio *aio, int rv) +{ + nni_http_conn *conn = nni_aio_get_prov_data(aio); + + nni_mtx_lock(&conn->mtx); + if (aio == conn->wr_uaio) { + conn->wr_uaio = NULL; + nni_aio_abort(conn->wr_aio, rv); + nni_aio_finish_error(aio, rv); + } else if (nni_aio_list_active(aio)) { + nni_aio_list_remove(aio); + nni_aio_finish_error(aio, rv); + } + nni_mtx_unlock(&conn->mtx); +} + +static void +http_wr_submit(nni_http_conn *conn, nni_aio *aio) +{ + if (nni_aio_start(aio, http_wr_cancel, conn) != 0) { + return; + } + if (conn->closed) { + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } + nni_list_append(&conn->wrq, aio); + if (conn->wr_uaio == NULL) { + http_wr_start(conn); + } +} + +void +nni_http_read_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio) +{ + SET_RD_FLAVOR(aio, HTTP_RD_REQ); + nni_aio_set_prov_extra(aio, 1, req); + + nni_mtx_lock(&conn->mtx); + http_rd_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_read_res(nni_http_conn *conn, nni_http_res *res, nni_aio *aio) +{ + SET_RD_FLAVOR(aio, HTTP_RD_RES); + nni_aio_set_prov_extra(aio, 1, res); + + nni_mtx_lock(&conn->mtx); + http_rd_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_read_full(nni_http_conn *conn, nni_aio *aio) +{ + SET_RD_FLAVOR(aio, HTTP_RD_FULL); + nni_aio_set_prov_extra(aio, 1, NULL); + + nni_mtx_lock(&conn->mtx); + http_rd_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_read(nni_http_conn *conn, nni_aio *aio) +{ + SET_RD_FLAVOR(aio, HTTP_RD_RAW); + nni_aio_set_prov_extra(aio, 1, NULL); + + nni_mtx_lock(&conn->mtx); + http_rd_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_write_req(nni_http_conn *conn, nni_http_req *req, nni_aio *aio) +{ + int rv; + void * buf; + size_t bufsz; + void * data; + size_t size; + nni_iov iov[2]; + int niov; + + if ((rv = nni_http_req_get_buf(req, &buf, &bufsz)) != 0) { + nni_aio_finish_error(aio, rv); + return; + } + nni_http_req_get_data(req, &data, &size); + niov = 1; + iov[0].iov_len = bufsz; + iov[0].iov_buf = buf; + if ((size > 0) && (data != NULL)) { + niov++; + iov[1].iov_len = size; + iov[1].iov_buf = data; + } + nni_aio_set_iov(aio, niov, iov); + + SET_WR_FLAVOR(aio, HTTP_WR_REQ); + + nni_mtx_lock(&conn->mtx); + http_wr_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_write_res(nni_http_conn *conn, nni_http_res *res, nni_aio *aio) +{ + int rv; + void * buf; + size_t bufsz; + void * data; + size_t size; + nni_iov iov[2]; + int niov; + + if ((rv = nni_http_res_get_buf(res, &buf, &bufsz)) != 0) { + nni_aio_finish_error(aio, rv); + return; + } + nni_http_res_get_data(res, &data, &size); + niov = 1; + iov[0].iov_len = bufsz; + iov[0].iov_buf = buf; + if ((size > 0) && (data != NULL)) { + niov++; + iov[1].iov_len = size; + iov[1].iov_buf = data; + } + nni_aio_set_iov(aio, niov, iov); + + SET_WR_FLAVOR(aio, HTTP_WR_RES); + + nni_mtx_lock(&conn->mtx); + http_wr_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_write(nni_http_conn *conn, nni_aio *aio) +{ + SET_WR_FLAVOR(aio, HTTP_WR_RAW); + + nni_mtx_lock(&conn->mtx); + http_wr_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +void +nni_http_write_full(nni_http_conn *conn, nni_aio *aio) +{ + SET_WR_FLAVOR(aio, HTTP_WR_FULL); + + nni_mtx_lock(&conn->mtx); + http_wr_submit(conn, aio); + nni_mtx_unlock(&conn->mtx); +} + +int +nni_http_sock_addr(nni_http_conn *conn, nni_sockaddr *sa) +{ + int rv; + nni_mtx_lock(&conn->mtx); + rv = conn->closed ? NNG_ECLOSED : conn->sock_addr(conn->sock, sa); + nni_mtx_unlock(&conn->mtx); + return (rv); +} + +int +nni_http_peer_addr(nni_http_conn *conn, nni_sockaddr *sa) +{ + int rv; + nni_mtx_lock(&conn->mtx); + rv = conn->closed ? NNG_ECLOSED : conn->peer_addr(conn->sock, sa); + nni_mtx_unlock(&conn->mtx); + return (rv); +} + +bool +nni_http_tls_verified(nni_http_conn *conn) +{ + bool rv; + + nni_mtx_lock(&conn->mtx); + rv = conn->closed ? false : conn->verified(conn->sock); + nni_mtx_unlock(&conn->mtx); + return (rv); +} + +void +nni_http_conn_fini(nni_http_conn *conn) +{ + nni_mtx_lock(&conn->mtx); + http_close(conn); + if ((conn->sock != NULL) && (conn->fini != NULL)) { + conn->fini(conn->sock); + conn->sock = NULL; + } + nni_mtx_unlock(&conn->mtx); + nni_aio_stop(conn->wr_aio); + nni_aio_stop(conn->rd_aio); + nni_aio_fini(conn->wr_aio); + nni_aio_fini(conn->rd_aio); + nni_free(conn->rd_buf, conn->rd_bufsz); + nni_mtx_fini(&conn->mtx); + NNI_FREE_STRUCT(conn); +} + +static int +http_init(nni_http_conn **connp, nni_http_tran *tran, void *data) +{ + nni_http_conn *conn; + int rv; + + if ((conn = NNI_ALLOC_STRUCT(conn)) == NULL) { + return (NNG_ENOMEM); + } + conn->rd_bufsz = HTTP_BUFSIZE; + if ((conn->rd_buf = nni_alloc(conn->rd_bufsz)) == NULL) { + NNI_FREE_STRUCT(conn); + return (NNG_ENOMEM); + } + nni_mtx_init(&conn->mtx); + nni_aio_list_init(&conn->rdq); + nni_aio_list_init(&conn->wrq); + + conn->sock = data; + conn->rd_bufsz = HTTP_BUFSIZE; + conn->rd = tran->h_read; + conn->wr = tran->h_write; + conn->close = tran->h_close; + conn->fini = tran->h_fini; + conn->sock_addr = tran->h_sock_addr; + conn->peer_addr = tran->h_peer_addr; + conn->verified = tran->h_verified; + + if (((rv = nni_aio_init(&conn->wr_aio, http_wr_cb, conn)) != 0) || + ((rv = nni_aio_init(&conn->rd_aio, http_rd_cb, conn)) != 0)) { + nni_http_conn_fini(conn); + return (rv); + } + + *connp = conn; + + return (0); +} + +static bool +nni_http_verified_tcp(void *arg) +{ + NNI_ARG_UNUSED(arg); + return (false); +} + +static nni_http_tran http_tcp_ops = { + .h_read = (void *) nni_plat_tcp_pipe_recv, + .h_write = (void *) nni_plat_tcp_pipe_send, + .h_close = (void *) nni_plat_tcp_pipe_close, + .h_fini = (void *) nni_plat_tcp_pipe_fini, + .h_sock_addr = (void *) nni_plat_tcp_pipe_sockname, + .h_peer_addr = (void *) nni_plat_tcp_pipe_peername, + .h_verified = nni_http_verified_tcp, +}; + +int +nni_http_conn_init_tcp(nni_http_conn **connp, void *tcp) +{ + return (http_init(connp, &http_tcp_ops, tcp)); +} + +#ifdef NNG_SUPP_TLS +static nni_http_tran http_tls_ops = { + .h_read = (void *) nni_tls_recv, + .h_write = (void *) nni_tls_send, + .h_close = (void *) nni_tls_close, + .h_fini = (void *) nni_tls_fini, + .h_sock_addr = (void *) nni_tls_sockname, + .h_peer_addr = (void *) nni_tls_peername, + .h_verified = (void *) nni_tls_verified, +}; + +int +nni_http_conn_init_tls(nni_http_conn **connp, nng_tls_config *cfg, void *tcp) +{ + nni_tls *tls; + int rv; + + if ((rv = nni_tls_init(&tls, cfg, tcp)) != 0) { + nni_plat_tcp_pipe_fini(tcp); + return (rv); + } + + return (http_init(connp, &http_tls_ops, tls)); +} +#else +int +nni_http_conn_init_tls(nni_http_conn **connp, nng_tls_config *cfg, void *tcp) +{ + NNI_ARG_UNUSED(connp); + NNI_ARG_UNUSED(cfg); + nni_plat_tcp_pipe_fini(tcp); + return (NNG_ENOTSUP); +} +#endif // NNG_SUPP_TLS
\ No newline at end of file diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index da8c70f3..81c1b453 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -27,14 +27,14 @@ typedef struct http_header { nni_list_node node; } http_header; -struct nni_http_entity { +typedef struct nni_http_entity { char * data; size_t size; // allocated/expected size size_t len; // current length bool own; // if true, data is "ours", and should be freed -}; +} nni_http_entity; -struct nni_http_req { +struct nng_http_req { nni_list hdrs; nni_http_entity data; char * meth; @@ -42,23 +42,27 @@ struct nni_http_req { char * vers; char * buf; size_t bufsz; + bool parsed; }; -struct nni_http_res { +struct nng_http_res { nni_list hdrs; nni_http_entity data; - int code; + uint16_t code; char * rsn; char * vers; char * buf; size_t bufsz; + bool parsed; }; static int http_set_string(char **strp, const char *val) { char *news; - if ((news = nni_strdup(val)) == NULL) { + if (val == NULL) { + news = NULL; + } else if ((news = nni_strdup(val)) == NULL) { return (NNG_ENOMEM); } nni_strfree(*strp); @@ -114,6 +118,8 @@ nni_http_res_reset(nni_http_res *res) http_entity_reset(&res->data); nni_strfree(res->rsn); nni_strfree(res->vers); + res->vers = NULL; + res->rsn = NULL; res->code = 0; if (res->bufsz) { res->buf[0] = '\0'; @@ -121,7 +127,7 @@ nni_http_res_reset(nni_http_res *res) } void -nni_http_req_fini(nni_http_req *req) +nni_http_req_free(nni_http_req *req) { nni_http_req_reset(req); if (req->bufsz) { @@ -131,7 +137,7 @@ nni_http_req_fini(nni_http_req *req) } void -nni_http_res_fini(nni_http_res *res) +nni_http_res_free(nni_http_res *res) { nni_http_res_reset(res); if (res->bufsz) { @@ -157,13 +163,13 @@ http_del_header(nni_list *hdrs, const char *key) } int -nni_req_del_header(nni_http_req *req, const char *key) +nni_http_req_del_header(nni_http_req *req, const char *key) { return (http_del_header(&req->hdrs, key)); } int -nni_res_del_header(nni_http_res *res, const char *key) +nni_http_res_del_header(nni_http_res *res, const char *key) { return (http_del_header(&res->hdrs, key)); } @@ -398,12 +404,6 @@ nni_http_res_copy_data(nni_http_res *res, const void *data, size_t size) return (0); } -int -nni_http_res_alloc_data(nni_http_res *res, size_t size) -{ - return (http_entity_alloc_data(&res->data, size)); -} - static int http_parse_header(nni_list *hdrs, void *line) { @@ -501,11 +501,12 @@ static int http_req_prepare(nni_http_req *req) { int rv; - if ((req->uri == NULL) || (req->meth == NULL)) { + if (req->uri == NULL) { return (NNG_EINVAL); } rv = http_asprintf(&req->buf, &req->bufsz, &req->hdrs, "%s %s %s\r\n", - req->meth, req->uri, req->vers != NULL ? req->vers : "HTTP/1.1"); + req->meth != NULL ? req->meth : "GET", req->uri, + req->vers != NULL ? req->vers : "HTTP/1.1"); return (rv); } @@ -514,8 +515,8 @@ http_res_prepare(nni_http_res *res) { int rv; rv = http_asprintf(&res->buf, &res->bufsz, &res->hdrs, "%s %d %s\r\n", - res->vers != NULL ? res->vers : "HTTP/1.1", res->code, - res->rsn != NULL ? res->rsn : "Unknown Error"); + nni_http_res_get_version(res), nni_http_res_get_status(res), + nni_http_res_get_reason(res)); return (rv); } @@ -572,7 +573,7 @@ nni_http_res_get_buf(nni_http_res *res, void **data, size_t *szp) } int -nni_http_req_init(nni_http_req **reqp) +nni_http_req_alloc(nni_http_req **reqp, const nni_url *url) { nni_http_req *req; if ((req = NNI_ALLOC_STRUCT(req)) == NULL) { @@ -587,12 +588,33 @@ nni_http_req_init(nni_http_req **reqp) req->vers = NULL; req->meth = NULL; req->uri = NULL; - *reqp = req; + if (url != NULL) { + const char *host; + int rv; + if ((req->uri = nni_strdup(url->u_rawpath)) == NULL) { + NNI_FREE_STRUCT(req); + return (NNG_ENOMEM); + } + + // Add a Host: header since we know that from the URL. Also, + // only include the :port portion if it isn't the default port. + if (strcmp(nni_url_default_port(url->u_scheme), url->u_port) == + 0) { + host = url->u_hostname; + } else { + host = url->u_host; + } + if ((rv = nni_http_req_add_header(req, "Host", host)) != 0) { + nni_http_req_free(req); + return (rv); + } + } + *reqp = req; return (0); } int -nni_http_res_init(nni_http_res **resp) +nni_http_res_alloc(nni_http_res **resp) { nni_http_res *res; if ((res = NNI_ALLOC_STRUCT(res)) == NULL) { @@ -614,7 +636,7 @@ nni_http_res_init(nni_http_res **resp) const char * nni_http_req_get_method(nni_http_req *req) { - return (req->meth != NULL ? req->meth : ""); + return (req->meth != NULL ? req->meth : "GET"); } const char * @@ -626,24 +648,30 @@ nni_http_req_get_uri(nni_http_req *req) const char * nni_http_req_get_version(nni_http_req *req) { - return (req->vers != NULL ? req->vers : ""); + return (req->vers != NULL ? req->vers : "HTTP/1.1"); } const char * nni_http_res_get_version(nni_http_res *res) { - return (res->vers != NULL ? res->vers : ""); + return (res->vers != NULL ? res->vers : "HTTP/1.1"); } int nni_http_req_set_version(nni_http_req *req, const char *vers) { + if (strcmp(vers, "HTTP/1.1") == 0) { + vers = NULL; + } return (http_set_string(&req->vers, vers)); } int nni_http_res_set_version(nni_http_res *res, const char *vers) { + if (strcmp(vers, "HTTP/1.1") == 0) { + vers = NULL; + } return (http_set_string(&res->vers, vers)); } @@ -656,31 +684,25 @@ nni_http_req_set_uri(nni_http_req *req, const char *uri) int nni_http_req_set_method(nni_http_req *req, const char *meth) { + if (strcmp(meth, "GET") == 0) { + meth = NULL; + } return (http_set_string(&req->meth, meth)); } int -nni_http_res_set_status(nni_http_res *res, int status, const char *reason) +nni_http_res_set_status(nni_http_res *res, uint16_t status) { - int rv; - if ((rv = http_set_string(&res->rsn, reason)) == 0) { - res->code = status; - } - return (rv); + res->code = status; + return (0); } -int +uint16_t nni_http_res_get_status(nni_http_res *res) { return (res->code); } -const char * -nni_http_res_get_reason(nni_http_res *res) -{ - return (res->rsn != NULL ? res->rsn : ""); -} - static int http_scan_line(void *vbuf, size_t n, size_t *lenp) { @@ -740,6 +762,7 @@ http_req_parse_line(nni_http_req *req, void *line) ((rv = nni_http_req_set_version(req, version)) != 0)) { return (rv); } + req->parsed = true; return (0); } @@ -770,10 +793,12 @@ http_res_parse_line(nni_http_res *res, uint8_t *line) return (NNG_EPROTO); } - if (((rv = nni_http_res_set_status(res, status, reason)) != 0) || - ((rv = nni_http_res_set_version(res, version)) != 0)) { + if (((rv = nni_http_res_set_status(res, (uint16_t) status)) != 0) || + ((rv = nni_http_res_set_version(res, version)) != 0) || + ((rv = nni_http_res_set_reason(res, reason)) != 0)) { return (rv); } + res->parsed = true; return (0); } @@ -806,7 +831,7 @@ nni_http_req_parse(nni_http_req *req, void *buf, size_t n, size_t *lenp) break; } - if (req->vers != NULL) { + if (req->parsed) { rv = http_parse_header(&req->hdrs, line); } else { rv = http_req_parse_line(req, line); @@ -843,7 +868,7 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp) break; } - if (res->vers != NULL) { + if (res->parsed) { rv = http_parse_header(&res->hdrs, line); } else { rv = http_res_parse_line(res, line); @@ -858,105 +883,121 @@ nni_http_res_parse(nni_http_res *res, void *buf, size_t n, size_t *lenp) return (rv); } +static struct { + uint16_t code; + const char *mesg; +} http_status[] = { + // 200, listed first because most likely + { NNG_HTTP_STATUS_OK, "OK" }, + + // 100 series -- informational + { NNG_HTTP_STATUS_CONTINUE, "Continue" }, + { NNG_HTTP_STATUS_SWITCHING, "Swithching Protocols" }, + { NNG_HTTP_STATUS_PROCESSING, "Processing" }, + + // 200 series -- successful + { NNG_HTTP_STATUS_CREATED, "Created" }, + { NNG_HTTP_STATUS_ACCEPTED, "Accepted" }, + { NNG_HTTP_STATUS_NOT_AUTHORITATIVE, "Not Authoritative" }, + { NNG_HTTP_STATUS_NO_CONTENT, "No Content" }, + { NNG_HTTP_STATUS_RESET_CONTENT, "Reset Content" }, + { NNG_HTTP_STATUS_PARTIAL_CONTENT, "Partial Content" }, + + // 300 series -- redirection + { NNG_HTTP_STATUS_MULTIPLE_CHOICES, "Multiple Choices" }, + { NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY, "Moved Permanently" }, + { NNG_HTTP_STATUS_FOUND, "Found" }, + { NNG_HTTP_STATUS_SEE_OTHER, "See Other" }, + { NNG_HTTP_STATUS_NOT_MODIFIED, "Not Modified" }, + { NNG_HTTP_STATUS_USE_PROXY, "Use Proxy" }, + { NNG_HTTP_STATUS_TEMPORARY_REDIRECT, "Temporary Redirect" }, + + // 400 series -- client errors + { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Request" }, + { NNG_HTTP_STATUS_UNAUTHORIZED, "Unauthorized" }, + { NNG_HTTP_STATUS_PAYMENT_REQUIRED, "Payment Required" }, + { NNG_HTTP_STATUS_FORBIDDEN, "Forbidden" }, + { NNG_HTTP_STATUS_NOT_FOUND, "Not Found" }, + { NNG_HTTP_STATUS_METHOD_NOT_ALLOWED, "Method Not Allowed" }, + { NNG_HTTP_STATUS_NOT_ACCEPTABLE, "Not Acceptable" }, + { NNG_HTTP_STATUS_PROXY_AUTH_REQUIRED, + "Proxy Authentication Required" }, + { NNG_HTTP_STATUS_REQUEST_TIMEOUT, "Request Timeout" }, + { NNG_HTTP_STATUS_CONFLICT, "Conflict" }, + { NNG_HTTP_STATUS_GONE, "Gone" }, + { NNG_HTTP_STATUS_LENGTH_REQUIRED, "Length Required" }, + { NNG_HTTP_STATUS_PRECONDITION_FAILED, "Precondition Failed" }, + { NNG_HTTP_STATUS_ENTITY_TOO_LONG, "Request Entity Too Long" }, + { NNG_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type" }, + { NNG_HTTP_STATUS_RANGE_NOT_SATISFIABLE, + "Requested Range Not Satisfiable" }, + { NNG_HTTP_STATUS_EXPECTATION_FAILED, "Expectation Failed" }, + { NNG_HTTP_STATUS_TEAPOT, "I Am A Teapot" }, + { NNG_HTTP_STATUS_LOCKED, "Locked" }, + { NNG_HTTP_STATUS_FAILED_DEPENDENCY, "Failed Dependency" }, + { NNG_HTTP_STATUS_UPGRADE_REQUIRED, "Upgrade Required" }, + { NNG_HTTP_STATUS_PRECONDITION_REQUIRED, "Precondition Required" }, + { NNG_HTTP_STATUS_TOO_MANY_REQUESTS, "Too Many Requests" }, + { NNG_HTTP_STATUS_HEADERS_TOO_LARGE, "Headers Too Large" }, + { NNG_HTTP_STATUS_UNAVAIL_LEGAL_REASONS, + "Unavailable For Legal Reasons" }, + + // 500 series -- server errors + { NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR, "Internal Server Error" }, + { NNG_HTTP_STATUS_NOT_IMPLEMENTED, "Not Implemented" }, + { NNG_HTTP_STATUS_BAD_REQUEST, "Bad Gateway" }, + { NNG_HTTP_STATUS_SERVICE_UNAVAILABLE, "Service Unavailable" }, + { NNG_HTTP_STATUS_GATEWAY_TIMEOUT, "Gateway Timeout" }, + { NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP, + "HTTP Version Not Supported" }, + { NNG_HTTP_STATUS_VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates" }, + { NNG_HTTP_STATUS_INSUFFICIENT_STORAGE, "Insufficient Storage" }, + { NNG_HTTP_STATUS_LOOP_DETECTED, "Loop Detected" }, + { NNG_HTTP_STATUS_NOT_EXTENDED, "Not Extended" }, + { NNG_HTTP_STATUS_NETWORK_AUTH_REQUIRED, + "Network Authentication Required" }, + + // Terminator + { 0, NULL }, +}; + +const char * +http_reason(uint16_t code) +{ + for (int i = 0; http_status[i].code != 0; i++) { + if (http_status[i].code == code) { + return (http_status[i].mesg); + } + } + return ("Unknown HTTP Status"); +} + +const char * +nni_http_res_get_reason(nni_http_res *res) +{ + return (res->rsn ? res->rsn : http_reason(res->code)); +} + int -nni_http_res_init_error(nni_http_res **resp, uint16_t err) +nni_http_res_set_reason(nni_http_res *res, const char *reason) { - char * rsn; - char rsnbuf[80]; - char html[1024]; + if (strcmp(reason, http_reason(res->code)) == 0) { + reason = NULL; + } + return (http_set_string(&res->rsn, reason)); +} + +int +nni_http_res_alloc_error(nni_http_res **resp, uint16_t err) +{ + char html[512]; int rv; nni_http_res *res; - if ((rv = nni_http_res_init(&res)) != 0) { + if ((rv = nni_http_res_alloc(&res)) != 0) { return (rv); } - // Note that it is expected that redirect URIs will update the - // payload to reflect the target location. - switch (err) { - case NNI_HTTP_STATUS_STATUS_MOVED_PERMANENTLY: - rsn = "Moved Permanently"; - break; - case NNI_HTTP_STATUS_MULTIPLE_CHOICES: - rsn = "Multiple Choices"; - break; - case NNI_HTTP_STATUS_FOUND: - rsn = "Found"; - break; - case NNI_HTTP_STATUS_SEE_OTHER: - rsn = "See Other"; - break; - case NNI_HTTP_STATUS_TEMPORARY_REDIRECT: - rsn = "Temporary Redirect"; - break; - case NNI_HTTP_STATUS_BAD_REQUEST: - rsn = "Bad Request"; - break; - case NNI_HTTP_STATUS_UNAUTHORIZED: - rsn = "Unauthorized"; - break; - case NNI_HTTP_STATUS_PAYMENT_REQUIRED: - rsn = "Payment Required"; - break; - case NNI_HTTP_STATUS_NOT_FOUND: - rsn = "Not Found"; - break; - case NNI_HTTP_STATUS_METHOD_NOT_ALLOWED: - // Caller must also supply an Allow: header - rsn = "Method Not Allowed"; - break; - case NNI_HTTP_STATUS_NOT_ACCEPTABLE: - rsn = "Not Acceptable"; - break; - case NNI_HTTP_STATUS_REQUEST_TIMEOUT: - rsn = "Request Timeout"; - break; - case NNI_HTTP_STATUS_CONFLICT: - rsn = "Conflict"; - break; - case NNI_HTTP_STATUS_GONE: - rsn = "Gone"; - break; - case NNI_HTTP_STATUS_LENGTH_REQUIRED: - rsn = "Length Required"; - break; - case NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE: - rsn = "Payload Too Large"; - break; - case NNI_HTTP_STATUS_FORBIDDEN: - rsn = "Forbidden"; - break; - case NNI_HTTP_STATUS_URI_TOO_LONG: - rsn = "URI Too Long"; - break; - case NNI_HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: - rsn = "Unsupported Media Type"; - break; - case NNI_HTTP_STATUS_EXPECTATION_FAILED: - rsn = "Expectation Failed"; - break; - case NNI_HTTP_STATUS_UPGRADE_REQUIRED: - // Caller must add "Upgrade:" header. - rsn = "Upgrade Required"; - break; - case NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR: - rsn = "Internal Server Error"; - break; - case NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP: - rsn = "HTTP version not supported"; - break; - case NNI_HTTP_STATUS_NOT_IMPLEMENTED: - rsn = "Not Implemented"; - break; - case NNI_HTTP_STATUS_SERVICE_UNAVAILABLE: - rsn = "Service Unavailable"; - break; - default: - snprintf(rsnbuf, sizeof(rsnbuf), "HTTP error code %d", err); - rsn = rsnbuf; - break; - } - // very simple builtin error page (void) snprintf(html, sizeof(html), "<head><title>%d %s</title></head>" @@ -967,14 +1008,13 @@ nni_http_res_init_error(nni_http_res **resp, uint16_t err) "<p align=\"center\">" "<span style=\"font-size: 24px; font-family: Arial, sans serif;\">" "%s</span></p></body>", - err, rsn, err, rsn); + err, http_reason(err), err, http_reason(err)); - if (((rv = nni_http_res_set_status(res, err, rsn)) != 0) || - ((rv = nni_http_res_set_version(res, "HTTP/1.1")) != 0) || - ((rv = nni_http_res_set_header( + res->code = err; + if (((rv = nni_http_res_set_header( res, "Content-Type", "text/html; charset=UTF-8")) != 0) || ((rv = nni_http_res_copy_data(res, html, strlen(html))) != 0)) { - nni_http_res_fini(res); + nni_http_res_free(res); } else { *resp = res; } diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c new file mode 100644 index 00000000..f19b83b1 --- /dev/null +++ b/src/supplemental/http/http_public.c @@ -0,0 +1,668 @@ +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +#include "core/nng_impl.h" +#include "http.h" + +// Symbols in this file are "public" versions of the HTTP API. +// These are suitable for exposure to applications. + +int +nng_http_req_alloc(nng_http_req **reqp, const nng_url *url) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_alloc(reqp, url)); +#else + NNI_ARG_UNUSED(reqp); + NNI_ARG_UNUSED(url); + return (NNG_ENOTSUP); +#endif +} + +void +nng_http_req_free(nng_http_req *req) +{ +#ifdef NNG_SUPP_HTTP + nni_http_req_free(req); +#else + NNI_ARG_UNUSED(req); +#endif +} + +void +nng_http_res_free(nng_http_res *res) +{ +#ifdef NNG_SUPP_HTTP + nni_http_res_free(res); +#else + NNI_ARG_UNUSED(res); +#endif +} + +int +nng_http_res_alloc(nng_http_res **resp) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_alloc(resp)); +#else + NNI_ARG_UNUSED(resp); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_alloc_error(nng_http_res **resp, uint16_t code) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_alloc_error(resp, code)); +#else + NNI_ARG_UNUSED(resp); + NNI_ARG_UNUSED(code); + return (NNG_ENOTSUP); +#endif +} + +const char * +nng_http_req_get_header(nng_http_req *req, const char *key) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_get_header(req, key)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(key); + return (NULL); +#endif +} + +const char * +nng_http_res_get_header(nng_http_res *res, const char *key) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_get_header(res, key)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(key); + return (NULL); +#endif +} + +int +nng_http_req_add_header(nng_http_req *req, const char *key, const char *val) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_add_header(req, key, val)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(key); + NNI_ARG_UNUSED(val); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_add_header(nng_http_res *res, const char *key, const char *val) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_add_header(res, key, val)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(key); + NNI_ARG_UNUSED(val); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_set_header(nng_http_req *req, const char *key, const char *val) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_header(req, key, val)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(key); + NNI_ARG_UNUSED(val); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_set_header(nng_http_res *res, const char *key, const char *val) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_set_header(res, key, val)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(key); + NNI_ARG_UNUSED(val); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_del_header(nng_http_req *req, const char *key) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_del_header(req, key)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(key); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_del_header(nng_http_res *res, const char *key) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_del_header(res, key)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(key); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_copy_data(nng_http_req *req, const void *data, size_t sz) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_copy_data(req, data, sz)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(data); + NNI_ARG_UNUSED(sz); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_copy_data(nng_http_res *res, const void *data, size_t sz) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_copy_data(res, data, sz)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(data); + NNI_ARG_UNUSED(sz); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_set_data(nng_http_req *req, const void *data, size_t sz) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_data(req, data, sz)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(data); + NNI_ARG_UNUSED(sz); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_set_data(nng_http_res *res, const void *data, size_t sz) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_set_data(res, data, sz)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(data); + NNI_ARG_UNUSED(sz); + return (NNG_ENOTSUP); +#endif +} + +const char * +nng_http_req_get_method(nng_http_req *req) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_get_method(req)); +#else + NNI_ARG_UNUSED(req); + return (NULL); +#endif +} + +const char * +nng_http_req_get_version(nng_http_req *req) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_get_version(req)); +#else + NNI_ARG_UNUSED(req); + return (NULL); +#endif +} + +const char * +nng_http_req_get_uri(nng_http_req *req) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_get_uri(req)); +#else + NNI_ARG_UNUSED(req); + return (NULL); +#endif +} + +int +nng_http_req_set_method(nng_http_req *req, const char *meth) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_method(req, meth)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(meth); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_set_version(nng_http_req *req, const char *vers) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_version(req, vers)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(vers); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_req_set_uri(nng_http_req *req, const char *uri) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_req_set_uri(req, uri)); +#else + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(uri); + return (NNG_ENOTSUP); +#endif +} + +uint16_t +nng_http_res_get_status(nng_http_res *res) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_get_status(res)); +#else + NNI_ARG_UNUSED(res); + return (0); +#endif +} + +const char * +nng_http_res_get_version(nng_http_res *res) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_get_version(res)); +#else + NNI_ARG_UNUSED(res); + return (NULL); +#endif +} + +const char * +nng_http_res_get_reason(nng_http_res *res) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_get_reason(res)); +#else + NNI_ARG_UNUSED(res); + return (NULL); +#endif +} + +int +nng_http_res_set_status(nng_http_res *res, uint16_t status) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_set_status(res, status)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(status); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_set_version(nng_http_res *res, const char *vers) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_set_version(res, vers)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(vers); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_res_set_reason(nng_http_res *res, const char *rsn) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_res_set_reason(res, rsn)); +#else + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(rsn); + return (NNG_ENOTSUP); +#endif +} + +void +nng_http_conn_close(nng_http_conn *conn) +{ +#ifdef NNG_SUPP_HTTP + // API version of this closes *and* frees the structure. + nni_http_conn_fini(conn); +#else + NNI_ARG_UNUSED(conn); +#endif +} + +void +nng_http_conn_read(nng_http_conn *conn, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_read(conn, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_read_all(nng_http_conn *conn, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_read_full(conn, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_write(nng_http_conn *conn, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_write(conn, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_write_all(nng_http_conn *conn, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_write_full(conn, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_write_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_write_req(conn, req, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_write_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_write_res(conn, res, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_read_req(nng_http_conn *conn, nng_http_req *req, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_read_req(conn, req, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(req); + NNI_ARG_UNUSED(aio); +#endif +} + +void +nng_http_conn_read_res(nng_http_conn *conn, nng_http_res *res, nng_aio *aio) +{ +#ifdef NNG_SUPP_HTTP + nni_http_read_res(conn, res, aio); +#else + NNI_ARG_UNUSED(conn); + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(aio); +#endif +} + +int +nng_http_handler_alloc( + nng_http_handler **hp, const char *uri, void (*cb)(nng_aio *)) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_init(hp, uri, cb)); +#else + NNI_ARG_UNUSED(hp); + NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(cb); + return (NNG_ENOTSUP); +#endif +} + +void +nng_http_handler_free(nng_http_handler *h) +{ +#ifdef NNG_SUPP_HTTP + nni_http_handler_fini(h); +#else + NNI_ARG_UNUSED(h); +#endif +} + +int +nng_http_handler_alloc_file( + nng_http_handler **hp, const char *uri, const char *path) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_init_file(hp, uri, path)); +#else + NNI_ARG_UNUSED(hp); + NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(path); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_handler_alloc_directory( + nng_http_handler **hp, const char *uri, const char *path) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_init_directory(hp, uri, path)); +#else + NNI_ARG_UNUSED(hp); + NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(path); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_handler_alloc_static(nng_http_handler **hp, const char *uri, + const void *data, size_t size, const char *ctype) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_init_static(hp, uri, data, size, ctype)); +#else + NNI_ARG_UNUSED(hp); + NNI_ARG_UNUSED(uri); + NNI_ARG_UNUSED(data); + NNI_ARG_UNUSED(size); + NNI_ARG_UNUSED(ctype); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_handler_set_method(nng_http_handler *h, const char *meth) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_set_method(h, meth)); +#else + NNI_ARG_UNUSED(h); + NNI_ARG_UNUSED(meth); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_handler_set_host(nng_http_handler *h, const char *host) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_set_host(h, host)); +#else + NNI_ARG_UNUSED(h); + NNI_ARG_UNUSED(host); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_handler_set_data(nng_http_handler *h, void *dat, void (*dtor)(void *)) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_set_data(h, dat, dtor)); +#else + NNI_ARG_UNUSED(h); + NNI_ARG_UNUSED(dat); + NNI_ARG_UNUSED(dtor); + return (NNG_ENOTSUP); +#endif +} + +void * +nng_handler_get_data(nng_http_handler *h) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_handler_get_data(h)); +#else + NNI_ARG_UNUSED(h); + return (NULL); +#endif +} + +int +nng_http_server_hold(nng_http_server **srvp, const nng_url *url) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_init(srvp, url)); +#else + NNI_ARG_UNUSED(srvp); + NNI_ARG_UNUSED(url); +#endif +} + +void +nng_http_server_release(nng_http_server *srv) +{ +#ifdef NNG_SUPP_HTTP + nni_http_server_fini(srv); +#else + NNI_ARG_UNUSED(srv); +#endif +} + +int +nng_http_server_start(nng_http_server *srv) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_start(srv)); +#else + NNI_ARG_UNUSED(srv); +#endif +} + +void +nng_http_server_stop(nng_http_server *srv) +{ +#ifdef NNG_SUPP_HTTP + nni_http_server_stop(srv); +#else + NNI_ARG_UNUSED(srv); +#endif +} + +int +nng_http_server_add_handler(nng_http_server *srv, nng_http_handler *h) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_add_handler(srv, h)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(h); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_server_del_handler(nng_http_server *srv, nng_http_handler *h) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_del_handler(srv, h)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(h); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_server_set_tls(nng_http_server *srv, nng_tls_config *cfg) +{ +#if defined(NNG_SUPP_HTTP) && defined(NNG_SUPP_TLS) + return (nni_http_server_set_tls(srv, cfg)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(cfg); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_server_get_tls(nng_http_server *srv, nng_tls_config **cfgp) +{ +#if defined(NNG_SUPP_HTTP) && defined(NNG_SUPP_TLS) + return (nni_http_server_get_tls(srv, cfgp)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(cfgp); + return (NNG_ENOTSUP); +#endif +} diff --git a/src/supplemental/http/server.c b/src/supplemental/http/http_server.c index ecb544ea..21a88f9e 100644 --- a/src/supplemental/http/server.c +++ b/src/supplemental/http/http_server.c @@ -27,22 +27,21 @@ static nni_initializer http_server_initializer = { .i_once = 0, }; -struct nni_http_handler { +struct nng_http_handler { nni_list_node node; - void ** args; - unsigned nargs; char * path; - const char * method; + char * method; char * host; bool tree; int refcnt; + void * data; + nni_cb dtor; void (*cb)(nni_aio *); - void (*dtor)(nni_http_handler *); }; typedef struct nni_http_ctx { nni_list_node node; - nni_http * http; + nni_http_conn * conn; nni_http_server *server; nni_http_req * req; nni_http_res * res; @@ -56,7 +55,7 @@ typedef struct nni_http_ctx { nni_reap_item reap; } http_sconn; -struct nni_http_server { +struct nng_http_server { nng_sockaddr addr; nni_list_node node; int refcnt; @@ -82,16 +81,15 @@ nni_http_handler_init( if ((h = NNI_ALLOC_STRUCT(h)) == NULL) { return (NNG_ENOMEM); } - if ((h->path = nni_strdup(path)) == NULL) { - NNI_FREE_STRUCT(h); + if (((h->path = nni_strdup(path)) == NULL) || + ((h->method = nni_strdup("GET")) == NULL)) { + nni_http_handler_fini(h); return (NNG_ENOMEM); } NNI_LIST_NODE_INIT(&h->node); h->cb = cb; - h->args = NULL; - h->nargs = 0; + h->data = NULL; h->dtor = NULL; - h->method = "GET"; h->host = NULL; h->tree = false; h->refcnt = 0; @@ -106,54 +104,44 @@ nni_http_handler_fini(nni_http_handler *h) return; } if (h->dtor != NULL) { - h->dtor(h); - } - if (h->nargs > 0) { - nni_free(h->args, h->nargs * sizeof(void *)); + h->dtor(h->data); } nni_strfree(h->host); nni_strfree(h->path); + nni_strfree(h->method); NNI_FREE_STRUCT(h); } int -nni_http_handler_set_data(nni_http_handler *h, void *data, unsigned index) +nni_http_handler_set_data(nni_http_handler *h, void *data, nni_cb dtor) { if (h->refcnt != 0) { return (NNG_EBUSY); } - if (index >= h->nargs) { - void ** newargs; - unsigned newnargs = index + 4; // +4 to reduce allocations - if ((newargs = nni_alloc(newnargs * sizeof(void *))) == NULL) { - return (NNG_ENOMEM); - } - - memcpy(newargs, h->args, h->nargs * sizeof(void *)); - for (unsigned i = h->nargs; i < newnargs; i++) { - newargs[i] = NULL; - } - nni_free(h->args, h->nargs * sizeof(void *)); - h->args = newargs; - h->nargs = newnargs; - } - h->args[index] = data; + h->data = data; + h->dtor = dtor; return (0); } void * -nni_http_handler_get_data(nni_http_handler *h, unsigned index) +nni_http_handler_get_data(nni_http_handler *h) +{ + return (h->data); +} + +const char * +nni_http_handler_get_uri(nni_http_handler *h) { - return ((index < h->nargs) ? h->args[index] : NULL); + return (h->path); } int -nni_http_handler_set_tree(nni_http_handler *h, bool is_tree) +nni_http_handler_set_tree(nni_http_handler *h) { if (h->refcnt != 0) { return (NNG_EBUSY); } - h->tree = is_tree; + h->tree = true; return (0); } @@ -180,21 +168,20 @@ nni_http_handler_set_host(nni_http_handler *h, const char *host) int nni_http_handler_set_method(nni_http_handler *h, const char *method) { + char *dupmeth; if (h->refcnt != 0) { return (NNG_EBUSY); } - h->method = method; - return (0); -} - -int -nni_http_handler_set_dtor( - nni_http_handler *h, void (*dtor)(nni_http_handler *)) -{ - if (h->refcnt != 0) { - return (NNG_EBUSY); + if (method == NULL) { + nni_strfree(h->method); + h->method = NULL; + return (0); } - h->dtor = dtor; + if ((dupmeth = nni_strdup(method)) == NULL) { + return (NNG_ENOMEM); + } + nni_strfree(h->method); + h->method = dupmeth; return (0); } @@ -213,14 +200,14 @@ http_sconn_reap(void *arg) nni_aio_stop(sc->txdataio); nni_aio_stop(sc->cbaio); - if (sc->http != NULL) { - nni_http_fini(sc->http); + if (sc->conn != NULL) { + nni_http_conn_fini(sc->conn); } if (sc->req != NULL) { - nni_http_req_fini(sc->req); + nni_http_req_free(sc->req); } if (sc->res != NULL) { - nni_http_res_fini(sc->res); + nni_http_res_free(sc->res); } nni_aio_fini(sc->rxaio); nni_aio_fini(sc->txaio); @@ -249,9 +236,7 @@ http_sconn_fini(http_sconn *sc) static void http_sconn_close_locked(http_sconn *sc) { - nni_http_server *s; - s = sc->server; - nni_http *h; + nni_http_conn *conn; if (sc->closed) { return; @@ -259,13 +244,13 @@ http_sconn_close_locked(http_sconn *sc) NNI_ASSERT(!sc->finished); sc->closed = true; - nni_aio_cancel(sc->rxaio, NNG_ECLOSED); - nni_aio_cancel(sc->txaio, NNG_ECLOSED); - nni_aio_cancel(sc->txdataio, NNG_ECLOSED); - nni_aio_cancel(sc->cbaio, NNG_ECLOSED); + nni_aio_abort(sc->rxaio, NNG_ECLOSED); + nni_aio_abort(sc->txaio, NNG_ECLOSED); + nni_aio_abort(sc->txdataio, NNG_ECLOSED); + nni_aio_abort(sc->cbaio, NNG_ECLOSED); - if ((h = sc->http) != NULL) { - nni_http_close(h); + if ((conn = sc->conn) != NULL) { + nni_http_conn_close(conn); } http_sconn_fini(sc); } @@ -293,7 +278,7 @@ http_sconn_txdatdone(void *arg) } if (sc->res != NULL) { - nni_http_res_fini(sc->res); + nni_http_res_free(sc->res); sc->res = NULL; } @@ -303,7 +288,7 @@ http_sconn_txdatdone(void *arg) } nni_http_req_reset(sc->req); - nni_http_read_req(sc->http, sc->req, sc->rxaio); + nni_http_read_req(sc->conn, sc->req, sc->rxaio); } static void @@ -311,42 +296,23 @@ http_sconn_txdone(void *arg) { http_sconn *sc = arg; nni_aio * aio = sc->txaio; - int rv; - void * data; - size_t size; - if ((rv = nni_aio_result(aio)) != 0) { + if (nni_aio_result(aio) != 0) { http_sconn_close(sc); return; } - // For HEAD requests, we just treat like "GET" but don't send - // the data. (Required per HTTP.) - if (strcmp(nni_http_req_get_method(sc->req), "HEAD") == 0) { - size = 0; - } else { - nni_http_res_get_data(sc->res, &data, &size); - } - if (size) { - // Submit data. - sc->txdataio->a_niov = 1; - sc->txdataio->a_iov[0].iov_buf = data; - sc->txdataio->a_iov[0].iov_len = size; - nni_http_write_full(sc->http, sc->txdataio); - return; - } - if (sc->close) { http_sconn_close(sc); return; } if (sc->res != NULL) { - nni_http_res_fini(sc->res); + nni_http_res_free(sc->res); sc->res = NULL; } nni_http_req_reset(sc->req); - nni_http_read_req(sc->http, sc->req, sc->rxaio); + nni_http_read_req(sc->conn, sc->req, sc->rxaio); } static char @@ -364,6 +330,7 @@ http_hexval(char c) return (0); } +// XXX: REPLACE THIS WITH CODE USING THE URL FRAMEWORK. static char * http_uri_canonify(char *path) { @@ -430,7 +397,7 @@ http_sconn_error(http_sconn *sc, uint16_t err) { nni_http_res *res; - if (nni_http_res_init_error(&res, err) != 0) { + if (nni_http_res_alloc_error(&res, err) != 0) { http_sconn_close(sc); return; } @@ -441,32 +408,24 @@ http_sconn_error(http_sconn *sc, uint16_t err) } } sc->res = res; - nni_http_write_res(sc->http, res, sc->txaio); + nni_http_write_res(sc->conn, res, sc->txaio); } int -nni_http_hijack(nni_http_ctx *ctx) +nni_http_hijack(nni_http_conn *conn) { - nni_http_server *s = ctx->server; + http_sconn *sc; - nni_mtx_lock(&s->mtx); - ctx->http = NULL; - ctx->req = NULL; - nni_mtx_unlock(&s->mtx); - return (0); -} + sc = nni_http_conn_get_ctx(conn); + if (sc != NULL) { + nni_http_server *s = sc->server; + nni_http_conn_set_ctx(conn, NULL); -int -nni_http_ctx_stream(nni_http_ctx *ctx, nni_http **hpp) -{ - nni_http_server *s = ctx->server; - - nni_mtx_lock(&s->mtx); - if ((*hpp = ctx->http) == NULL) { + nni_mtx_lock(&s->mtx); + sc->conn = NULL; + sc->req = NULL; nni_mtx_unlock(&s->mtx); - return (NNG_ECLOSED); } - nni_mtx_unlock(&s->mtx); return (0); } @@ -498,12 +457,12 @@ http_sconn_rxdone(void *arg) // cope with HTTP/2. if ((val = nni_http_req_get_version(req)) == NULL) { sc->close = true; - http_sconn_error(sc, NNI_HTTP_STATUS_BAD_REQUEST); + http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST); return; } if (strncmp(val, "HTTP/1.", 7) != 0) { sc->close = true; - http_sconn_error(sc, NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP); + http_sconn_error(sc, NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP); return; } if (strcmp(val, "HTTP/1.1") != 0) { @@ -540,7 +499,8 @@ http_sconn_rxdone(void *arg) host = nni_http_req_get_header(req, "Host"); if ((host == NULL) && (needhost)) { // Per RFC 2616 14.23 we have to send 400 status here. - http_sconn_error(sc, NNI_HTTP_STATUS_BAD_REQUEST); + http_sconn_error(sc, NNG_HTTP_STATUS_BAD_REQUEST); + nni_free(uri, urisz); return; } @@ -616,16 +576,16 @@ http_sconn_rxdone(void *arg) nni_mtx_unlock(&s->mtx); if (badmeth) { http_sconn_error( - sc, NNI_HTTP_STATUS_METHOD_NOT_ALLOWED); + sc, NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); } else { - http_sconn_error(sc, NNI_HTTP_STATUS_NOT_FOUND); + http_sconn_error(sc, NNG_HTTP_STATUS_NOT_FOUND); } return; } nni_aio_set_input(sc->cbaio, 0, sc->req); nni_aio_set_input(sc->cbaio, 1, h); - nni_aio_set_input(sc->cbaio, 2, sc); + nni_aio_set_input(sc->cbaio, 2, sc->conn); // Technically, probably callback should initialize this with // start, but we do it instead. @@ -668,7 +628,7 @@ http_sconn_cbdone(void *arg) // If its an upgrader, and they didn't give us back a response, // it means that they took over, and we should just discard // this session, without closing the underlying channel. - if (sc->http == NULL) { + if (sc->conn == NULL) { // If this happens, then the session was hijacked. // We close the context, but the http channel stays up. http_sconn_close(sc); @@ -684,14 +644,24 @@ http_sconn_cbdone(void *arg) nni_http_res_set_header(res, "Connection", "close"); } sc->res = res; - nni_http_write_res(sc->http, res, sc->txaio); + if (strcmp(nni_http_req_get_method(sc->req), "HEAD") == 0) { + void * data; + size_t size; + // prune off the data, but preserve the content-length + // header. By passing NULL here, we leave off the old + // data, but the non-zero size means we don't clobber + // the HTTP header. + nni_http_res_get_data(res, &data, &size); + nni_http_res_set_data(res, NULL, size); + } + nni_http_write_res(sc->conn, res, sc->txaio); } else if (sc->close) { http_sconn_close(sc); } else { // Presumably client already sent a response. // Wait for another request. nni_http_req_reset(sc->req); - nni_http_read_req(sc->http, sc->req, sc->rxaio); + nni_http_read_req(sc->conn, sc->req, sc->rxaio); } } @@ -706,7 +676,7 @@ http_sconn_init(http_sconn **scp, nni_http_server *s, nni_plat_tcp_pipe *tcp) return (NNG_ENOMEM); } - if (((rv = nni_http_req_init(&sc->req)) != 0) || + if (((rv = nni_http_req_alloc(&sc->req, NULL)) != 0) || ((rv = nni_aio_init(&sc->rxaio, http_sconn_rxdone, sc)) != 0) || ((rv = nni_aio_init(&sc->txaio, http_sconn_txdone, sc)) != 0) || ((rv = nni_aio_init(&sc->txdataio, http_sconn_txdatdone, sc)) != @@ -718,14 +688,15 @@ http_sconn_init(http_sconn **scp, nni_http_server *s, nni_plat_tcp_pipe *tcp) } if (s->tls != NULL) { - rv = nni_http_init_tls(&sc->http, s->tls, tcp); + rv = nni_http_conn_init_tls(&sc->conn, s->tls, tcp); } else { - rv = nni_http_init_tcp(&sc->http, tcp); + rv = nni_http_conn_init_tcp(&sc->conn, tcp); } if (rv != 0) { http_sconn_close(sc); return (rv); } + nni_http_conn_set_ctx(sc->conn, sc); *scp = sc; return (0); } @@ -765,7 +736,7 @@ http_server_acccb(void *arg) sc->server = s; nni_list_append(&s->conns, sc); - nni_http_read_req(sc->http, sc->req, sc->rxaio); + nni_http_read_req(sc->conn, sc->req, sc->rxaio); nni_plat_tcp_ep_accept(s->tep, s->accaio); nni_mtx_unlock(&s->mtx); } @@ -816,14 +787,12 @@ nni_http_server_fini(nni_http_server *s) } static int -http_server_init(nni_http_server **serverp, nni_url *url) +http_server_init(nni_http_server **serverp, const nni_url *url) { nni_http_server *s; int rv; - const char * port; nni_aio * aio; - port = url->u_port; if ((strcmp(url->u_scheme, "http") != 0) && #ifdef NNG_SUPP_TLS (strcmp(url->u_scheme, "https") != 0) && @@ -874,7 +843,7 @@ http_server_init(nni_http_server **serverp, nni_url *url) http_server_fini(s); return (rv); } - aio->a_addr = &s->addr; + nni_aio_set_input(aio, 0, &s->addr); nni_plat_tcp_resolv(s->hostname, s->port, NNG_AF_UNSPEC, true, aio); nni_aio_wait(aio); rv = nni_aio_result(aio); @@ -889,7 +858,7 @@ http_server_init(nni_http_server **serverp, nni_url *url) } int -nni_http_server_init(nni_http_server **serverp, nni_url *url) +nni_http_server_init(nni_http_server **serverp, const nni_url *url) { int rv; nni_http_server *s; @@ -1058,15 +1027,22 @@ nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) return (0); } -void +int nni_http_server_del_handler(nni_http_server *s, nni_http_handler *h) { + int rv = NNG_ENOENT; + nni_http_handler *srch; nni_mtx_lock(&s->mtx); - if (nni_list_node_active(&h->node)) { - nni_list_remove(&s->handlers, h); - h->refcnt--; + NNI_LIST_FOREACH (&s->handlers, srch) { + if (srch == h) { + nni_list_remove(&s->handlers, h); + h->refcnt--; + rv = 0; + break; + } } nni_mtx_unlock(&s->mtx); + return (rv); } // Very limited MIME type map. Used only if the handler does not @@ -1127,6 +1103,11 @@ http_lookup_type(const char *path) return (NULL); } +typedef struct http_file { + char *path; + char *ctype; +} http_file; + static void http_handle_file(nni_aio *aio) { @@ -1135,31 +1116,36 @@ http_handle_file(nni_aio *aio) void * data; size_t size; int rv; - char * path = nni_http_handler_get_data(h, 0); - char * ctype = nni_http_handler_get_data(h, 1); + http_file * hf = nni_http_handler_get_data(h); + char * path = nni_http_handler_get_data(h); + const char * ctype; + + if ((ctype = hf->ctype) == NULL) { + ctype = "application/octet-stream"; + } // This is a very simplistic file server, suitable only for small // files. In the future we can use an AIO based file read, where // we read files a bit at a time, or even mmap them, and serve // them up chunkwise. Applications could even come up with their own // caching version of the http handler. - if ((rv = nni_file_get(path, &data, &size)) != 0) { + if ((rv = nni_file_get(hf->path, &data, &size)) != 0) { uint16_t status; switch (rv) { case NNG_ENOMEM: - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; case NNG_ENOENT: - status = NNI_HTTP_STATUS_NOT_FOUND; + status = NNG_HTTP_STATUS_NOT_FOUND; break; case NNG_EPERM: - status = NNI_HTTP_STATUS_FORBIDDEN; + status = NNG_HTTP_STATUS_FORBIDDEN; break; default: - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; } - if ((rv = nni_http_res_init_error(&res, status)) != 0) { + if ((rv = nni_http_res_alloc_error(&res, status)) != 0) { nni_aio_finish_error(aio, rv); return; } @@ -1167,14 +1153,13 @@ http_handle_file(nni_aio *aio) nni_aio_finish(aio, 0, 0); return; } - if (((rv = nni_http_res_init(&res)) != 0) || - ((rv = nni_http_res_set_status(res, NNI_HTTP_STATUS_OK, "OK")) != - 0) || + if (((rv = nni_http_res_alloc(&res)) != 0) || + ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { if (res != NULL) { - nni_http_res_fini(res); + nni_http_res_free(res); } nni_free(data, size); nni_aio_finish_error(aio, rv); @@ -1187,10 +1172,14 @@ http_handle_file(nni_aio *aio) } static void -http_file_dtor(nni_http_handler *h) +http_file_free(void *arg) { - char *p = nni_http_handler_get_data(h, 0); - nni_strfree(p); + http_file *hf; + if ((hf = arg) != NULL) { + nni_strfree(hf->path); + nni_strfree(hf->ctype); + NNI_FREE_STRUCT(hf); + } } int @@ -1198,8 +1187,12 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri, const char *path, const char *ctype) { nni_http_handler *h; + http_file * hf; int rv; - char * p; + + if ((hf = NNI_ALLOC_STRUCT(hf)) == NULL) { + return (NNG_ENOMEM); + } // Later we might want to do this in the server side, if we support // custom media type lists on a per-server basis. For now doing this @@ -1209,19 +1202,19 @@ nni_http_handler_init_file_ctype(nni_http_handler **hpp, const char *uri, ctype = "application/octet-stream"; } } - if ((p = nni_strdup(path)) == NULL) { + if (((hf->path = nni_strdup(path)) == NULL) || + ((hf->ctype = nni_strdup(ctype)) == NULL)) { + http_file_free(hf); return (NNG_ENOMEM); } if ((rv = nni_http_handler_init(&h, uri, http_handle_file)) != 0) { - nni_strfree(p); + http_file_free(hf); return (rv); } - if (((rv = nni_http_handler_set_data(h, p, 0)) != 0) || - ((rv = nni_http_handler_set_data(h, (void *) ctype, 1)) != 0) || - ((rv = nni_http_handler_set_dtor(h, http_file_dtor)))) { - nni_strfree(p); + if ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0) { + http_file_free(hf); nni_http_handler_fini(h); return (rv); } @@ -1238,16 +1231,7 @@ nni_http_handler_init_file( } static void -http_directory_dtor(nni_http_handler *h) -{ - char *path = nni_http_handler_get_data(h, 0); - char *base = nni_http_handler_get_data(h, 1); - nni_strfree(path); - nni_strfree(base); -} - -static void -http_handle_directory(nni_aio *aio) +http_handle_dir(nni_aio *aio) { nni_http_req * req = nni_aio_get_input(aio, 0); nni_http_handler *h = nni_aio_get_input(aio, 1); @@ -1255,8 +1239,9 @@ http_handle_directory(nni_aio *aio) void * data; size_t size; int rv; - char * path = nni_http_handler_get_data(h, 0); - const char * base = nni_http_handler_get_data(h, 1); // base uri + http_file * hf = nni_http_handler_get_data(h); + const char * path = hf->path; + const char * base = nni_http_handler_get_uri(h); // base uri const char * uri = nni_http_req_get_uri(req); const char * ctype; char * dst; @@ -1335,19 +1320,19 @@ http_handle_directory(nni_aio *aio) switch (rv) { case NNG_ENOMEM: - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; case NNG_ENOENT: - status = NNI_HTTP_STATUS_NOT_FOUND; + status = NNG_HTTP_STATUS_NOT_FOUND; break; case NNG_EPERM: - status = NNI_HTTP_STATUS_FORBIDDEN; + status = NNG_HTTP_STATUS_FORBIDDEN; break; default: - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; break; } - if ((rv = nni_http_res_init_error(&res, status)) != 0) { + if ((rv = nni_http_res_alloc_error(&res, status)) != 0) { nni_aio_finish_error(aio, rv); return; } @@ -1356,14 +1341,13 @@ http_handle_directory(nni_aio *aio) return; } - if (((rv = nni_http_res_init(&res)) != 0) || - ((rv = nni_http_res_set_status(res, NNI_HTTP_STATUS_OK, "OK")) != - 0) || + if (((rv = nni_http_res_alloc(&res)) != 0) || + ((rv = nni_http_res_set_status(res, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { if (res != NULL) { - nni_http_res_fini(res); + nni_http_res_free(res); } nni_free(data, size); nni_aio_finish_error(aio, rv); @@ -1379,31 +1363,27 @@ int nni_http_handler_init_directory( nni_http_handler **hpp, const char *uri, const char *path) { + http_file * hf; nni_http_handler *h; int rv; char * p; - char * b; - if ((p = nni_strdup(path)) == NULL) { + if ((hf = NNI_ALLOC_STRUCT(hf)) == NULL) { return (NNG_ENOMEM); } - if ((b = nni_strdup(uri)) == NULL) { - nni_strfree(p); + if ((hf->path = nni_strdup(path)) == NULL) { + NNI_FREE_STRUCT(hf); return (NNG_ENOMEM); } - if ((rv = nni_http_handler_init(&h, uri, http_handle_directory)) != - 0) { - nni_strfree(p); + if ((rv = nni_http_handler_init(&h, uri, http_handle_dir)) != 0) { + http_file_free(hf); return (rv); } - if (((rv = nni_http_handler_set_data(h, p, 0)) != 0) || - ((rv = nni_http_handler_set_data(h, b, 1)) != 0) || - ((rv = nni_http_handler_set_tree(h, true)) != 0) || - ((rv = nni_http_handler_set_dtor(h, http_directory_dtor)))) { - nni_strfree(p); - nni_strfree(b); + if (((rv = nni_http_handler_set_tree(h)) != 0) || + ((rv = nni_http_handler_set_data(h, hf, http_file_free)) != 0)) { + http_file_free(hf); nni_http_handler_fini(h); return (rv); } @@ -1412,32 +1392,34 @@ nni_http_handler_init_directory( return (0); } +typedef struct http_static { + void * data; + size_t size; + char * ctype; +} http_static; + static void http_handle_static(nni_aio *aio) { - void * data; - size_t size; - char * ctype; + http_static * hs; + const char * ctype; nni_http_handler *h; nni_http_res * r = NULL; int rv; - h = nni_aio_get_input(aio, 1); - data = nni_http_handler_get_data(h, 0); - size = (size_t)(uintptr_t) nni_http_handler_get_data(h, 1); - ctype = nni_http_handler_get_data(h, 2); + h = nni_aio_get_input(aio, 1); + hs = nni_http_handler_get_data(h); - if (ctype == NULL) { + if ((ctype = hs->ctype) == NULL) { ctype = "application/octet-stream"; } - if (((rv = nni_http_res_init(&r)) != 0) || + if (((rv = nni_http_res_alloc(&r)) != 0) || ((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) || - ((rv = nni_http_res_set_status(r, NNI_HTTP_STATUS_OK, "OK")) != - 0) || - ((rv = nni_http_res_set_data(r, data, size)) != 0)) { + ((rv = nni_http_res_set_status(r, NNG_HTTP_STATUS_OK)) != 0) || + ((rv = nni_http_res_set_data(r, hs->data, hs->size)) != 0)) { if (r != NULL) { - nni_http_res_fini(r); + nni_http_res_free(r); } nni_aio_finish_error(aio, rv); return; @@ -1448,12 +1430,15 @@ http_handle_static(nni_aio *aio) } static void -http_static_dtor(nni_http_handler *h) +http_static_free(void *arg) { - void * data = nni_http_handler_get_data(h, 0); - size_t size = (size_t)(uintptr_t) nni_http_handler_get_data(h, 1); + http_static *hs; - nni_free(data, size); + if ((hs = arg) != NULL) { + nni_free(hs->data, hs->size); + nni_strfree(hs->ctype); + NNI_FREE_STRUCT(hs); + } } int @@ -1462,23 +1447,26 @@ nni_http_handler_init_static(nni_http_handler **hpp, const char *uri, { nni_http_handler *h; int rv; - void * dat; + http_static * hs; - if ((dat = nni_alloc(size)) == NULL) { + if ((hs = NNI_ALLOC_STRUCT(hs)) == NULL) { + return (NNG_ENOMEM); + } + if (((hs->ctype = nni_strdup(ctype)) == NULL) || + ((size > 0) && ((hs->data = nni_alloc(size)) == NULL))) { + http_static_free(hs); return (NNG_ENOMEM); } - memcpy(dat, data, size); + hs->size = size; + memcpy(hs->data, data, size); if ((rv = nni_http_handler_init(&h, uri, http_handle_static)) != 0) { - nni_free(dat, size); + http_static_free(hs); return (rv); } - if (((rv = nni_http_handler_set_data(h, dat, 0)) != 0) || - ((rv = nni_http_handler_set_data(h, (void *) size, 1)) != 0) || - ((rv = nni_http_handler_set_data(h, (void *) ctype, 2)) != 0) || - ((rv = nni_http_handler_set_dtor(h, http_static_dtor)) != 0)) { - nni_free(dat, size); + if ((rv = nni_http_handler_set_data(h, hs, http_static_free)) != 0) { + http_static_free(hs); nni_http_handler_fini(h); return (rv); } @@ -1541,4 +1529,4 @@ static void http_server_sys_fini(void) { nni_mtx_fini(&http_servers_lk); -}
\ No newline at end of file +} diff --git a/src/supplemental/tls/CMakeLists.txt b/src/supplemental/tls/CMakeLists.txt index e78f1c13..1d0dd08d 100644 --- a/src/supplemental/tls/CMakeLists.txt +++ b/src/supplemental/tls/CMakeLists.txt @@ -11,6 +11,7 @@ if (NNG_SUPP_TLS) set(NNG_SUPP_TLS_MBEDTLS ON) set(TLS_SOURCES supplemental/tls/tls.h) + set(TLS_DEFINES -DNNG_SUPP_TLS) endif() # For now we only support the ARM mbedTLS library. @@ -35,4 +36,5 @@ if (NNG_SUPP_TLS_MBEDTLS) set(TLS_SOURCES ${TLS_SOURCES} supplemental/tls/mbedtls/tls.c) endif() +set(NNG_DEFINES ${NNG_DEFINES} ${TLS_DEFINES} PARENT_SCOPE) set(NNG_SOURCES ${NNG_SOURCES} ${TLS_SOURCES} PARENT_SCOPE) diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c index 4ae842a2..cb0a4bbf 100644 --- a/src/supplemental/tls/mbedtls/tls.c +++ b/src/supplemental/tls/mbedtls/tls.c @@ -365,7 +365,7 @@ nni_tls_init(nni_tls **tpp, nng_tls_config *cfg, nni_plat_tcp_pipe *tcp) static void nni_tls_cancel(nni_aio *aio, int rv) { - nni_tls *tp = aio->a_prov_data; + nni_tls *tp = nni_aio_get_prov_data(aio); nni_mtx_lock(&tp->lk); if (nni_aio_list_active(aio)) { nni_aio_list_remove(aio); @@ -407,11 +407,11 @@ nni_tls_send_cb(void *ctx) NNI_ASSERT(tp->sendlen <= n); tp->sendlen -= n; if (tp->sendlen) { + nni_iov iov; tp->sendoff += n; - - aio->a_niov = 1; - aio->a_iov[0].iov_buf = tp->sendbuf + tp->sendoff; - aio->a_iov[0].iov_len = tp->sendlen; + iov.iov_buf = tp->sendbuf + tp->sendoff; + iov.iov_len = tp->sendlen; + nni_aio_set_iov(aio, 1, &iov); nni_aio_set_timeout(aio, NNG_DURATION_INFINITE); nni_plat_tcp_pipe_send(tp->tcp, aio); nni_mtx_unlock(&tp->lk); @@ -434,6 +434,7 @@ static void nni_tls_recv_start(nni_tls *tp) { nni_aio *aio; + nni_iov iov; if (tp->recving || tp->tcp_closed) { return; @@ -444,12 +445,12 @@ nni_tls_recv_start(nni_tls *tp) return; } - tp->recving = 1; - tp->recvoff = 0; - aio = tp->tcp_recv; - aio->a_niov = 1; - aio->a_iov[0].iov_buf = tp->recvbuf; - aio->a_iov[0].iov_len = NNG_TLS_MAX_RECV_SIZE; + tp->recving = 1; + tp->recvoff = 0; + aio = tp->tcp_recv; + iov.iov_buf = tp->recvbuf; + iov.iov_len = NNG_TLS_MAX_RECV_SIZE; + nni_aio_set_iov(aio, 1, &iov); nni_aio_set_timeout(tp->tcp_recv, NNG_DURATION_INFINITE); nni_plat_tcp_pipe_recv(tp->tcp, aio); } @@ -498,6 +499,7 @@ int nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len) { nni_tls *tp = ctx; + nni_iov iov; if (len > NNG_TLS_MAX_SEND_SIZE) { len = NNG_TLS_MAX_SEND_SIZE; @@ -517,10 +519,9 @@ nni_tls_net_send(void *ctx, const unsigned char *buf, size_t len) tp->sendlen = len; tp->sendoff = 0; memcpy(tp->sendbuf, buf, len); - - tp->tcp_send->a_niov = 1; - tp->tcp_send->a_iov[0].iov_buf = tp->sendbuf; - tp->tcp_send->a_iov[0].iov_len = len; + iov.iov_buf = tp->sendbuf; + iov.iov_len = len; + nni_aio_set_iov(tp->tcp_send, 1, &iov); nni_aio_set_timeout(tp->tcp_send, NNG_DURATION_INFINITE); nni_plat_tcp_pipe_send(tp->tcp, tp->tcp_send); return (len); @@ -640,11 +641,15 @@ nni_tls_do_send(nni_tls *tp) int n; uint8_t *buf = NULL; size_t len = 0; + nni_iov *iov; + int niov; - for (int i = 0; i < aio->a_niov; i++) { - if (aio->a_iov[i].iov_len != 0) { - buf = aio->a_iov[i].iov_buf; - len = aio->a_iov[i].iov_len; + nni_aio_get_iov(aio, &niov, &iov); + + for (int i = 0; i < niov; i++) { + if (iov[i].iov_len != 0) { + buf = iov[i].iov_buf; + len = iov[i].iov_len; break; } } @@ -682,11 +687,15 @@ nni_tls_do_recv(nni_tls *tp) int n; uint8_t *buf = NULL; size_t len = 0; + nni_iov *iov; + int niov; + + nni_aio_get_iov(aio, &niov, &iov); - for (int i = 0; i < aio->a_niov; i++) { - if (aio->a_iov[i].iov_len != 0) { - buf = aio->a_iov[i].iov_buf; - len = aio->a_iov[i].iov_len; + for (int i = 0; i < niov; i++) { + if (iov[i].iov_len != 0) { + buf = iov[i].iov_buf; + len = iov[i].iov_len; break; } } @@ -865,7 +874,7 @@ nng_tls_config_own_cert( pem = (const uint8_t *) key; len = strlen(key) + 1; rv = mbedtls_pk_parse_key(&ck->key, pem, len, (const uint8_t *) pass, - pass != NULL ? strlen(pass) : 0); + pass != NULL ? strlen(pass) : 0); if (rv != 0) { rv = nni_tls_mkerr(rv); goto err; diff --git a/src/supplemental/tls/tls.h b/src/supplemental/tls/tls.h index 57b552d7..4dd94290 100644 --- a/src/supplemental/tls/tls.h +++ b/src/supplemental/tls/tls.h @@ -34,8 +34,8 @@ extern void nni_tls_config_hold(nng_tls_config *); extern int nni_tls_init(nni_tls **, nng_tls_config *, nni_plat_tcp_pipe *); extern void nni_tls_close(nni_tls *); extern void nni_tls_fini(nni_tls *); -extern void nni_tls_send(nni_tls *, nni_aio *); -extern void nni_tls_recv(nni_tls *, nni_aio *); +extern void nni_tls_send(nni_tls *, nng_aio *); +extern void nni_tls_recv(nni_tls *, nng_aio *); extern int nni_tls_sockname(nni_tls *, nni_sockaddr *); extern int nni_tls_peername(nni_tls *, nni_sockaddr *); diff --git a/src/supplemental/websocket/websocket.c b/src/supplemental/websocket/websocket.c index 8e75490b..ad4ce196 100644 --- a/src/supplemental/websocket/websocket.c +++ b/src/supplemental/websocket/websocket.c @@ -47,7 +47,7 @@ struct nni_ws { nni_aio * httpaio; nni_aio * connaio; // connect aio nni_aio * useraio; // user aio, during HTTP negotiation - nni_http * http; + nni_http_conn * http; nni_http_req * req; nni_http_res * res; char * reqhdrs; @@ -411,10 +411,10 @@ ws_close_cb(void *arg) // we are done, and its time to abort everything else. nni_mtx_lock(&ws->mtx); - nni_http_close(ws->http); - nni_aio_cancel(ws->txaio, NNG_ECLOSED); - nni_aio_cancel(ws->rxaio, NNG_ECLOSED); - nni_aio_cancel(ws->httpaio, NNG_ECLOSED); + nni_http_conn_close(ws->http); + nni_aio_abort(ws->txaio, NNG_ECLOSED); + nni_aio_abort(ws->rxaio, NNG_ECLOSED); + nni_aio_abort(ws->httpaio, NNG_ECLOSED); // This list (receive) should be empty. while ((wm = nni_list_first(&ws->rxmsgs)) != NULL) { @@ -463,8 +463,8 @@ ws_close(nni_ws *ws, uint16_t code) // pending connect request. if (!ws->closed) { // ABORT connection negotiation. - nni_aio_cancel(ws->connaio, NNG_ECLOSED); - nni_aio_cancel(ws->httpaio, NNG_ECLOSED); + nni_aio_abort(ws->connaio, NNG_ECLOSED); + nni_aio_abort(ws->httpaio, NNG_ECLOSED); ws_send_close(ws, code); } @@ -484,6 +484,8 @@ ws_start_write(nni_ws *ws) { ws_frame *frame; ws_msg * wm; + nni_iov iov[2]; + int niov; if ((ws->txframe != NULL) || (!ws->ready)) { return; // busy @@ -498,21 +500,23 @@ ws_start_write(nni_ws *ws) NNI_ASSERT(frame != NULL); // Push it out. - ws->txframe = frame; - ws->txaio->a_niov = frame->len > 0 ? 2 : 1; - ws->txaio->a_iov[0].iov_len = frame->hlen; - ws->txaio->a_iov[0].iov_buf = frame->head; + ws->txframe = frame; + niov = 1; + iov[0].iov_len = frame->hlen; + iov[0].iov_buf = frame->head; if (frame->len > 0) { - ws->txaio->a_iov[1].iov_len = frame->len; - ws->txaio->a_iov[1].iov_buf = frame->buf; + niov++; + iov[1].iov_len = frame->len; + iov[1].iov_buf = frame->buf; } + nni_aio_set_iov(ws->txaio, niov, iov); nni_http_write_full(ws->http, ws->txaio); } static void ws_cancel_close(nni_aio *aio, int rv) { - nni_ws *ws = aio->a_prov_data; + nni_ws *ws = nni_aio_get_prov_data(aio); nni_mtx_lock(&ws->mtx); if (ws->wclose) { ws->wclose = false; @@ -567,7 +571,7 @@ ws_write_cb(void *arg) } ws->closed = true; - nni_http_close(ws->http); + nni_http_conn_close(ws->http); nni_mtx_unlock(&ws->mtx); return; } @@ -598,11 +602,11 @@ ws_write_cancel(nni_aio *aio, int rv) // Is this aio active? We can tell by looking at the // active tx frame. - wm = aio->a_prov_data; + wm = nni_aio_get_prov_data(aio); ws = wm->ws; nni_mtx_lock(&ws->mtx); if (((frame = ws->txframe) != NULL) && (frame->wmsg == wm)) { - nni_aio_cancel(ws->txaio, rv); + nni_aio_abort(ws->txaio, rv); // We will wait for callback on the txaio to finish aio. } else if (nni_list_active(&ws->txmsgs, wm)) { // If scheduled, just need to remove node and complete it. @@ -731,6 +735,7 @@ ws_start_read(nni_ws *ws) ws_frame *frame; ws_msg * wm; nni_aio * aio; + nni_iov iov; if ((ws->rxframe != NULL) || ws->closed) { return; // already reading or closed @@ -755,10 +760,10 @@ ws_start_read(nni_ws *ws) frame->len = 0; ws->rxframe = frame; - aio = ws->rxaio; - aio->a_niov = 1; - aio->a_iov[0].iov_len = 2; // We want the first two bytes. - aio->a_iov[0].iov_buf = frame->head; + aio = ws->rxaio; + iov.iov_len = 2; // We want the first two bytes. + iov.iov_buf = frame->head; + nni_aio_set_iov(aio, 1, &iov); nni_http_read_full(ws->http, aio); } @@ -891,9 +896,10 @@ ws_read_cb(void *arg) // If we didn't read the full header yet, then read // the rest of it. if (frame->hlen != 2) { - aio->a_niov = 1; - aio->a_iov[0].iov_buf = frame->head + 2; - aio->a_iov[0].iov_len = frame->hlen - 2; + nni_iov iov; + iov.iov_buf = frame->head + 2; + iov.iov_len = frame->hlen - 2; + nni_aio_set_iov(aio, 1, &iov); nni_http_read_full(ws->http, aio); nni_mtx_unlock(&ws->mtx); return; @@ -954,6 +960,8 @@ ws_read_cb(void *arg) // If we expected data, then ask for it. if (frame->len != 0) { + nni_iov iov; + // Short frames can avoid an alloc if (frame->len < 126) { frame->buf = frame->sdata; @@ -968,9 +976,9 @@ ws_read_cb(void *arg) frame->bufsz = frame->len; } - aio->a_niov = 1; - aio->a_iov[0].iov_buf = frame->buf; - aio->a_iov[0].iov_len = frame->len; + iov.iov_buf = frame->buf; + iov.iov_len = frame->len; + nni_aio_set_iov(aio, 1, &iov); nni_http_read_full(ws->http, aio); nni_mtx_unlock(&ws->mtx); return; @@ -988,13 +996,13 @@ ws_read_cb(void *arg) static void ws_read_cancel(nni_aio *aio, int rv) { - ws_msg *wm = aio->a_prov_data; + ws_msg *wm = nni_aio_get_prov_data(aio); nni_ws *ws = wm->ws; nni_mtx_lock(&ws->mtx); if (wm == nni_list_first(&ws->rxmsgs)) { // Cancellation will percolate back up. - nni_aio_cancel(ws->rxaio, rv); + nni_aio_abort(ws->rxaio, rv); } else if (nni_list_active(&ws->rxmsgs, wm)) { nni_list_remove(&ws->rxmsgs, wm); ws_msg_fini(wm); @@ -1124,13 +1132,13 @@ ws_fini(void *arg) nni_mtx_unlock(&ws->mtx); if (ws->http) { - nni_http_fini(ws->http); + nni_http_conn_fini(ws->http); } if (ws->req) { - nni_http_req_fini(ws->req); + nni_http_req_free(ws->req); } if (ws->res) { - nni_http_res_fini(ws->res); + nni_http_res_free(ws->res); } nni_strfree(ws->reqhdrs); @@ -1201,7 +1209,7 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio) // If we have no response structure, then this was completion of the // send of the request. Prepare an empty response, and read it. if (ws->res == NULL) { - if ((rv = nni_http_res_init(&ws->res)) != 0) { + if ((rv = nni_http_res_alloc(&ws->res)) != 0) { goto err; } nni_http_read_res(ws->http, ws->res, ws->httpaio); @@ -1211,17 +1219,17 @@ ws_http_cb_dialer(nni_ws *ws, nni_aio *aio) status = nni_http_res_get_status(ws->res); switch (status) { - case NNI_HTTP_STATUS_SWITCHING: + case NNG_HTTP_STATUS_SWITCHING: break; - case NNI_HTTP_STATUS_FORBIDDEN: - case NNI_HTTP_STATUS_UNAUTHORIZED: + case NNG_HTTP_STATUS_FORBIDDEN: + case NNG_HTTP_STATUS_UNAUTHORIZED: rv = NNG_EPERM; goto err; - case NNI_HTTP_STATUS_NOT_FOUND: - case NNI_HTTP_STATUS_METHOD_NOT_ALLOWED: + case NNG_HTTP_STATUS_NOT_FOUND: + case NNG_HTTP_STATUS_METHOD_NOT_ALLOWED: rv = NNG_ECONNREFUSED; // Treat these as refusals. goto err; - case NNI_HTTP_STATUS_BAD_REQUEST: + case NNG_HTTP_STATUS_BAD_REQUEST: default: // Perhaps we should use NNG_ETRANERR... rv = NNG_EPROTO; @@ -1360,36 +1368,30 @@ ws_handler(nni_aio *aio) { nni_ws_listener * l; nni_ws * ws; - nni_http * http; + nni_http_conn * conn; nni_http_req * req; nni_http_res * res; nni_http_handler *h; - nni_http_ctx * ctx; const char * ptr; const char * proto; uint16_t status; int rv; char key[29]; - req = nni_aio_get_input(aio, 0); - h = nni_aio_get_input(aio, 1); - ctx = nni_aio_get_input(aio, 2); - l = nni_http_handler_get_data(h, 0); - - if ((rv = nni_http_ctx_stream(ctx, &http)) != 0) { - nni_aio_finish_error(aio, rv); - return; - } + req = nni_aio_get_input(aio, 0); + h = nni_aio_get_input(aio, 1); + conn = nni_aio_get_input(aio, 2); + l = nni_http_handler_get_data(h); // Now check the headers, etc. if (strcmp(nni_http_req_get_version(req), "HTTP/1.1") != 0) { - status = NNI_HTTP_STATUS_HTTP_VERSION_NOT_SUPP; + status = NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP; goto err; } if (strcmp(nni_http_req_get_method(req), "GET") != 0) { // HEAD request. We can't really deal with it. - status = NNI_HTTP_STATUS_BAD_REQUEST; + status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } @@ -1399,7 +1401,7 @@ ws_handler(nni_aio *aio) if ((((ptr = GETH("Content-Length")) != NULL) && (atoi(ptr) > 0)) || (((ptr = GETH("Transfer-Encoding")) != NULL) && (nni_strcasestr(ptr, "chunked") != NULL))) { - status = NNI_HTTP_STATUS_PAYLOAD_TOO_LARGE; + status = NNG_HTTP_STATUS_PAYLOAD_TOO_LARGE; goto err; } @@ -1410,13 +1412,13 @@ ws_handler(nni_aio *aio) (!ws_contains_word(ptr, "upgrade")) || ((ptr = GETH("Sec-WebSocket-Version")) == NULL) || (strcmp(ptr, "13") != 0)) { - status = NNI_HTTP_STATUS_BAD_REQUEST; + status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } if (((ptr = GETH("Sec-WebSocket-Key")) == NULL) || (ws_make_accept(ptr, key) != 0)) { - status = NNI_HTTP_STATUS_BAD_REQUEST; + status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } @@ -1427,51 +1429,50 @@ ws_handler(nni_aio *aio) proto = GETH("Sec-WebSocket-Protocol"); if (proto == NULL) { if (l->proto != NULL) { - status = NNI_HTTP_STATUS_BAD_REQUEST; + status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } } else if ((l->proto == NULL) || (!ws_contains_word(l->proto, proto))) { - status = NNI_HTTP_STATUS_BAD_REQUEST; + status = NNG_HTTP_STATUS_BAD_REQUEST; goto err; } - if ((rv = nni_http_res_init(&res)) != 0) { + if ((rv = nni_http_res_alloc(&res)) != 0) { // Give a chance to reply to client. - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; goto err; } - if (nni_http_res_set_status( - res, NNI_HTTP_STATUS_SWITCHING, "Switching Protocols") != 0) { - nni_http_res_fini(res); - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + if (nni_http_res_set_status(res, NNG_HTTP_STATUS_SWITCHING) != 0) { + nni_http_res_free(res); + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; goto err; } if ((SETH("Connection", "Upgrade") != 0) || (SETH("Upgrade", "websocket") != 0) || (SETH("Sec-WebSocket-Accept", key) != 0)) { - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; - nni_http_res_fini(res); + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; + nni_http_res_free(res); goto err; } if ((proto != NULL) && (SETH("Sec-WebSocket-Protocol", proto) != 0)) { - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; - nni_http_res_fini(res); + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; + nni_http_res_free(res); goto err; } if (l->hookfn != NULL) { rv = l->hookfn(l->hookarg, req, res); if (rv != 0) { - nni_http_res_fini(res); + nni_http_res_free(res); nni_aio_finish_error(aio, rv); return; } if (nni_http_res_get_status(res) != - NNI_HTTP_STATUS_SWITCHING) { + NNG_HTTP_STATUS_SWITCHING) { // The hook has decided to give back a different // reply and we are not upgrading anymore. For // example the Origin might not be permitted, or @@ -1479,7 +1480,7 @@ ws_handler(nni_aio *aio) // (Note that the hook can also give back various // other headers, but it would be bad for it to // alter the websocket mandated headers.) - nni_http_req_fini(req); + nni_http_req_free(req); nni_aio_set_output(aio, 0, res); nni_aio_finish(aio, 0, 0); return; @@ -1492,12 +1493,12 @@ ws_handler(nni_aio *aio) // We are good to go, provided we can get the websocket struct, // and send the reply. if ((rv = ws_init(&ws)) != 0) { - nni_http_req_fini(req); - nni_http_res_fini(res); - status = NNI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + nni_http_req_free(req); + nni_http_res_free(res); + status = NNG_HTTP_STATUS_INTERNAL_SERVER_ERROR; goto err; } - ws->http = http; + ws->http = conn; ws->req = req; ws->res = res; ws->mode = NNI_EP_MODE_LISTEN; @@ -1506,14 +1507,14 @@ ws_handler(nni_aio *aio) nni_list_append(&l->reply, ws); nni_aio_set_data(ws->httpaio, 0, l); - nni_http_write_res(http, res, ws->httpaio); - (void) nni_http_hijack(ctx); + nni_http_write_res(conn, res, ws->httpaio); + (void) nni_http_hijack(conn); nni_aio_set_output(aio, 0, NULL); nni_aio_finish(aio, 0, 0); return; err: - if ((rv = nni_http_res_init_error(&res, status)) != 0) { + if ((rv = nni_http_res_alloc_error(&res, status)) != 0) { nni_aio_finish_error(aio, rv); } else { nni_aio_set_output(aio, 0, res); @@ -1588,7 +1589,7 @@ nni_ws_listener_proto(nni_ws_listener *l, const char *proto) static void ws_accept_cancel(nni_aio *aio, int rv) { - nni_ws_listener *l = aio->a_prov_data; + nni_ws_listener *l = nni_aio_get_prov_data(aio); nni_mtx_lock(&l->mtx); if (nni_aio_list_active(aio)) { @@ -1723,7 +1724,7 @@ ws_conn_cb(void *arg) nni_ws_dialer *d; nni_ws * ws; nni_aio * uaio; - nni_http * http; + nni_http_conn *http; nni_http_req * req = NULL; int rv; uint8_t raw[16]; @@ -1757,7 +1758,7 @@ ws_conn_cb(void *arg) nni_aio_set_output(ws->connaio, 0, NULL); if (uaio == NULL) { // This request was canceled for some reason. - nni_http_fini(http); + nni_http_conn_fini(http); nni_mtx_unlock(&ws->mtx); nni_ws_fini(ws); return; @@ -1770,11 +1771,7 @@ ws_conn_cb(void *arg) wskey[24] = '\0'; #define SETH(h, v) nni_http_req_set_header(req, h, v) - if ((rv != 0) || ((rv = nni_http_req_init(&req)) != 0) || - ((rv = nni_http_req_set_uri(req, d->url->u_rawpath)) != 0) || - ((rv = nni_http_req_set_version(req, "HTTP/1.1")) != 0) || - ((rv = nni_http_req_set_method(req, "GET")) != 0) || - ((rv = SETH("Host", d->url->u_host)) != 0) || + if ((rv != 0) || ((rv = nni_http_req_alloc(&req, d->url)) != 0) || ((rv = SETH("Upgrade", "websocket")) != 0) || ((rv = SETH("Connection", "Upgrade")) != 0) || ((rv = SETH("Sec-WebSocket-Key", wskey)) != 0) || @@ -1805,10 +1802,10 @@ err: nni_aio_finish_error(uaio, rv); nni_mtx_unlock(&ws->mtx); if (http != NULL) { - nni_http_fini(http); + nni_http_conn_fini(http); } if (req != NULL) { - nni_http_req_fini(req); + nni_http_req_free(req); } nni_ws_fini(ws); } @@ -1920,12 +1917,12 @@ nni_ws_dialer_proto(nni_ws_dialer *d, const char *proto) static void ws_dial_cancel(nni_aio *aio, int rv) { - nni_ws *ws = aio->a_prov_data; + nni_ws *ws = nni_aio_get_prov_data(aio); nni_mtx_lock(&ws->mtx); if (aio == ws->useraio) { - nni_aio_cancel(ws->connaio, rv); - nni_aio_cancel(ws->httpaio, rv); + nni_aio_abort(ws->connaio, rv); + nni_aio_abort(ws->httpaio, rv); ws->useraio = NULL; nni_aio_finish_error(aio, rv); } diff --git a/src/supplemental/websocket/websocket.h b/src/supplemental/websocket/websocket.h index 2cabb9cc..546f41a9 100644 --- a/src/supplemental/websocket/websocket.h +++ b/src/supplemental/websocket/websocket.h @@ -13,15 +13,11 @@ #include <stdbool.h> -// Pre-defined types for some prototypes. These are from other subsystems. -typedef struct nni_http_req nni_http_req; -typedef struct nni_http_res nni_http_res; - typedef struct nni_ws nni_ws; typedef struct nni_ws_listener nni_ws_listener; typedef struct nni_ws_dialer nni_ws_dialer; -typedef int (*nni_ws_listen_hook)(void *, nni_http_req *, nni_http_res *); +typedef int (*nni_ws_listen_hook)(void *, nng_http_req *, nng_http_res *); // Specify URL as ws://[<host>][:port][/path] // If host is missing, INADDR_ANY is assumed. If port is missing, @@ -34,7 +30,7 @@ extern void nni_ws_listener_fini(nni_ws_listener *); extern void nni_ws_listener_close(nni_ws_listener *); extern int nni_ws_listener_proto(nni_ws_listener *, const char *); extern int nni_ws_listener_listen(nni_ws_listener *); -extern void nni_ws_listener_accept(nni_ws_listener *, nni_aio *); +extern void nni_ws_listener_accept(nni_ws_listener *, nng_aio *); extern void nni_ws_listener_hook( nni_ws_listener *, nni_ws_listen_hook, void *); extern int nni_ws_listener_set_tls(nni_ws_listener *, nng_tls_config *); @@ -45,7 +41,7 @@ extern void nni_ws_dialer_fini(nni_ws_dialer *); extern void nni_ws_dialer_close(nni_ws_dialer *); extern int nni_ws_dialer_proto(nni_ws_dialer *, const char *); extern int nni_ws_dialer_header(nni_ws_dialer *, const char *, const char *); -extern void nni_ws_dialer_dial(nni_ws_dialer *, nni_aio *); +extern void nni_ws_dialer_dial(nni_ws_dialer *, nng_aio *); extern int nni_ws_dialer_set_tls(nni_ws_dialer *, nng_tls_config *); extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **); @@ -54,10 +50,10 @@ extern int nni_ws_dialer_get_tls(nni_ws_dialer *, nng_tls_config **); // not confirm the server's response at the HTTP level. (It can still issue // a websocket close). -extern void nni_ws_send_msg(nni_ws *, nni_aio *); -extern void nni_ws_recv_msg(nni_ws *, nni_aio *); -extern nni_http_res *nni_ws_response(nni_ws *); -extern nni_http_req *nni_ws_request(nni_ws *); +extern void nni_ws_send_msg(nni_ws *, nng_aio *); +extern void nni_ws_recv_msg(nni_ws *, nng_aio *); +extern nng_http_res *nni_ws_response(nni_ws *); +extern nng_http_req *nni_ws_request(nni_ws *); extern int nni_ws_sock_addr(nni_ws *, nni_sockaddr *); extern int nni_ws_peer_addr(nni_ws *, nni_sockaddr *); extern void nni_ws_close(nni_ws *); @@ -69,4 +65,4 @@ extern bool nni_ws_tls_verified(nni_ws *); // The implementation will send periodic PINGs, and respond with PONGs. -#endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H
\ No newline at end of file +#endif // NNG_SUPPLEMENTAL_WEBSOCKET_WEBSOCKET_H diff --git a/src/transport/inproc/inproc.c b/src/transport/inproc/inproc.c index 4cd1c97d..6329a627 100644 --- a/src/transport/inproc/inproc.c +++ b/src/transport/inproc/inproc.c @@ -143,7 +143,7 @@ static void nni_inproc_pipe_send(void *arg, nni_aio *aio) { nni_inproc_pipe *pipe = arg; - nni_msg * msg = aio->a_msg; + nni_msg * msg = nni_aio_get_msg(aio); char * h; size_t l; int rv; @@ -153,7 +153,7 @@ nni_inproc_pipe_send(void *arg, nni_aio *aio) h = nni_msg_header(msg); l = nni_msg_header_len(msg); if ((rv = nni_msg_insert(msg, h, l)) != 0) { - nni_aio_finish(aio, rv, aio->a_count); + nni_aio_finish(aio, rv, nni_aio_count(aio)); return; } nni_msg_header_chop(msg, l); @@ -219,12 +219,12 @@ nni_inproc_ep_fini(void *arg) static void nni_inproc_conn_finish(nni_aio *aio, int rv) { - nni_inproc_ep *ep = aio->a_prov_extra[0]; + nni_inproc_ep *ep = nni_aio_get_prov_data(aio); void * pipe; nni_aio_list_remove(aio); - pipe = aio->a_pipe; - aio->a_pipe = NULL; + pipe = nni_aio_get_pipe(aio); + nni_aio_set_pipe(aio, NULL); if ((ep != NULL) && (ep->mode != NNI_EP_MODE_LISTEN) && nni_list_empty(&ep->aios)) { @@ -298,8 +298,8 @@ nni_inproc_accept_clients(nni_inproc_ep *server) nni_mtx_init(&pair->mx); - pair->pipes[0] = caio->a_pipe; - pair->pipes[1] = saio->a_pipe; + pair->pipes[0] = nni_aio_get_pipe(caio); + pair->pipes[1] = nni_aio_get_pipe(saio); pair->pipes[0]->rq = pair->pipes[1]->wq = pair->q[0]; pair->pipes[1]->rq = pair->pipes[0]->wq = pair->q[1]; pair->pipes[0]->pair = pair->pipes[1]->pair = pair; @@ -324,15 +324,15 @@ nni_inproc_accept_clients(nni_inproc_ep *server) static void nni_inproc_ep_cancel(nni_aio *aio, int rv) { - nni_inproc_ep * ep = aio->a_prov_data; + nni_inproc_ep * ep = nni_aio_get_prov_data(aio); nni_inproc_pipe *pipe; nni_mtx_lock(&nni_inproc.mx); if (nni_aio_list_active(aio)) { nni_aio_list_remove(aio); nni_list_node_remove(&ep->node); - if ((pipe = aio->a_pipe) != NULL) { - aio->a_pipe = NULL; + if ((pipe = nni_aio_get_pipe(aio)) != NULL) { + nni_aio_set_pipe(aio, NULL); nni_inproc_pipe_fini(pipe); } nni_aio_finish_error(aio, rv); @@ -343,9 +343,10 @@ nni_inproc_ep_cancel(nni_aio *aio, int rv) static void nni_inproc_ep_connect(void *arg, nni_aio *aio) { - nni_inproc_ep *ep = arg; - nni_inproc_ep *server; - int rv; + nni_inproc_ep * ep = arg; + nni_inproc_ep * server; + int rv; + nni_inproc_pipe *pipe; if (ep->mode != NNI_EP_MODE_DIAL) { nni_aio_finish_error(aio, NNG_EINVAL); @@ -358,12 +359,12 @@ nni_inproc_ep_connect(void *arg, nni_aio *aio) return; } - aio->a_prov_extra[0] = ep; - if ((rv = nni_inproc_pipe_init((void *) &aio->a_pipe, ep)) != 0) { + if ((rv = nni_inproc_pipe_init(&pipe, ep)) != 0) { nni_aio_finish_error(aio, rv); nni_mtx_unlock(&nni_inproc.mx); return; } + nni_aio_set_pipe(aio, pipe); // Find a server. NNI_LIST_FOREACH (&nni_inproc.servers, server) { @@ -406,8 +407,9 @@ nni_inproc_ep_bind(void *arg) static void nni_inproc_ep_accept(void *arg, nni_aio *aio) { - nni_inproc_ep *ep = arg; - int rv; + nni_inproc_ep * ep = arg; + nni_inproc_pipe *pipe; + int rv; nni_mtx_lock(&nni_inproc.mx); @@ -416,15 +418,14 @@ nni_inproc_ep_accept(void *arg, nni_aio *aio) return; } - aio->a_prov_extra[0] = ep; - // We are already on the master list of servers, thanks to bind. - if ((rv = nni_inproc_pipe_init((void *) &aio->a_pipe, ep)) != 0) { + if ((rv = nni_inproc_pipe_init(&pipe, ep)) != 0) { nni_aio_finish_error(aio, rv); nni_mtx_unlock(&nni_inproc.mx); return; } + nni_aio_set_pipe(aio, pipe); // Insert us into the pending server aios, and then run the // accept list. diff --git a/src/transport/ipc/ipc.c b/src/transport/ipc/ipc.c index 9e8a3829..6475e43b 100644 --- a/src/transport/ipc/ipc.c +++ b/src/transport/ipc/ipc.c @@ -28,7 +28,7 @@ struct nni_ipc_pipe { uint16_t peer; uint16_t proto; size_t rcvmax; - nng_sockaddr sa; + nni_sockaddr sa; uint8_t txhead[1 + sizeof(uint64_t)]; uint8_t rxhead[1 + sizeof(uint64_t)]; @@ -133,7 +133,7 @@ nni_ipc_pipe_init(nni_ipc_pipe **pipep, nni_ipc_ep *ep, void *ipp) static void nni_ipc_cancel_start(nni_aio *aio, int rv) { - nni_ipc_pipe *pipe = aio->a_prov_data; + nni_ipc_pipe *pipe = nni_aio_get_prov_data(aio); nni_mtx_lock(&pipe->mtx); if (pipe->user_negaio != aio) { @@ -143,7 +143,7 @@ nni_ipc_cancel_start(nni_aio *aio, int rv) pipe->user_negaio = NULL; nni_mtx_unlock(&pipe->mtx); - nni_aio_cancel(pipe->negaio, rv); + nni_aio_abort(pipe->negaio, rv); nni_aio_finish_error(aio, rv); } @@ -167,18 +167,20 @@ nni_ipc_pipe_nego_cb(void *arg) } if (pipe->gottxhead < pipe->wanttxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = pipe->wanttxhead - pipe->gottxhead; - aio->a_iov[0].iov_buf = &pipe->txhead[pipe->gottxhead]; + nni_iov iov; + iov.iov_len = pipe->wanttxhead - pipe->gottxhead; + iov.iov_buf = &pipe->txhead[pipe->gottxhead]; + nni_aio_set_iov(aio, 1, &iov); // send it down... nni_plat_ipc_pipe_send(pipe->ipp, aio); nni_mtx_unlock(&pipe->mtx); return; } if (pipe->gotrxhead < pipe->wantrxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = pipe->wantrxhead - pipe->gotrxhead; - aio->a_iov[0].iov_buf = &pipe->rxhead[pipe->gotrxhead]; + nni_iov iov; + iov.iov_len = pipe->wantrxhead - pipe->gotrxhead; + iov.iov_buf = &pipe->rxhead[pipe->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); nni_plat_ipc_pipe_recv(pipe->ipp, aio); nni_mtx_unlock(&pipe->mtx); return; @@ -229,20 +231,8 @@ nni_ipc_pipe_send_cb(void *arg) } n = nni_aio_count(txaio); - while (n) { - NNI_ASSERT(txaio->a_niov != 0); - if (txaio->a_iov[0].iov_len > n) { - txaio->a_iov[0].iov_len -= n; - NNI_INCPTR(txaio->a_iov[0].iov_buf, n); - break; - } - n -= txaio->a_iov[0].iov_len; - for (int i = 0; i < txaio->a_niov; i++) { - txaio->a_iov[i] = txaio->a_iov[i + 1]; - } - txaio->a_niov--; - } - if ((txaio->a_niov != 0) && (txaio->a_iov[0].iov_len != 0)) { + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) != 0) { nni_plat_ipc_pipe_send(pipe->ipp, txaio); nni_mtx_unlock(&pipe->mtx); return; @@ -281,22 +271,9 @@ nni_ipc_pipe_recv_cb(void *arg) } n = nni_aio_count(rxaio); - while (n) { - NNI_ASSERT(rxaio->a_niov != 0); - if (rxaio->a_iov[0].iov_len > n) { - rxaio->a_iov[0].iov_len -= n; - NNI_INCPTR(rxaio->a_iov[0].iov_buf, n); - break; - } - n -= rxaio->a_iov[0].iov_len; - for (int i = 0; i < rxaio->a_niov; i++) { - rxaio->a_iov[i] = rxaio->a_iov[i + 1]; - } - rxaio->a_niov--; - } - - // Was this a partial read? If so then resubmit for the rest. - if ((rxaio->a_niov != 0) && (rxaio->a_iov[0].iov_len != 0)) { + nni_aio_iov_advance(rxaio, n); + if (nni_aio_iov_count(rxaio) != 0) { + // Was this a partial read? If so then resubmit for the rest. nni_plat_ipc_pipe_recv(pipe->ipp, rxaio); nni_mtx_unlock(&pipe->mtx); return; @@ -329,17 +306,17 @@ nni_ipc_pipe_recv_cb(void *arg) // lock for the read side in the future, so that we allow // transmits to proceed normally. In practice this is // unlikely to be much of an issue though. - if ((rv = nng_msg_alloc(&pipe->rxmsg, (size_t) len)) != 0) { + if ((rv = nni_msg_alloc(&pipe->rxmsg, (size_t) len)) != 0) { goto recv_error; } if (len != 0) { + nni_iov iov; // Submit the rest of the data for a read -- we want to // read the entire message now. - rxaio->a_iov[0].iov_buf = nni_msg_body(pipe->rxmsg); - rxaio->a_iov[0].iov_len = (size_t) len; - rxaio->a_niov = 1; - + iov.iov_buf = nni_msg_body(pipe->rxmsg); + iov.iov_len = (size_t) len; + nni_aio_set_iov(rxaio, 1, &iov); nni_plat_ipc_pipe_recv(pipe->ipp, rxaio); nni_mtx_unlock(&pipe->mtx); return; @@ -368,7 +345,7 @@ recv_error: static void nni_ipc_cancel_tx(nni_aio *aio, int rv) { - nni_ipc_pipe *pipe = aio->a_prov_data; + nni_ipc_pipe *pipe = nni_aio_get_prov_data(aio); nni_mtx_lock(&pipe->mtx); if (pipe->user_txaio != aio) { @@ -378,7 +355,7 @@ nni_ipc_cancel_tx(nni_aio *aio, int rv) pipe->user_txaio = NULL; nni_mtx_unlock(&pipe->mtx); - nni_aio_cancel(pipe->txaio, rv); + nni_aio_abort(pipe->txaio, rv); nni_aio_finish_error(aio, rv); } @@ -390,6 +367,7 @@ nni_ipc_pipe_send(void *arg, nni_aio *aio) uint64_t len; nni_aio * txaio; int niov; + nni_iov iov[3]; len = nni_msg_len(msg) + nni_msg_header_len(msg); @@ -404,22 +382,22 @@ nni_ipc_pipe_send(void *arg, nni_aio *aio) pipe->txhead[0] = 1; // message type, 1. NNI_PUT64(pipe->txhead + 1, len); - txaio = pipe->txaio; - niov = 0; - txaio->a_iov[niov].iov_buf = pipe->txhead; - txaio->a_iov[niov].iov_len = sizeof(pipe->txhead); + txaio = pipe->txaio; + niov = 0; + iov[0].iov_buf = pipe->txhead; + iov[0].iov_len = sizeof(pipe->txhead); niov++; if (nni_msg_header_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_header(msg); - txaio->a_iov[niov].iov_len = nni_msg_header_len(msg); + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); niov++; } if (nni_msg_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_body(msg); - txaio->a_iov[niov].iov_len = nni_msg_len(msg); + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); niov++; } - txaio->a_niov = niov; + nni_aio_set_iov(txaio, niov, iov); nni_plat_ipc_pipe_send(pipe->ipp, txaio); nni_mtx_unlock(&pipe->mtx); @@ -428,7 +406,7 @@ nni_ipc_pipe_send(void *arg, nni_aio *aio) static void nni_ipc_cancel_rx(nni_aio *aio, int rv) { - nni_ipc_pipe *pipe = aio->a_prov_data; + nni_ipc_pipe *pipe = nni_aio_get_prov_data(aio); nni_mtx_lock(&pipe->mtx); if (pipe->user_rxaio != aio) { @@ -438,7 +416,7 @@ nni_ipc_cancel_rx(nni_aio *aio, int rv) pipe->user_rxaio = NULL; nni_mtx_unlock(&pipe->mtx); - nni_aio_cancel(pipe->rxaio, rv); + nni_aio_abort(pipe->rxaio, rv); nni_aio_finish_error(aio, rv); } @@ -447,6 +425,7 @@ nni_ipc_pipe_recv(void *arg, nni_aio *aio) { nni_ipc_pipe *pipe = arg; nni_aio * rxaio; + nni_iov iov; nni_mtx_lock(&pipe->mtx); @@ -459,10 +438,10 @@ nni_ipc_pipe_recv(void *arg, nni_aio *aio) NNI_ASSERT(pipe->rxmsg == NULL); // Schedule a read of the IPC header. - rxaio = pipe->rxaio; - rxaio->a_iov[0].iov_buf = pipe->rxhead; - rxaio->a_iov[0].iov_len = sizeof(pipe->rxhead); - rxaio->a_niov = 1; + rxaio = pipe->rxaio; + iov.iov_buf = pipe->rxhead; + iov.iov_len = sizeof(pipe->rxhead); + nni_aio_set_iov(rxaio, 1, &iov); nni_plat_ipc_pipe_recv(pipe->ipp, rxaio); nni_mtx_unlock(&pipe->mtx); @@ -474,6 +453,7 @@ nni_ipc_pipe_start(void *arg, nni_aio *aio) nni_ipc_pipe *pipe = arg; int rv; nni_aio * negaio; + nni_iov iov; nni_mtx_lock(&pipe->mtx); pipe->txhead[0] = 0; @@ -483,15 +463,15 @@ nni_ipc_pipe_start(void *arg, nni_aio *aio) NNI_PUT16(&pipe->txhead[4], pipe->proto); NNI_PUT16(&pipe->txhead[6], 0); - pipe->user_negaio = aio; - pipe->gotrxhead = 0; - pipe->gottxhead = 0; - pipe->wantrxhead = 8; - pipe->wanttxhead = 8; - negaio = pipe->negaio; - negaio->a_niov = 1; - negaio->a_iov[0].iov_len = 8; - negaio->a_iov[0].iov_buf = &pipe->txhead[0]; + pipe->user_negaio = aio; + pipe->gotrxhead = 0; + pipe->gottxhead = 0; + pipe->wantrxhead = 8; + pipe->wanttxhead = 8; + negaio = pipe->negaio; + iov.iov_len = 8; + iov.iov_buf = &pipe->txhead[0]; + nni_aio_set_iov(negaio, 1, &iov); rv = nni_aio_start(aio, nni_ipc_cancel_start, pipe); if (rv != 0) { nni_mtx_unlock(&pipe->mtx); @@ -638,7 +618,7 @@ nni_ipc_ep_cb(void *arg) static void nni_ipc_cancel_ep(nni_aio *aio, int rv) { - nni_ipc_ep *ep = aio->a_prov_data; + nni_ipc_ep *ep = nni_aio_get_prov_data(aio); NNI_ASSERT(rv != 0); nni_mtx_lock(&ep->mtx); @@ -649,7 +629,7 @@ nni_ipc_cancel_ep(nni_aio *aio, int rv) ep->user_aio = NULL; nni_mtx_unlock(&ep->mtx); - nni_aio_cancel(ep->aio, rv); + nni_aio_abort(ep->aio, rv); nni_aio_finish_error(aio, rv); } diff --git a/src/transport/tcp/tcp.c b/src/transport/tcp/tcp.c index 28ec9438..1504d0ee 100644 --- a/src/transport/tcp/tcp.c +++ b/src/transport/tcp/tcp.c @@ -130,7 +130,7 @@ nni_tcp_pipe_init(nni_tcp_pipe **pipep, nni_tcp_ep *ep, void *tpp) static void nni_tcp_cancel_nego(nni_aio *aio, int rv) { - nni_tcp_pipe *p = aio->a_prov_data; + nni_tcp_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_negaio != aio) { @@ -140,7 +140,7 @@ nni_tcp_cancel_nego(nni_aio *aio, int rv) p->user_negaio = NULL; nni_mtx_unlock(&p->mtx); - nni_aio_cancel(p->negaio, rv); + nni_aio_abort(p->negaio, rv); nni_aio_finish_error(aio, rv); } @@ -164,18 +164,20 @@ nni_tcp_pipe_nego_cb(void *arg) } if (p->gottxhead < p->wanttxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = p->wanttxhead - p->gottxhead; - aio->a_iov[0].iov_buf = &p->txlen[p->gottxhead]; + nni_iov iov; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; // send it down... + nni_aio_set_iov(aio, 1, &iov); nni_plat_tcp_pipe_send(p->tpp, aio); nni_mtx_unlock(&p->mtx); return; } if (p->gotrxhead < p->wantrxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = p->wantrxhead - p->gotrxhead; - aio->a_iov[0].iov_buf = &p->rxlen[p->gotrxhead]; + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); nni_plat_tcp_pipe_recv(p->tpp, aio); nni_mtx_unlock(&p->mtx); return; @@ -206,7 +208,7 @@ nni_tcp_pipe_send_cb(void *arg) int rv; nni_aio * aio; size_t n; - nng_msg * msg; + nni_msg * msg; nni_aio * txaio = p->txaio; nni_mtx_lock(&p->mtx); @@ -226,20 +228,8 @@ nni_tcp_pipe_send_cb(void *arg) } n = nni_aio_count(txaio); - while (n) { - NNI_ASSERT(txaio->a_niov != 0); - if (txaio->a_iov[0].iov_len > n) { - txaio->a_iov[0].iov_len -= n; - NNI_INCPTR(txaio->a_iov[0].iov_buf, n); - break; - } - n -= txaio->a_iov[0].iov_len; - for (int i = 0; i < txaio->a_niov; i++) { - txaio->a_iov[i] = txaio->a_iov[i + 1]; - } - txaio->a_niov--; - } - if ((txaio->a_niov != 0) && (txaio->a_iov[0].iov_len != 0)) { + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) > 0) { nni_plat_tcp_pipe_send(p->tpp, txaio); nni_mtx_unlock(&p->mtx); return; @@ -261,7 +251,7 @@ nni_tcp_pipe_recv_cb(void *arg) int rv; size_t n; nni_msg * msg; - nni_aio * rxaio = p->rxaio; + nni_aio * rxaio; nni_mtx_lock(&p->mtx); @@ -271,26 +261,15 @@ nni_tcp_pipe_recv_cb(void *arg) return; } - if ((rv = nni_aio_result(p->rxaio)) != 0) { + rxaio = p->rxaio; + + if ((rv = nni_aio_result(rxaio)) != 0) { goto recv_error; } - n = nni_aio_count(p->rxaio); - while (n) { - NNI_ASSERT(rxaio->a_niov != 0); - if (rxaio->a_iov[0].iov_len > n) { - rxaio->a_iov[0].iov_len -= n; - NNI_INCPTR(rxaio->a_iov[0].iov_buf, n); - break; - } - n -= rxaio->a_iov[0].iov_len; - rxaio->a_niov--; - for (int i = 0; i < rxaio->a_niov; i++) { - rxaio->a_iov[i] = rxaio->a_iov[i + 1]; - } - } - // Was this a partial read? If so then resubmit for the rest. - if ((rxaio->a_niov != 0) && (rxaio->a_iov[0].iov_len != 0)) { + n = nni_aio_count(rxaio); + nni_aio_iov_advance(rxaio, n); + if (nni_aio_iov_count(rxaio) > 0) { nni_plat_tcp_pipe_recv(p->tpp, rxaio); nni_mtx_unlock(&p->mtx); return; @@ -311,17 +290,18 @@ nni_tcp_pipe_recv_cb(void *arg) goto recv_error; } - if ((rv = nng_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { goto recv_error; } // Submit the rest of the data for a read -- we want to // read the entire message now. if (len != 0) { - rxaio->a_iov[0].iov_buf = nni_msg_body(p->rxmsg); - rxaio->a_iov[0].iov_len = (size_t) len; - rxaio->a_niov = 1; + nni_iov iov; + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + nni_aio_set_iov(rxaio, 1, &iov); nni_plat_tcp_pipe_recv(p->tpp, rxaio); nni_mtx_unlock(&p->mtx); return; @@ -348,7 +328,7 @@ recv_error: static void nni_tcp_cancel_tx(nni_aio *aio, int rv) { - nni_tcp_pipe *p = aio->a_prov_data; + nni_tcp_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_txaio != aio) { @@ -359,7 +339,7 @@ nni_tcp_cancel_tx(nni_aio *aio, int rv) nni_mtx_unlock(&p->mtx); // cancel the underlying operation. - nni_aio_cancel(p->txaio, rv); + nni_aio_abort(p->txaio, rv); nni_aio_finish_error(aio, rv); } @@ -371,6 +351,7 @@ nni_tcp_pipe_send(void *arg, nni_aio *aio) uint64_t len; nni_aio * txaio; int niov; + nni_iov iov[3]; len = nni_msg_len(msg) + nni_msg_header_len(msg); @@ -385,22 +366,22 @@ nni_tcp_pipe_send(void *arg, nni_aio *aio) NNI_PUT64(p->txlen, len); - niov = 0; - txaio = p->txaio; - txaio->a_iov[niov].iov_buf = p->txlen; - txaio->a_iov[niov].iov_len = sizeof(p->txlen); + niov = 0; + txaio = p->txaio; + iov[niov].iov_buf = p->txlen; + iov[niov].iov_len = sizeof(p->txlen); niov++; if (nni_msg_header_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_header(msg); - txaio->a_iov[niov].iov_len = nni_msg_header_len(msg); + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); niov++; } if (nni_msg_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_body(msg); - txaio->a_iov[niov].iov_len = nni_msg_len(msg); + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); niov++; } - txaio->a_niov = niov; + nni_aio_set_iov(txaio, niov, iov); nni_plat_tcp_pipe_send(p->tpp, txaio); nni_mtx_unlock(&p->mtx); @@ -409,7 +390,7 @@ nni_tcp_pipe_send(void *arg, nni_aio *aio) static void nni_tcp_cancel_rx(nni_aio *aio, int rv) { - nni_tcp_pipe *p = aio->a_prov_data; + nni_tcp_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_rxaio != aio) { @@ -420,7 +401,7 @@ nni_tcp_cancel_rx(nni_aio *aio, int rv) nni_mtx_unlock(&p->mtx); // cancel the underlying operation. - nni_aio_cancel(p->rxaio, rv); + nni_aio_abort(p->rxaio, rv); nni_aio_finish_error(aio, rv); } @@ -429,6 +410,7 @@ nni_tcp_pipe_recv(void *arg, nni_aio *aio) { nni_tcp_pipe *p = arg; nni_aio * rxaio; + nni_iov iov; nni_mtx_lock(&p->mtx); @@ -441,10 +423,10 @@ nni_tcp_pipe_recv(void *arg, nni_aio *aio) NNI_ASSERT(p->rxmsg == NULL); // Schedule a read of the TCP header. - rxaio = p->rxaio; - rxaio->a_iov[0].iov_buf = p->rxlen; - rxaio->a_iov[0].iov_len = sizeof(p->rxlen); - rxaio->a_niov = 1; + rxaio = p->rxaio; + iov.iov_buf = p->rxlen; + iov.iov_len = sizeof(p->rxlen); + nni_aio_set_iov(rxaio, 1, &iov); nni_plat_tcp_pipe_recv(p->tpp, rxaio); nni_mtx_unlock(&p->mtx); @@ -463,7 +445,7 @@ nni_tcp_pipe_getopt_locaddr(void *arg, void *v, size_t *szp) { nni_tcp_pipe *p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_plat_tcp_pipe_sockname(p->tpp, &sa)) == 0) { @@ -477,7 +459,7 @@ nni_tcp_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) { nni_tcp_pipe *p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_plat_tcp_pipe_peername(p->tpp, &sa)) == 0) { @@ -492,6 +474,7 @@ nni_tcp_pipe_start(void *arg, nni_aio *aio) { nni_tcp_pipe *p = arg; nni_aio * negaio; + nni_iov iov; nni_mtx_lock(&p->mtx); p->txlen[0] = 0; @@ -501,15 +484,15 @@ nni_tcp_pipe_start(void *arg, nni_aio *aio) NNI_PUT16(&p->txlen[4], p->proto); NNI_PUT16(&p->txlen[6], 0); - p->user_negaio = aio; - p->gotrxhead = 0; - p->gottxhead = 0; - p->wantrxhead = 8; - p->wanttxhead = 8; - negaio = p->negaio; - negaio->a_niov = 1; - negaio->a_iov[0].iov_len = 8; - negaio->a_iov[0].iov_buf = &p->txlen[0]; + p->user_negaio = aio; + p->gotrxhead = 0; + p->gottxhead = 0; + p->wantrxhead = 8; + p->wanttxhead = 8; + negaio = p->negaio; + iov.iov_len = 8; + iov.iov_buf = &p->txlen[0]; + nni_aio_set_iov(negaio, 1, &iov); if (nni_aio_start(aio, nni_tcp_cancel_nego, p) != 0) { nni_mtx_unlock(&p->mtx); return; @@ -572,7 +555,7 @@ nni_tcp_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) if (mode == NNI_EP_MODE_DIAL) { passive = 0; lsa.s_un.s_family = NNG_AF_UNSPEC; - aio->a_addr = &rsa; + nni_aio_set_input(aio, 0, &rsa); if ((host == NULL) || (serv == NULL)) { nni_aio_fini(aio); return (NNG_EADDRINVAL); @@ -580,7 +563,7 @@ nni_tcp_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) } else { passive = 1; rsa.s_un.s_family = NNG_AF_UNSPEC; - aio->a_addr = &lsa; + nni_aio_set_input(aio, 0, &lsa); } nni_plat_tcp_resolv(host, serv, NNG_AF_UNSPEC, passive, aio); @@ -685,7 +668,7 @@ nni_tcp_ep_cb(void *arg) static void nni_tcp_cancel_ep(nni_aio *aio, int rv) { - nni_tcp_ep *ep = aio->a_prov_data; + nni_tcp_ep *ep = nni_aio_get_prov_data(aio); nni_mtx_lock(&ep->mtx); if (ep->user_aio != aio) { @@ -695,7 +678,7 @@ nni_tcp_cancel_ep(nni_aio *aio, int rv) ep->user_aio = NULL; nni_mtx_unlock(&ep->mtx); - nni_aio_cancel(ep->aio, rv); + nni_aio_abort(ep->aio, rv); nni_aio_finish_error(aio, rv); } diff --git a/src/transport/tls/tls.c b/src/transport/tls/tls.c index f6c5bc6e..09c59582 100644 --- a/src/transport/tls/tls.c +++ b/src/transport/tls/tls.c @@ -138,7 +138,7 @@ nni_tls_pipe_init(nni_tls_pipe **pipep, nni_tls_ep *ep, void *tpp) static void nni_tls_cancel_nego(nni_aio *aio, int rv) { - nni_tls_pipe *p = aio->a_prov_data; + nni_tls_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_negaio != aio) { @@ -148,7 +148,7 @@ nni_tls_cancel_nego(nni_aio *aio, int rv) p->user_negaio = NULL; nni_mtx_unlock(&p->mtx); - nni_aio_cancel(p->negaio, rv); + nni_aio_abort(p->negaio, rv); nni_aio_finish_error(aio, rv); } @@ -172,18 +172,20 @@ nni_tls_pipe_nego_cb(void *arg) } if (p->gottxhead < p->wanttxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = p->wanttxhead - p->gottxhead; - aio->a_iov[0].iov_buf = &p->txlen[p->gottxhead]; + nni_iov iov; + iov.iov_len = p->wanttxhead - p->gottxhead; + iov.iov_buf = &p->txlen[p->gottxhead]; + nni_aio_set_iov(aio, 1, &iov); // send it down... nni_tls_send(p->tls, aio); nni_mtx_unlock(&p->mtx); return; } if (p->gotrxhead < p->wantrxhead) { - aio->a_niov = 1; - aio->a_iov[0].iov_len = p->wantrxhead - p->gotrxhead; - aio->a_iov[0].iov_buf = &p->rxlen[p->gotrxhead]; + nni_iov iov; + iov.iov_len = p->wantrxhead - p->gotrxhead; + iov.iov_buf = &p->rxlen[p->gotrxhead]; + nni_aio_set_iov(aio, 1, &iov); nni_tls_recv(p->tls, aio); nni_mtx_unlock(&p->mtx); return; @@ -234,20 +236,8 @@ nni_tls_pipe_send_cb(void *arg) } n = nni_aio_count(txaio); - while (n) { - NNI_ASSERT(txaio->a_niov != 0); - if (txaio->a_iov[0].iov_len > n) { - txaio->a_iov[0].iov_len -= n; - NNI_INCPTR(txaio->a_iov[0].iov_buf, n); - break; - } - n -= txaio->a_iov[0].iov_len; - for (int i = 0; i < txaio->a_niov; i++) { - txaio->a_iov[i] = txaio->a_iov[i + 1]; - } - txaio->a_niov--; - } - if ((txaio->a_niov != 0) && (txaio->a_iov[0].iov_len != 0)) { + nni_aio_iov_advance(txaio, n); + if (nni_aio_iov_count(txaio) > 0) { nni_tls_send(p->tls, txaio); nni_mtx_unlock(&p->mtx); return; @@ -269,7 +259,7 @@ nni_tls_pipe_recv_cb(void *arg) int rv; size_t n; nni_msg * msg; - nni_aio * rxaio = p->rxaio; + nni_aio * rxaio; nni_mtx_lock(&p->mtx); @@ -279,26 +269,16 @@ nni_tls_pipe_recv_cb(void *arg) return; } + rxaio = p->rxaio; + if ((rv = nni_aio_result(p->rxaio)) != 0) { goto recv_error; } - n = nni_aio_count(p->rxaio); - while (n) { - NNI_ASSERT(rxaio->a_niov != 0); - if (rxaio->a_iov[0].iov_len > n) { - rxaio->a_iov[0].iov_len -= n; - NNI_INCPTR(rxaio->a_iov[0].iov_buf, n); - break; - } - n -= rxaio->a_iov[0].iov_len; - rxaio->a_niov--; - for (int i = 0; i < rxaio->a_niov; i++) { - rxaio->a_iov[i] = rxaio->a_iov[i + 1]; - } - } - // Was this a partial read? If so then resubmit for the rest. - if ((rxaio->a_niov != 0) && (rxaio->a_iov[0].iov_len != 0)) { + n = nni_aio_count(rxaio); + nni_aio_iov_advance(rxaio, n); + if (nni_aio_iov_count(rxaio) > 0) { + // Was this a partial read? If so then resubmit for the rest. nni_tls_recv(p->tls, rxaio); nni_mtx_unlock(&p->mtx); return; @@ -319,16 +299,17 @@ nni_tls_pipe_recv_cb(void *arg) goto recv_error; } - if ((rv = nng_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { + if ((rv = nni_msg_alloc(&p->rxmsg, (size_t) len)) != 0) { goto recv_error; } // Submit the rest of the data for a read -- we want to // read the entire message now. if (len != 0) { - rxaio->a_iov[0].iov_buf = nni_msg_body(p->rxmsg); - rxaio->a_iov[0].iov_len = (size_t) len; - rxaio->a_niov = 1; + nni_iov iov; + iov.iov_buf = nni_msg_body(p->rxmsg); + iov.iov_len = (size_t) len; + nni_aio_set_iov(rxaio, 1, &iov); nni_tls_recv(p->tls, rxaio); nni_mtx_unlock(&p->mtx); @@ -356,7 +337,7 @@ recv_error: static void nni_tls_cancel_tx(nni_aio *aio, int rv) { - nni_tls_pipe *p = aio->a_prov_data; + nni_tls_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_txaio != aio) { @@ -367,7 +348,7 @@ nni_tls_cancel_tx(nni_aio *aio, int rv) nni_mtx_unlock(&p->mtx); // cancel the underlying operation. - nni_aio_cancel(p->txaio, rv); + nni_aio_abort(p->txaio, rv); nni_aio_finish_error(aio, rv); } @@ -379,6 +360,7 @@ nni_tls_pipe_send(void *arg, nni_aio *aio) uint64_t len; nni_aio * txaio; int niov; + nni_iov iov[3]; len = nni_msg_len(msg) + nni_msg_header_len(msg); @@ -393,23 +375,23 @@ nni_tls_pipe_send(void *arg, nni_aio *aio) NNI_PUT64(p->txlen, len); - niov = 0; - txaio = p->txaio; - txaio->a_iov[niov].iov_buf = p->txlen; - txaio->a_iov[niov].iov_len = sizeof(p->txlen); + niov = 0; + txaio = p->txaio; + iov[niov].iov_buf = p->txlen; + iov[niov].iov_len = sizeof(p->txlen); niov++; if (nni_msg_header_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_header(msg); - txaio->a_iov[niov].iov_len = nni_msg_header_len(msg); + iov[niov].iov_buf = nni_msg_header(msg); + iov[niov].iov_len = nni_msg_header_len(msg); niov++; } if (nni_msg_len(msg) > 0) { - txaio->a_iov[niov].iov_buf = nni_msg_body(msg); - txaio->a_iov[niov].iov_len = nni_msg_len(msg); + iov[niov].iov_buf = nni_msg_body(msg); + iov[niov].iov_len = nni_msg_len(msg); niov++; } - txaio->a_niov = niov; + nni_aio_set_iov(txaio, niov, iov); nni_tls_send(p->tls, txaio); nni_mtx_unlock(&p->mtx); } @@ -417,7 +399,7 @@ nni_tls_pipe_send(void *arg, nni_aio *aio) static void nni_tls_cancel_rx(nni_aio *aio, int rv) { - nni_tls_pipe *p = aio->a_prov_data; + nni_tls_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_rxaio != aio) { @@ -428,7 +410,7 @@ nni_tls_cancel_rx(nni_aio *aio, int rv) nni_mtx_unlock(&p->mtx); // cancel the underlying operation. - nni_aio_cancel(p->rxaio, rv); + nni_aio_abort(p->rxaio, rv); nni_aio_finish_error(aio, rv); } @@ -437,6 +419,7 @@ nni_tls_pipe_recv(void *arg, nni_aio *aio) { nni_tls_pipe *p = arg; nni_aio * rxaio; + nni_iov iov; nni_mtx_lock(&p->mtx); @@ -449,10 +432,11 @@ nni_tls_pipe_recv(void *arg, nni_aio *aio) NNI_ASSERT(p->rxmsg == NULL); // Schedule a read of the TCP header. - rxaio = p->rxaio; - rxaio->a_iov[0].iov_buf = p->rxlen; - rxaio->a_iov[0].iov_len = sizeof(p->rxlen); - rxaio->a_niov = 1; + rxaio = p->rxaio; + + iov.iov_buf = p->rxlen; + iov.iov_len = sizeof(p->rxlen); + nni_aio_set_iov(rxaio, 1, &iov); nni_tls_recv(p->tls, rxaio); nni_mtx_unlock(&p->mtx); @@ -471,7 +455,7 @@ nni_tls_pipe_getopt_locaddr(void *arg, void *v, size_t *szp) { nni_tls_pipe *p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_tls_sockname(p->tls, &sa)) == 0) { @@ -485,7 +469,7 @@ nni_tls_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) { nni_tls_pipe *p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_tls_peername(p->tls, &sa)) == 0) { @@ -499,6 +483,7 @@ nni_tls_pipe_start(void *arg, nni_aio *aio) { nni_tls_pipe *p = arg; nni_aio * negaio; + nni_iov iov; nni_mtx_lock(&p->mtx); p->txlen[0] = 0; @@ -508,15 +493,15 @@ nni_tls_pipe_start(void *arg, nni_aio *aio) NNI_PUT16(&p->txlen[4], p->proto); NNI_PUT16(&p->txlen[6], 0); - p->user_negaio = aio; - p->gotrxhead = 0; - p->gottxhead = 0; - p->wantrxhead = 8; - p->wanttxhead = 8; - negaio = p->negaio; - negaio->a_niov = 1; - negaio->a_iov[0].iov_len = 8; - negaio->a_iov[0].iov_buf = &p->txlen[0]; + p->user_negaio = aio; + p->gotrxhead = 0; + p->gottxhead = 0; + p->wantrxhead = 8; + p->wanttxhead = 8; + negaio = p->negaio; + iov.iov_len = 8; + iov.iov_buf = &p->txlen[0]; + nni_aio_set_iov(negaio, 1, &iov); if (nni_aio_start(aio, nni_tls_cancel_nego, p) != 0) { nni_mtx_unlock(&p->mtx); return; @@ -584,7 +569,7 @@ nni_tls_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) tlsmode = NNG_TLS_MODE_CLIENT; authmode = NNG_TLS_AUTH_MODE_REQUIRED; lsa.s_un.s_family = NNG_AF_UNSPEC; - aio->a_addr = &rsa; + nni_aio_set_input(aio, 0, &rsa); if ((host == NULL) || (serv == NULL)) { nni_aio_fini(aio); return (NNG_EADDRINVAL); @@ -594,7 +579,7 @@ nni_tls_ep_init(void **epp, nni_url *url, nni_sock *sock, int mode) tlsmode = NNG_TLS_MODE_SERVER; authmode = NNG_TLS_AUTH_MODE_NONE; rsa.s_un.s_family = NNG_AF_UNSPEC; - aio->a_addr = &lsa; + nni_aio_set_input(aio, 0, &lsa); } // XXX: arguably we could defer this part to the point we do a bind @@ -705,7 +690,7 @@ nni_tls_ep_cb(void *arg) static void nni_tls_cancel_ep(nni_aio *aio, int rv) { - nni_tls_ep *ep = aio->a_prov_data; + nni_tls_ep *ep = nni_aio_get_prov_data(aio); nni_mtx_lock(&ep->mtx); if (ep->user_aio != aio) { @@ -715,7 +700,7 @@ nni_tls_cancel_ep(nni_aio *aio, int rv) ep->user_aio = NULL; nni_mtx_unlock(&ep->mtx); - nni_aio_cancel(ep->aio, rv); + nni_aio_abort(ep->aio, rv); nni_aio_finish_error(aio, rv); } diff --git a/src/transport/ws/websocket.c b/src/transport/ws/websocket.c index aead6f59..2fe7804c 100644 --- a/src/transport/ws/websocket.c +++ b/src/transport/ws/websocket.c @@ -111,13 +111,13 @@ ws_pipe_recv_cb(void *arg) static void ws_pipe_recv_cancel(nni_aio *aio, int rv) { - ws_pipe *p = aio->a_prov_data; + ws_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_rxaio != aio) { nni_mtx_unlock(&p->mtx); return; } - nni_aio_cancel(p->rxaio, rv); + nni_aio_abort(p->rxaio, rv); p->user_rxaio = NULL; nni_aio_finish_error(aio, rv); nni_mtx_unlock(&p->mtx); @@ -142,14 +142,14 @@ ws_pipe_recv(void *arg, nni_aio *aio) static void ws_pipe_send_cancel(nni_aio *aio, int rv) { - ws_pipe *p = aio->a_prov_data; + ws_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&p->mtx); if (p->user_txaio != aio) { nni_mtx_unlock(&p->mtx); return; } p->user_txaio = NULL; - nni_aio_cancel(p->txaio, rv); + nni_aio_abort(p->txaio, rv); nni_aio_finish_error(aio, rv); nni_mtx_unlock(&p->mtx); } @@ -255,7 +255,7 @@ ws_hook(void *arg, nni_http_req *req, nni_http_res *res) NNI_LIST_FOREACH (&ep->headers, h) { int rv; - rv = nni_http_res_set_header(res, h->name, h->value); + rv = nng_http_res_set_header(res, h->name, h->value); if (rv != 0) { return (rv); } @@ -279,7 +279,7 @@ ws_ep_bind(void *arg) static void ws_ep_cancel(nni_aio *aio, int rv) { - ws_ep *ep = aio->a_prov_data; + ws_ep *ep = nni_aio_get_prov_data(aio); nni_mtx_lock(&ep->mtx); if (nni_aio_list_active(aio)) { @@ -484,7 +484,7 @@ ws_pipe_getopt_locaddr(void *arg, void *v, size_t *szp) { ws_pipe * p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_ws_sock_addr(p->ws, &sa)) == 0) { @@ -498,7 +498,7 @@ ws_pipe_getopt_remaddr(void *arg, void *v, size_t *szp) { ws_pipe * p = arg; int rv; - nng_sockaddr sa; + nni_sockaddr sa; memset(&sa, 0, sizeof(sa)); if ((rv = nni_ws_peer_addr(p->ws, &sa)) == 0) { diff --git a/src/transport/zerotier/zerotier.c b/src/transport/zerotier/zerotier.c index a5ca739c..d6762d25 100644 --- a/src/transport/zerotier/zerotier.c +++ b/src/transport/zerotier/zerotier.c @@ -367,18 +367,19 @@ zt_node_rcv4_cb(void *arg) // XXX: CHECK THIS, if it fails then we have a fatal error with // the znode, and have to shut everything down. ZT_Node_processWirePacket(ztn->zn_znode, NULL, now, 0, (void *) &sa, - ztn->zn_rcv4_buf, aio->a_count, &now); + ztn->zn_rcv4_buf, nni_aio_count(aio), &now); // Schedule background work zt_node_resched(ztn, now); // Schedule another receive. if (ztn->zn_udp4 != NULL) { - aio->a_niov = 1; - aio->a_iov[0].iov_buf = ztn->zn_rcv4_buf; - aio->a_iov[0].iov_len = zt_rcv_bufsize; - aio->a_addr = &ztn->zn_rcv4_addr; - aio->a_count = 0; + nni_iov iov; + iov.iov_buf = ztn->zn_rcv4_buf; + iov.iov_len = zt_rcv_bufsize; + nni_aio_set_iov(aio, 1, &iov); + + nni_aio_set_input(aio, 0, &ztn->zn_rcv4_addr); nni_plat_udp_recv(ztn->zn_udp4, aio); } @@ -416,18 +417,18 @@ zt_node_rcv6_cb(void *arg) // We are not going to perform any validation of the data; we // just pass this straight into the ZeroTier core. ZT_Node_processWirePacket(ztn->zn_znode, NULL, now, 0, (void *) &sa, - ztn->zn_rcv6_buf, aio->a_count, &now); + ztn->zn_rcv6_buf, nni_aio_count(aio), &now); // Schedule background work zt_node_resched(ztn, now); // Schedule another receive. if (ztn->zn_udp6 != NULL) { - aio->a_niov = 1; - aio->a_iov[0].iov_buf = ztn->zn_rcv6_buf; - aio->a_iov[0].iov_len = zt_rcv_bufsize; - aio->a_addr = &ztn->zn_rcv6_addr; - aio->a_count = 0; + nni_iov iov; + iov.iov_buf = ztn->zn_rcv6_buf; + iov.iov_len = zt_rcv_bufsize; + nni_aio_set_iov(aio, 1, &iov); + nni_aio_set_input(aio, 0, &ztn->zn_rcv6_addr); nni_plat_udp_recv(ztn->zn_udp6, aio); } nni_mtx_unlock(&zt_lk); @@ -1309,6 +1310,7 @@ zt_wire_packet_send(ZT_Node *node, void *userptr, void *thr, int64_t socket, uint16_t port; uint8_t * buf; zt_send_hdr * hdr; + nni_iov iov; NNI_ARG_UNUSED(thr); NNI_ARG_UNUSED(socket); @@ -1353,11 +1355,11 @@ zt_wire_packet_send(ZT_Node *node, void *userptr, void *thr, int64_t socket, nni_aio_set_data(aio, 0, hdr); hdr->sa = addr; hdr->len = len; + nni_aio_set_input(aio, 0, &hdr->sa); - aio->a_addr = &hdr->sa; - aio->a_niov = 1; - aio->a_iov[0].iov_buf = buf; - aio->a_iov[0].iov_len = len; + iov.iov_buf = buf; + iov.iov_len = len; + nni_aio_set_iov(aio, 1, &iov); // This should be non-blocking/best-effort, so while // not great that we're holding the lock, also not tragic. @@ -1423,6 +1425,7 @@ zt_node_create(zt_node **ztnp, const char *path) nng_sockaddr sa6; int rv; enum ZT_ResultCode zrv; + nni_iov iov; // We want to bind to any address we can (for now). // Note that at the moment we only support IPv4. Its @@ -1487,16 +1490,14 @@ zt_node_create(zt_node **ztnp, const char *path) zt_node_resched(ztn, 1); // Schedule receive - ztn->zn_rcv4_aio->a_niov = 1; - ztn->zn_rcv4_aio->a_iov[0].iov_buf = ztn->zn_rcv4_buf; - ztn->zn_rcv4_aio->a_iov[0].iov_len = zt_rcv_bufsize; - ztn->zn_rcv4_aio->a_addr = &ztn->zn_rcv4_addr; - ztn->zn_rcv4_aio->a_count = 0; - ztn->zn_rcv6_aio->a_niov = 1; - ztn->zn_rcv6_aio->a_iov[0].iov_buf = ztn->zn_rcv6_buf; - ztn->zn_rcv6_aio->a_iov[0].iov_len = zt_rcv_bufsize; - ztn->zn_rcv6_aio->a_addr = &ztn->zn_rcv6_addr; - ztn->zn_rcv6_aio->a_count = 0; + iov.iov_buf = ztn->zn_rcv4_buf; + iov.iov_len = zt_rcv_bufsize; + nni_aio_set_iov(ztn->zn_rcv4_aio, 1, &iov); + nni_aio_set_input(ztn->zn_rcv4_aio, 0, &ztn->zn_rcv4_addr); + iov.iov_buf = ztn->zn_rcv6_buf; + iov.iov_len = zt_rcv_bufsize; + nni_aio_set_iov(ztn->zn_rcv6_aio, 1, &iov); + nni_aio_set_input(ztn->zn_rcv6_aio, 0, &ztn->zn_rcv6_addr); nni_plat_udp_recv(ztn->zn_udp4, ztn->zn_rcv4_aio); nni_plat_udp_recv(ztn->zn_udp6, ztn->zn_rcv6_aio); @@ -1812,7 +1813,7 @@ zt_pipe_send(void *arg, nni_aio *aio) static void zt_pipe_cancel_recv(nni_aio *aio, int rv) { - zt_pipe *p = aio->a_prov_data; + zt_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&zt_lk); if (p->zp_user_rxaio == aio) { p->zp_user_rxaio = NULL; @@ -1968,7 +1969,7 @@ zt_pipe_get_node(void *arg, void *buf, size_t *szp) static void zt_pipe_cancel_ping(nni_aio *aio, int rv) { - zt_pipe *p = aio->a_prov_data; + zt_pipe *p = nni_aio_get_prov_data(aio); nni_mtx_lock(&zt_lk); if (p->zp_ping_active) { @@ -2195,7 +2196,7 @@ zt_ep_close(void *arg) zt_node *ztn; nni_aio *aio; - nni_aio_cancel(ep->ze_creq_aio, NNG_ECLOSED); + nni_aio_abort(ep->ze_creq_aio, NNG_ECLOSED); // Cancel any outstanding user operation(s) - they should have // been aborted by the above cancellation, but we need to be @@ -2293,12 +2294,12 @@ zt_ep_bind(void *arg) static void zt_ep_cancel(nni_aio *aio, int rv) { - zt_ep *ep = aio->a_prov_data; + zt_ep *ep = nni_aio_get_prov_data(aio); nni_mtx_lock(&zt_lk); if (nni_aio_list_active(aio)) { if (ep->ze_aio != NULL) { - nni_aio_cancel(ep->ze_aio, rv); + nni_aio_abort(ep->ze_aio, rv); } nni_aio_list_remove(aio); nni_aio_finish_error(aio, rv); @@ -2370,7 +2371,7 @@ zt_ep_accept(void *arg, nni_aio *aio) static void zt_ep_conn_req_cancel(nni_aio *aio, int rv) { - zt_ep *ep = aio->a_prov_data; + zt_ep *ep = nni_aio_get_prov_data(aio); // We don't have much to do here. The AIO will have been // canceled as a result of the "parent" AIO canceling. nni_mtx_lock(&zt_lk); diff --git a/tests/aio.c b/tests/aio.c index 0746fa51..fc5d4baf 100644 --- a/tests/aio.c +++ b/tests/aio.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this diff --git a/tests/convey.c b/tests/convey.c index bfe836e4..5e87779f 100644 --- a/tests/convey.c +++ b/tests/convey.c @@ -76,14 +76,13 @@ * a scope not expressed to user code, these rules are relaxed. */ -static const char *convey_sym_pass = "."; -static const char *convey_sym_skip = "?"; -static const char *convey_sym_fail = "X"; -static const char *convey_sym_fatal = "!"; -static const char *convey_nocolor = ""; -static const char *convey_green = ""; -static const char *convey_red = ""; -static const char *convey_yellow = ""; +static const char *convey_sym_pass = "."; +static const char *convey_sym_skip = "?"; +static const char *convey_sym_fail = "X"; +static const char *convey_nocolor = ""; +static const char *convey_green = ""; +static const char *convey_red = ""; +static const char *convey_yellow = ""; static int convey_debug = 0; static int convey_verbose = 0; @@ -866,10 +865,9 @@ convey_init_term(void) (void) setlocale(LC_ALL, ""); codeset = nl_langinfo(CODESET); if ((codeset != NULL) && (strcmp(codeset, "UTF-8") == 0)) { - convey_sym_pass = "✔"; - convey_sym_fail = "✘"; - convey_sym_fatal = "🔥"; - convey_sym_skip = "⚠"; + convey_sym_pass = "✔"; + convey_sym_fail = "✘"; + convey_sym_skip = "⚠"; } term = getenv("TERM"); if (!isatty(fileno(stdin))) { diff --git a/tests/convey.h b/tests/convey.h index 59445059..9d9be0fa 100644 --- a/tests/convey.h +++ b/tests/convey.h @@ -185,7 +185,7 @@ extern void conveyPrintf(const char *, int, const char *, ...); */ #define ConveyTest(name, code) \ do { \ - int convey_rv; \ + int convey_rv = 0; \ conveyRun(name, code, &convey_rv); \ if (convey_rv > convey_main_rv) { \ convey_main_rv = convey_rv; \ diff --git a/tests/httpclient.c b/tests/httpclient.c index f965cf2d..f26674f6 100644 --- a/tests/httpclient.c +++ b/tests/httpclient.c @@ -31,52 +31,46 @@ TestMain("HTTP Client", { Convey("Given a TCP connection to httpbin.org", { nng_aio * aio; - nni_aio * iaio; nni_http_client *cli; - nni_http * http; - nni_url * url; + nng_http_conn * http; + nng_url * url; So(nng_aio_alloc(&aio, NULL, NULL) == 0); - iaio = (nni_aio *) aio; - So(nni_url_parse(&url, "http://httpbin.org") == 0); + So(nng_url_parse(&url, "http://httpbin.org/encoding/utf8") == + 0); So(nni_http_client_init(&cli, url) == 0); - nni_http_client_connect(cli, iaio); + nni_http_client_connect(cli, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - http = nni_aio_get_output(iaio, 0); + http = nni_aio_get_output(aio, 0); Reset({ nni_http_client_fini(cli); - nni_http_fini(http); + nng_http_conn_close(http); nng_aio_free(aio); - nni_url_free(url); + nng_url_free(url); }); Convey("We can initiate a message", { - nni_http_req *req; - nni_http_res *res; + nng_http_req *req; + nng_http_res *res; + So(http != NULL); - So(nni_http_req_init(&req) == 0); - So(nni_http_res_init(&res) == 0); + So(nng_http_req_alloc(&req, url) == 0); + So(nng_http_res_alloc(&res) == 0); Reset({ - nni_http_close(http); - nni_http_req_fini(req); - nni_http_res_fini(res); + nng_http_req_free(req); + nng_http_res_free(res); }); - So(nni_http_req_set_method(req, "GET") == 0); - So(nni_http_req_set_version(req, "HTTP/1.1") == 0); - So(nni_http_req_set_uri(req, "/encoding/utf8") == 0); - So(nni_http_req_set_header( - req, "Host", "httpbin.org") == 0); - nni_http_write_req(http, req, iaio); + nng_http_conn_write_req(http, req, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - nni_http_read_res(http, res, iaio); + nng_http_conn_read_res(http, res, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - So(nni_http_res_get_status(res) == 200); + So(nng_http_res_get_status(res) == 200); Convey("The message contents are correct", { uint8_t digest[20]; @@ -85,7 +79,7 @@ TestMain("HTTP Client", { size_t sz; nng_iov iov; - cstr = nni_http_res_get_header( + cstr = nng_http_res_get_header( res, "Content-Length"); So(cstr != NULL); sz = atoi(cstr); @@ -102,7 +96,7 @@ TestMain("HTTP Client", { nng_aio_wait(aio); So(nng_aio_result(aio) == 0); - nni_http_read_full(http, iaio); + nng_http_conn_read_all(http, aio); nng_aio_wait(aio); So(nng_aio_result(aio) == 0); diff --git a/tests/httpserver.c b/tests/httpserver.c index 062f964a..1008058f 100644 --- a/tests/httpserver.c +++ b/tests/httpserver.c @@ -30,56 +30,43 @@ cleanup(void) } static int -httpget(const char *addr, void **datap, size_t *sizep, uint16_t *statp, - char **ctypep) +httpdo(nng_url *url, nng_http_req *req, nng_http_res *res, void **datap, + size_t *sizep) { int rv; - nni_aio * aio = NULL; - nni_http_client *cli = NULL; - nni_http * h = NULL; - nni_http_req * req = NULL; - nni_http_res * res = NULL; - nni_url * url = NULL; - size_t clen = 0; - void * data = NULL; - char * ctype = NULL; + nng_aio * aio = NULL; + nni_http_client *cli = NULL; + nng_http_conn * h = NULL; + size_t clen = 0; + void * data = NULL; const char * ptr; - if (((rv = nni_url_parse(&url, addr)) != 0) || - ((rv = nni_aio_init(&aio, NULL, NULL)) != 0) || - ((rv = nni_http_req_init(&req)) != 0) || - ((rv = nni_http_res_init(&res)) != 0) || + if (((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) || ((rv = nni_http_client_init(&cli, url)) != 0)) { goto fail; } nni_http_client_connect(cli, aio); - nni_aio_wait(aio); + nng_aio_wait(aio); if ((rv = nni_aio_result(aio)) != 0) { goto fail; } h = nni_aio_get_output(aio, 0); - if (((rv = nni_http_req_set_method(req, "GET")) != 0) || - ((rv = nni_http_req_set_version(req, "HTTP/1.1")) != 0) || - ((rv = nni_http_req_set_uri(req, url->u_path)) != 0) || - ((rv = nni_http_req_set_header(req, "Host", url->u_host)) != 0)) { - goto fail; - } - nni_http_write_req(h, req, aio); - nni_aio_wait(aio); - if ((rv = nni_aio_result(aio)) != 0) { + + nng_http_conn_write_req(h, req, aio); + nng_aio_wait(aio); + if ((rv = nng_aio_result(aio)) != 0) { goto fail; } - nni_http_read_res(h, res, aio); - nni_aio_wait(aio); - if ((rv = nni_aio_result(aio)) != 0) { + nng_http_conn_read_res(h, res, aio); + nng_aio_wait(aio); + if ((rv = nng_aio_result(aio)) != 0) { goto fail; } - *statp = nni_http_res_get_status(res); - clen = 0; - if ((*statp == NNI_HTTP_STATUS_OK) && - ((ptr = nni_http_res_get_header(res, "Content-Length")) != NULL)) { + clen = 0; + if ((nng_http_res_get_status(res) == NNG_HTTP_STATUS_OK) && + ((ptr = nng_http_res_get_header(res, "Content-Length")) != NULL)) { clen = atoi(ptr); } @@ -88,13 +75,57 @@ httpget(const char *addr, void **datap, size_t *sizep, uint16_t *statp, data = nni_alloc(clen); iov.iov_buf = data; iov.iov_len = clen; - nni_aio_set_iov(aio, 1, &iov); - nni_http_read_full(h, aio); - nni_aio_wait(aio); - if ((rv = nni_aio_result(aio)) != 0) { + nng_aio_set_iov(aio, 1, &iov); + nng_http_conn_read_all(h, aio); + nng_aio_wait(aio); + if ((rv = nng_aio_result(aio)) != 0) { goto fail; } - if ((ptr = nni_http_res_get_header(res, "Content-Type")) != + } + + *datap = data; + *sizep = clen; + +fail: + if (aio != NULL) { + nng_aio_free(aio); + } + if (h != NULL) { + nng_http_conn_close(h); + } + if (cli != NULL) { + nni_http_client_fini(cli); + } + + return (rv); +} + +static int +httpget(const char *addr, void **datap, size_t *sizep, uint16_t *statp, + char **ctypep) +{ + int rv; + nng_http_req *req = NULL; + nng_http_res *res = NULL; + nng_url * url = NULL; + size_t clen = 0; + void * data = NULL; + char * ctype = NULL; + const char * ptr; + + if (((rv = nng_url_parse(&url, addr)) != 0) || + ((rv = nng_http_req_alloc(&req, url)) != 0) || + ((rv = nng_http_res_alloc(&res)) != 0)) { + goto fail; + } + if ((rv = httpdo(url, req, res, &data, &clen)) != 0) { + goto fail; + } + + *statp = nng_http_res_get_status(res); + + if (clen > 0) { + if ((ptr = nng_http_res_get_header(res, "Content-Type")) != NULL) { ctype = nni_strdup(ptr); } @@ -114,100 +145,86 @@ fail: if (url != NULL) { nni_url_free(url); } - if (aio != NULL) { - nni_aio_fini(aio); - } if (req != NULL) { - nni_http_req_fini(req); + nng_http_req_free(req); } if (res != NULL) { - nni_http_res_fini(res); - } - if (h != NULL) { - nni_http_fini(h); - } - if (cli != NULL) { - nni_http_client_fini(cli); + nng_http_res_free(res); } return (rv); } -TestMain("HTTP Client", { +TestMain("HTTP Server", { - nni_http_server * s; - nni_http_handler *h; + nng_http_server * s; + nng_http_handler *h; nni_init(); atexit(cleanup); Convey("We can start an HTTP server", { - nni_aio *aio; + nng_aio *aio; char portbuf[16]; char urlstr[32]; - nni_url *url; + nng_url *url; trantest_next_address(portbuf, "%u"); snprintf( urlstr, sizeof(urlstr), "http://127.0.0.1:%s", portbuf); - So(nni_url_parse(&url, urlstr) == 0); - So(nni_aio_init(&aio, NULL, NULL) == 0); + So(nng_url_parse(&url, urlstr) == 0); + So(nng_aio_alloc(&aio, NULL, NULL) == 0); - So(nni_http_server_init(&s, url) == 0); + So(nng_http_server_hold(&s, url) == 0); Reset({ - nni_aio_fini(aio); - nni_http_server_fini(s); - nni_url_free(url); + nng_aio_free(aio); + nng_http_server_release(s); + nng_url_free(url); }); - So(nni_http_handler_init_static(&h, "/home.html", doc1, + So(nng_http_handler_alloc_static(&h, "/home.html", doc1, strlen(doc1), "text/html") == 0); - So(nni_http_server_add_handler(s, h) == 0); - So(nni_http_server_start(s) == 0); + So(nng_http_server_add_handler(s, h) == 0); + So(nng_http_server_start(s) == 0); Convey("We can connect a client to it", { nni_http_client *cli; - nni_http * h; - nni_http_req * req; - nni_http_res * res; + nng_http_conn * h; + nng_http_req * req; + nng_http_res * res; So(nni_http_client_init(&cli, url) == 0); nni_http_client_connect(cli, aio); - nni_aio_wait(aio); + nng_aio_wait(aio); - So(nni_aio_result(aio) == 0); + So(nng_aio_result(aio) == 0); h = nni_aio_get_output(aio, 0); So(h != NULL); - So(nni_http_req_init(&req) == 0); - So(nni_http_res_init(&res) == 0); + So(nng_http_req_alloc(&req, url) == 0); + So(nng_http_res_alloc(&res) == 0); Reset({ nni_http_client_fini(cli); - nni_http_fini(h); - nni_http_req_fini(req); - nni_http_res_fini(res); + nng_http_conn_close(h); + nng_http_req_free(req); + nng_http_res_free(res); }); Convey("404 works", { - So(nni_http_req_set_method(req, "GET") == 0); - So(nni_http_req_set_version(req, "HTTP/1.1") == - 0); - So(nni_http_req_set_uri(req, "/bogus") == 0); - So(nni_http_req_set_header( - req, "Host", "localhost") == 0); - nni_http_write_req(h, req, aio); + So(nng_http_req_set_uri(req, "/bogus") == 0); + nng_http_conn_write_req(h, req, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); - nni_http_read_res(h, res, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_http_conn_read_res(h, res, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); - So(nni_http_res_get_status(res) == 404); + So(nng_http_res_get_status(res) == 404); }); Convey("Valid data works", { @@ -215,46 +232,38 @@ TestMain("HTTP Client", { const void *ptr; nng_iov iov; - So(nni_http_req_set_method(req, "GET") == 0); - So(nni_http_req_set_version(req, "HTTP/1.1") == - 0); - So(nni_http_req_set_uri(req, "/home.html") == + So(nng_http_req_set_uri(req, "/home.html") == 0); - So(nni_http_req_set_header( - req, "Host", "localhost") == 0); - nni_http_write_req(h, req, aio); + nng_http_conn_write_req(h, req, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); - nni_http_read_res(h, res, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_http_conn_read_res(h, res, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); - So(nni_http_res_get_status(res) == 200); + So(nng_http_res_get_status(res) == 200); - ptr = nni_http_res_get_header( + ptr = nng_http_res_get_header( res, "Content-Length"); So(ptr != NULL); So(atoi(ptr) == strlen(doc1)); iov.iov_len = strlen(doc1); iov.iov_buf = chunk; - So(nni_aio_set_iov(aio, 1, &iov) == 0); - nni_http_read_full(h, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); - So(nni_aio_count(aio) == strlen(doc1)); + So(nng_aio_set_iov(aio, 1, &iov) == 0); + nng_http_conn_read_all(h, aio); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); + So(nng_aio_count(aio) == strlen(doc1)); So(memcmp(chunk, doc1, strlen(doc1)) == 0); }); - }); }); Convey("Directory serving works", { - nni_aio *aio; - char portbuf[16]; char urlstr[32]; - nni_url *url; + nng_url *url; char * tmpdir; char * workdir; char * file1; @@ -264,9 +273,8 @@ TestMain("HTTP Client", { char * subdir2; trantest_next_address(urlstr, "http://127.0.0.1:%u"); - So(nni_url_parse(&url, urlstr) == 0); - So(nni_aio_init(&aio, NULL, NULL) == 0); - So(nni_http_server_init(&s, url) == 0); + So(nng_url_parse(&url, urlstr) == 0); + So(nng_http_server_hold(&s, url) == 0); So((tmpdir = nni_plat_temp_dir()) != NULL); So((workdir = nni_file_join(tmpdir, "httptest")) != NULL); So((subdir1 = nni_file_join(workdir, "subdir1")) != NULL); @@ -280,8 +288,7 @@ TestMain("HTTP Client", { So(nni_file_put(file3, doc3, strlen(doc3)) == 0); Reset({ - nni_aio_fini(aio); - nni_http_server_fini(s); + nng_http_server_release(s); nni_strfree(tmpdir); nni_file_delete(file1); nni_file_delete(file2); @@ -295,12 +302,13 @@ TestMain("HTTP Client", { nni_strfree(file3); nni_strfree(subdir1); nni_strfree(subdir2); - nni_url_free(url); + nng_url_free(url); }); - So(nni_http_handler_init_directory(&h, "/docs", workdir) == 0); - So(nni_http_server_add_handler(s, h) == 0); - So(nni_http_server_start(s) == 0); + So(nng_http_handler_alloc_directory(&h, "/docs", workdir) == + 0); + So(nng_http_server_add_handler(s, h) == 0); + So(nng_http_server_start(s) == 0); nng_msleep(100); Convey("Index.html works", { @@ -313,12 +321,12 @@ TestMain("HTTP Client", { snprintf(fullurl, sizeof(fullurl), "%s/docs/subdir1/index.html", urlstr); So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); - So(stat == NNI_HTTP_STATUS_OK); + So(stat == NNG_HTTP_STATUS_OK); So(size == strlen(doc1)); So(memcmp(data, doc1, size) == 0); So(strcmp(ctype, "text/html") == 0); nni_strfree(ctype); - nni_free(data, size); + nng_free(data, size); }); Convey("Index.htm works", { @@ -331,12 +339,12 @@ TestMain("HTTP Client", { snprintf(fullurl, sizeof(fullurl), "%s/docs/subdir2", urlstr); So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); - So(stat == NNI_HTTP_STATUS_OK); + So(stat == NNG_HTTP_STATUS_OK); So(size == strlen(doc3)); So(memcmp(data, doc3, size) == 0); So(strcmp(ctype, "text/html") == 0); nni_strfree(ctype); - nni_free(data, size); + nng_free(data, size); }); Convey("Named file works", { @@ -349,12 +357,12 @@ TestMain("HTTP Client", { snprintf(fullurl, sizeof(fullurl), "%s/docs/file.txt", urlstr); So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); - So(stat == NNI_HTTP_STATUS_OK); + So(stat == NNG_HTTP_STATUS_OK); So(size == strlen(doc2)); So(memcmp(data, doc2, size) == 0); So(strcmp(ctype, "text/plain") == 0); nni_strfree(ctype); - nni_free(data, size); + nng_free(data, size); }); Convey("Missing index gives 404", { @@ -366,8 +374,76 @@ TestMain("HTTP Client", { snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); - So(stat == NNI_HTTP_STATUS_NOT_FOUND); + So(stat == NNG_HTTP_STATUS_NOT_FOUND); So(size == 0); }); + + Convey("Bad method gives 405", { + char fullurl[256]; + void * data; + size_t size; + nng_http_req *req; + nng_http_res *res; + nng_url * curl; + + So(nng_http_res_alloc(&res) == 0); + snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); + So(nng_url_parse(&curl, fullurl) == 0); + So(nng_http_req_alloc(&req, curl) == 0); + So(nng_http_req_set_method(req, "POST") == 0); + + So(httpdo(curl, req, res, &data, &size) == 0); + So(nng_http_res_get_status(res) == + NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); + So(size == 0); + nng_http_req_free(req); + nng_http_res_free(res); + nng_url_free(curl); + }); + Convey("Version 0.9 gives 505", { + char fullurl[256]; + void * data; + size_t size; + nng_http_req *req; + nng_http_res *res; + nng_url * curl; + + So(nng_http_res_alloc(&res) == 0); + snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); + So(nng_url_parse(&curl, fullurl) == 0); + So(nng_http_req_alloc(&req, curl) == 0); + So(nng_http_req_set_version(req, "HTTP/0.9") == 0); + + So(httpdo(curl, req, res, &data, &size) == 0); + So(nng_http_res_get_status(res) == + NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP); + So(size == 0); + nng_http_req_free(req); + nng_http_res_free(res); + nng_url_free(curl); + }); + Convey("Missing Host gives 400", { + char fullurl[256]; + void * data; + size_t size; + nng_http_req *req; + nng_http_res *res; + nng_url * curl; + + So(nng_http_res_alloc(&res) == 0); + snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); + So(nng_url_parse(&curl, fullurl) == 0); + So(nng_http_req_alloc(&req, curl) == 0); + So(nng_http_req_del_header(req, "Host") == 0); + + So(httpdo(curl, req, res, &data, &size) == 0); + So(nng_http_res_get_status(res) == + NNG_HTTP_STATUS_BAD_REQUEST); + So(size == 0); + nng_http_req_free(req); + nng_http_res_free(res); + nng_url_free(curl); + }); + }); }) diff --git a/tests/resolv.c b/tests/resolv.c index d1d3b2fe..607b3b11 100644 --- a/tests/resolv.c +++ b/tests/resolv.c @@ -1,6 +1,6 @@ // -// Copyright 2017 Garrett D'Amore <garrett@damore.org> -// Copyright 2017 Capitar IT Group BV <info@capitar.com> +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this @@ -73,57 +73,57 @@ TestMain("Resolver", { nni_init(); Convey("Google DNS IPv4 resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("google-public-dns-a.google.com", "80", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(80)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "8.8.8.8") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("Numeric UDP resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_udp_resolv("8.8.4.4", "69", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(69)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "8.8.4.4") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("Numeric v4 resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("8.8.4.4", "80", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(80)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "8.8.4.4") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("Numeric v6 resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; @@ -135,80 +135,80 @@ TestMain("Resolver", { ConveySkip("IPv6 missing from CI provider"); } - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("::1", "80", NNG_AF_INET6, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in6.sa_family == NNG_AF_INET6); So(sa.s_un.s_in6.sa_port == ntohs(80)); str = ip6tostr(&sa.s_un.s_in6.sa_addr); So(strcmp(str, "::1") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("TCP Name service resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("8.8.4.4", "http", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(80)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "8.8.4.4") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("UDP Name service resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_udp_resolv("8.8.4.4", "tftp", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(69)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "8.8.4.4") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("Localhost IPv4 resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("localhost", "80", NNG_AF_INET, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So(sa.s_un.s_in.sa_family == NNG_AF_INET); So(sa.s_un.s_in.sa_port == ntohs(80)); So(sa.s_un.s_in.sa_addr == ntohl(0x7f000001)); str = ip4tostr(&sa.s_un.s_in.sa_addr); So(strcmp(str, "127.0.0.1") == 0); - nni_aio_fini(aio); + nng_aio_free(aio); }); Convey("Localhost UNSPEC resolves", { - nni_aio * aio; + nng_aio * aio; const char * str; nng_sockaddr sa; - nni_aio_init(&aio, NULL, NULL); - aio->a_addr = &sa; + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + nng_aio_set_input(aio, 0, &sa); nni_plat_tcp_resolv("localhost", "80", NNG_AF_UNSPEC, 1, aio); - nni_aio_wait(aio); - So(nni_aio_result(aio) == 0); + nng_aio_wait(aio); + So(nng_aio_result(aio) == 0); So((sa.s_un.s_family == NNG_AF_INET) || (sa.s_un.s_family == NNG_AF_INET6)); switch (sa.s_un.s_family) { @@ -224,7 +224,7 @@ TestMain("Resolver", { So(strcmp(str, "::1") == 0); break; } - nni_aio_fini(aio); + nng_aio_free(aio); }); nni_fini(); diff --git a/tests/trantest.h b/tests/trantest.h index 80f59ff9..771b761e 100644 --- a/tests/trantest.h +++ b/tests/trantest.h @@ -220,7 +220,6 @@ trantest_conn_refused(trantest *tt) Convey("Connection refused works", { nng_dialer d = 0; - int rv = trantest_dial(tt, &d); So(trantest_dial(tt, &d) == NNG_ECONNREFUSED); So(d == 0); So(trantest_dial(tt, &d) == NNG_ECONNREFUSED); diff --git a/tests/udp.c b/tests/udp.c index 3097476f..f10446b9 100644 --- a/tests/udp.c +++ b/tests/udp.c @@ -59,32 +59,34 @@ TestMain("UDP support", { char rbuf[1024]; nng_sockaddr to; nng_sockaddr from; - nni_aio * aio1; - nni_aio * aio2; + nng_aio * aio1; + nng_aio * aio2; + nng_iov iov1; + nng_iov iov2; - nni_aio_init(&aio1, NULL, NULL); - nni_aio_init(&aio2, NULL, NULL); + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + So(nng_aio_alloc(&aio2, NULL, NULL) == 0); - to = sa2; - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg; - aio1->a_iov[0].iov_len = strlen(msg) + 1; - aio1->a_addr = &to; + to = sa2; + iov1.iov_buf = msg; + iov1.iov_len = strlen(msg) + 1; + So(nng_aio_set_iov(aio1, 1, &iov1) == 0); + nng_aio_set_input(aio1, 0, &to); - aio2->a_niov = 1; - aio2->a_iov[0].iov_buf = (void *) rbuf; - aio2->a_iov[0].iov_len = 1024; - aio2->a_addr = &from; + iov2.iov_buf = rbuf; + iov2.iov_len = 1024; + So(nng_aio_set_iov(aio2, 1, &iov2) == 0); + nng_aio_set_input(aio2, 0, &from); nni_plat_udp_recv(u2, aio2); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio1); - nni_aio_wait(aio2); + nng_aio_wait(aio1); + nng_aio_wait(aio2); - So(nni_aio_result(aio1) == 0); - So(nni_aio_result(aio2) == 0); + So(nng_aio_result(aio1) == 0); + So(nng_aio_result(aio2) == 0); - So(nni_aio_count(aio2) == strlen(msg) + 1); + So(nng_aio_count(aio2) == strlen(msg) + 1); So(strcmp(msg, rbuf) == 0); So(from.s_un.s_in.sa_family == @@ -97,23 +99,25 @@ TestMain("UDP support", { nni_plat_udp_recv(u2, aio2); nni_plat_udp_send(u2, aio1); - nni_aio_fini(aio1); - nni_aio_fini(aio2); + nng_aio_free(aio1); + nng_aio_free(aio2); }); Convey("Sending without an address fails", { - nni_aio *aio1; + nng_aio *aio1; char * msg = "nope"; + nng_iov iov; - nni_aio_init(&aio1, NULL, NULL); - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg; - aio1->a_iov[0].iov_len = strlen(msg) + 1; + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + + iov.iov_buf = msg; + iov.iov_len = strlen(msg) + 1; + So(nng_aio_set_iov(aio1, 1, &iov) == 0); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio1); - So(nni_aio_result(aio1) == NNG_EADDRINVAL); - nni_aio_fini(aio1); + nng_aio_wait(aio1); + So(nng_aio_result(aio1) == NNG_EADDRINVAL); + nng_aio_free(aio1); }); Convey("Multiple operations work", { @@ -125,37 +129,41 @@ TestMain("UDP support", { nng_sockaddr to2; nng_sockaddr from1; nng_sockaddr from2; - nni_aio * aio1; - nni_aio * aio2; - nni_aio * aio3; - nni_aio * aio4; - - nni_aio_init(&aio1, NULL, NULL); - nni_aio_init(&aio2, NULL, NULL); - nni_aio_init(&aio3, NULL, NULL); - nni_aio_init(&aio4, NULL, NULL); - - to1 = sa2; - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg1; - aio1->a_iov[0].iov_len = strlen(msg1) + 1; - aio1->a_addr = &to1; - - to2 = sa2; - aio2->a_niov = 1; - aio2->a_iov[0].iov_buf = (void *) msg2; - aio2->a_iov[0].iov_len = strlen(msg2) + 1; - aio2->a_addr = &to2; - - aio3->a_niov = 1; - aio3->a_iov[0].iov_buf = (void *) rbuf1; - aio3->a_iov[0].iov_len = 1024; - aio3->a_addr = &from1; - - aio4->a_niov = 1; - aio4->a_iov[0].iov_buf = (void *) rbuf2; - aio4->a_iov[0].iov_len = 1024; - aio4->a_addr = &from2; + nng_aio * aio1; + nng_aio * aio2; + nng_aio * aio3; + nng_aio * aio4; + nng_iov iov1; + nng_iov iov2; + nng_iov iov3; + nng_iov iov4; + + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + So(nng_aio_alloc(&aio2, NULL, NULL) == 0); + So(nng_aio_alloc(&aio3, NULL, NULL) == 0); + So(nng_aio_alloc(&aio4, NULL, NULL) == 0); + + to1 = sa2; + iov1.iov_buf = msg1; + iov1.iov_len = strlen(msg1) + 1; + So(nng_aio_set_iov(aio1, 1, &iov1) == 0); + nng_aio_set_input(aio1, 0, &to1); + + to2 = sa2; + iov2.iov_buf = msg2; + iov2.iov_len = strlen(msg2) + 1; + So(nng_aio_set_iov(aio2, 1, &iov2) == 0); + nng_aio_set_input(aio2, 0, &to2); + + iov3.iov_buf = rbuf1; + iov3.iov_len = 1024; + So(nng_aio_set_iov(aio3, 1, &iov3) == 0); + nng_aio_set_input(aio3, 0, &from1); + + iov4.iov_buf = rbuf2; + iov4.iov_len = 1024; + So(nng_aio_set_iov(aio4, 1, &iov4) == 0); + nng_aio_set_input(aio4, 0, &from2); nni_plat_udp_recv(u2, aio4); nni_plat_udp_recv(u2, aio3); @@ -165,90 +173,93 @@ TestMain("UDP support", { nng_msleep(1); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio2); - nni_aio_wait(aio1); - nni_aio_wait(aio3); - nni_aio_wait(aio4); + nng_aio_wait(aio2); + nng_aio_wait(aio1); + nng_aio_wait(aio3); + nng_aio_wait(aio4); - So(nni_aio_result(aio1) == 0); - So(nni_aio_result(aio2) == 0); - So(nni_aio_result(aio3) == 0); - So(nni_aio_result(aio4) == 0); + So(nng_aio_result(aio1) == 0); + So(nng_aio_result(aio2) == 0); + So(nng_aio_result(aio3) == 0); + So(nng_aio_result(aio4) == 0); So(from1.s_un.s_in.sa_family == sa1.s_un.s_in.sa_family); So(from1.s_un.s_in.sa_port == sa1.s_un.s_in.sa_port); So(from1.s_un.s_in.sa_addr == sa1.s_un.s_in.sa_addr); - nni_aio_fini(aio1); - nni_aio_fini(aio2); - nni_aio_fini(aio3); - nni_aio_fini(aio4); + nng_aio_free(aio1); + nng_aio_free(aio2); + nng_aio_free(aio3); + nng_aio_free(aio4); }); Convey("Sending without an address fails", { - nni_aio *aio1; + nng_aio *aio1; char * msg = "nope"; + nng_iov iov; - nni_aio_init(&aio1, NULL, NULL); - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg; - aio1->a_iov[0].iov_len = strlen(msg) + 1; + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + iov.iov_buf = msg; + iov.iov_len = strlen(msg) + 1; + So(nng_aio_set_iov(aio1, 1, &iov) == 0); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio1); - So(nni_aio_result(aio1) == NNG_EADDRINVAL); - nni_aio_fini(aio1); + nng_aio_wait(aio1); + So(nng_aio_result(aio1) == NNG_EADDRINVAL); + nng_aio_free(aio1); }); Convey("Sending to an IPv6 address on IPv4 fails", { - nni_aio * aio1; + nng_aio * aio1; char * msg = "nope"; nng_sockaddr sa; int rv; + nng_iov iov; sa.s_un.s_in6.sa_family = NNG_AF_INET6; // address is for google.com inet_ntop(AF_INET6, "2607:f8b0:4007:804::200e", (void *) sa.s_un.s_in6.sa_addr, 16); sa.s_un.s_in6.sa_port = 80; - nni_aio_init(&aio1, NULL, NULL); - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg; - aio1->a_iov[0].iov_len = strlen(msg) + 1; - aio1->a_addr = &sa; + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + iov.iov_buf = msg; + iov.iov_len = strlen(msg) + 1; + So(nng_aio_set_iov(aio1, 1, &iov) == 0); + nng_aio_set_input(aio1, 0, &sa); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio1); - So((rv = nni_aio_result(aio1)) != 0); + nng_aio_wait(aio1); + So((rv = nng_aio_result(aio1)) != 0); So(rv == NNG_EADDRINVAL || rv == NNG_ENOTSUP || rv == NNG_EUNREACHABLE); - nni_aio_fini(aio1); + nng_aio_free(aio1); }); Convey("Sending to an IPC address fails", { - nni_aio * aio1; + nng_aio * aio1; char * msg = "nope"; nng_sockaddr sa; int rv; + nng_iov iov; sa.s_un.s_in6.sa_family = NNG_AF_INET6; // address is for google.com inet_ntop(AF_INET6, "2607:f8b0:4007:804::200e", (void *) sa.s_un.s_in6.sa_addr, 16); sa.s_un.s_in6.sa_port = 80; - nni_aio_init(&aio1, NULL, NULL); - aio1->a_niov = 1; - aio1->a_iov[0].iov_buf = (void *) msg; - aio1->a_iov[0].iov_len = strlen(msg) + 1; - aio1->a_addr = &sa; + So(nng_aio_alloc(&aio1, NULL, NULL) == 0); + iov.iov_buf = msg; + iov.iov_len = strlen(msg) + 1; + So(nng_aio_set_iov(aio1, 1, &iov) == 0); + nng_aio_set_input(aio1, 0, &sa); nni_plat_udp_send(u1, aio1); - nni_aio_wait(aio1); - So((rv = nni_aio_result(aio1)) != 0); + nng_aio_wait(aio1); + So((rv = nng_aio_result(aio1)) != 0); So(rv == NNG_EADDRINVAL || rv == NNG_ENOTSUP || rv == NNG_EUNREACHABLE); - nni_aio_fini(aio1); + nng_aio_free(aio1); }); }); @@ -184,6 +184,17 @@ check_props(nng_msg *msg, nng_listener l, nng_dialer d) So(mtu >= 1000 && mtu <= 10000); }); + Convey("Network name property works", { + char name[NNG_MAXADDRLEN]; + size_t namesz; + int status; + + namesz = sizeof(name); + So(nng_listener_getopt( + l, NNG_OPT_ZT_NETWORK_NAME, name, &namesz) == 0); + So(strcmp(name, "nng_test_open") == 0); + }); + return (0); } @@ -280,20 +291,6 @@ TestMain("ZeroTier Transport", { 0); So(node1 != 0); - Convey("Network name & status options work", { - char name[NNG_MAXADDRLEN]; - size_t namesz; - int status; - - namesz = sizeof(name); - nng_msleep(10000); - So(nng_listener_getopt(l, NNG_OPT_ZT_NETWORK_NAME, - name, &namesz) == 0); - So(strcmp(name, "nng_test_open") == 0); - So(nng_listener_getopt_int( - l, NNG_OPT_ZT_NETWORK_STATUS, &status) == 0); - So(status == nng_zt_network_status_ok); - }); Convey("Connection refused works", { snprintf(addr, sizeof(addr), "zt://%llx." NWID ":%u", (unsigned long long) node1, 42u); @@ -315,7 +312,6 @@ TestMain("ZeroTier Transport", { uint64_t node; port = 9944; - // uint64_t node = 0xb000072fa6ull; // my personal host So(nng_zt_register() == 0); snprintf(addr1, sizeof(addr1), "zt://*." NWID ":%u", port); @@ -324,8 +320,7 @@ TestMain("ZeroTier Transport", { So(nng_pair_open(&s2) == 0); Reset({ nng_close(s1); - // This sleep allows us to ensure disconnect - // messages work. + // This sleep ensures disconnect messages work. nng_msleep(500); nng_close(s2); }); @@ -345,7 +340,7 @@ TestMain("ZeroTier Transport", { So(nng_dialer_setopt( d, NNG_OPT_ZT_HOME, path2, strlen(path2) + 1) == 0); So(nng_dialer_start(d, 0) == 0); - nng_msleep(2000); + nng_msleep(2000); // to give dialer time to start up }); trantest_test_extended("zt://*." NWID ":%u", check_props); |
