diff options
Diffstat (limited to 'src')
59 files changed, 3124 insertions, 1980 deletions
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); |
