aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/core/aio.c150
-rw-r--r--src/core/aio.h96
-rw-r--r--src/core/defs.h4
-rw-r--r--src/core/device.c8
-rw-r--r--src/core/endpt.c10
-rw-r--r--src/core/msgqueue.c6
-rw-r--r--src/core/msgqueue.h4
-rw-r--r--src/core/pipe.c12
-rw-r--r--src/core/pipe.h4
-rw-r--r--src/core/protocol.h4
-rw-r--r--src/core/socket.c20
-rw-r--r--src/core/socket.h6
-rw-r--r--src/core/transport.c1
-rw-r--r--src/core/url.c5
-rw-r--r--src/core/url.h1
-rw-r--r--src/nng.c69
-rw-r--r--src/nng.h433
-rw-r--r--src/platform/posix/posix_aio.h3
-rw-r--r--src/platform/posix/posix_epdesc.c11
-rw-r--r--src/platform/posix/posix_ipc.c3
-rw-r--r--src/platform/posix/posix_pipedesc.c67
-rw-r--r--src/platform/posix/posix_resolv_gai.c26
-rw-r--r--src/platform/posix/posix_tcp.c3
-rw-r--r--src/platform/posix/posix_udp.c48
-rw-r--r--src/platform/windows/win_iocp.c2
-rw-r--r--src/platform/windows/win_ipc.c22
-rw-r--r--src/platform/windows/win_resolv.c8
-rw-r--r--src/platform/windows/win_tcp.c30
-rw-r--r--src/platform/windows/win_udp.c56
-rw-r--r--src/protocol/bus0/bus.c7
-rw-r--r--src/protocol/pair0/pair.c5
-rw-r--r--src/protocol/pipeline0/pull.c4
-rw-r--r--src/protocol/pipeline0/push.c4
-rw-r--r--src/protocol/pubsub0/pub.c6
-rw-r--r--src/protocol/pubsub0/sub.c4
-rw-r--r--src/protocol/reqrep0/rep.c6
-rw-r--r--src/protocol/reqrep0/req.c6
-rw-r--r--src/protocol/survey0/respond.c6
-rw-r--r--src/protocol/survey0/survey.c2
-rw-r--r--src/supplemental/http/CMakeLists.txt19
-rw-r--r--src/supplemental/http/http.c740
-rw-r--r--src/supplemental/http/http.h226
-rw-r--r--src/supplemental/http/http_client.c (renamed from src/supplemental/http/client.c)20
-rw-r--r--src/supplemental/http/http_conn.c765
-rw-r--r--src/supplemental/http/http_msg.c318
-rw-r--r--src/supplemental/http/http_public.c668
-rw-r--r--src/supplemental/http/http_server.c (renamed from src/supplemental/http/server.c)406
-rw-r--r--src/supplemental/tls/CMakeLists.txt2
-rw-r--r--src/supplemental/tls/mbedtls/tls.c57
-rw-r--r--src/supplemental/tls/tls.h4
-rw-r--r--src/supplemental/websocket/websocket.c177
-rw-r--r--src/supplemental/websocket/websocket.h20
-rw-r--r--src/transport/inproc/inproc.c41
-rw-r--r--src/transport/ipc/ipc.c124
-rw-r--r--src/transport/tcp/tcp.c137
-rw-r--r--src/transport/tls/tls.c135
-rw-r--r--src/transport/ws/websocket.c16
-rw-r--r--src/transport/zerotier/zerotier.c65
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
diff --git a/src/nng.c b/src/nng.c
index e88b6d2c..16de18d5 100644
--- a/src/nng.c
+++ b/src/nng.c
@@ -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
+}
diff --git a/src/nng.h b/src/nng.h
index 24689f96..47cd3bcc 100644
--- a/src/nng.h
+++ b/src/nng.h
@@ -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);