diff options
| author | Garrett D'Amore <garrett@damore.org> | 2024-12-28 13:53:18 -0800 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-12-28 13:53:24 -0800 |
| commit | 7b5515ca641f475dce8184a5d9fd67ceb860e843 (patch) | |
| tree | dd6e458ea87df33b3d9b359572abdd63154c6999 | |
| parent | 146e10d365e3c451ba92b226e0d7cbfcc3574383 (diff) | |
| download | nng-7b5515ca641f475dce8184a5d9fd67ceb860e843.tar.gz nng-7b5515ca641f475dce8184a5d9fd67ceb860e843.tar.bz2 nng-7b5515ca641f475dce8184a5d9fd67ceb860e843.zip | |
tcp: flatten the listener implementation
The endpoints both use a nesting level for some common code and some
platform dependent code. But the common code isn't that much and we
have similar patterns for e.g. IPC.
This avoids a layer of indirection in the structs, and extra allocations.
The payoff will be even larger for the dialers, but that is next.
(Dialers are more complicated because of DNS.)
| -rw-r--r-- | src/core/tcp.c | 140 | ||||
| -rw-r--r-- | src/platform/posix/posix_tcplisten.c | 197 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.h | 42 | ||||
| -rw-r--r-- | src/platform/windows/win_tcplisten.c | 239 |
4 files changed, 315 insertions, 303 deletions
diff --git a/src/core/tcp.c b/src/core/tcp.c index 159ffe41..fd1c7e96 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -273,143 +273,3 @@ nni_tcp_dialer_alloc(nng_stream_dialer **dp, const nng_url *url) *dp = (void *) d; return (0); } - -typedef struct { - nng_stream_listener ops; - nni_tcp_listener *l; - nng_sockaddr sa; -} tcp_listener; - -static void -tcp_listener_close(void *arg) -{ - tcp_listener *l = arg; - nni_tcp_listener_close(l->l); -} - -static void -tcp_listener_stop(void *arg) -{ - tcp_listener *l = arg; - nni_tcp_listener_stop(l->l); -} - -static void -tcp_listener_free(void *arg) -{ - tcp_listener *l = arg; - nni_tcp_listener_fini(l->l); - NNI_FREE_STRUCT(l); -} - -static int -tcp_listener_listen(void *arg) -{ - tcp_listener *l = arg; - return (nni_tcp_listener_listen(l->l, &l->sa)); -} - -static void -tcp_listener_accept(void *arg, nng_aio *aio) -{ - tcp_listener *l = arg; - nni_tcp_listener_accept(l->l, aio); -} - -static int -tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t) -{ - tcp_listener *l = arg; - int rv; - nng_sockaddr sa; - size_t sz; - int port; - uint8_t *paddr; - - sz = sizeof(sa); - rv = nni_tcp_listener_get( - l->l, NNG_OPT_LOCADDR, &sa, &sz, NNI_TYPE_SOCKADDR); - if (rv != 0) { - return (rv); - } - - switch (sa.s_family) { - case NNG_AF_INET: - paddr = (void *) &sa.s_in.sa_port; - break; - - case NNG_AF_INET6: - paddr = (void *) &sa.s_in6.sa_port; - break; - - default: - paddr = NULL; - break; - } - - if (paddr == NULL) { - return (NNG_ESTATE); - } - - NNI_GET16(paddr, port); - return (nni_copyout_int(port, buf, szp, t)); -} - -static int -tcp_listener_get( - void *arg, const char *name, void *buf, size_t *szp, nni_type t) -{ - tcp_listener *l = arg; - if (strcmp(name, NNG_OPT_TCP_BOUND_PORT) == 0) { - return (tcp_listener_get_port(l, buf, szp, t)); - } - return (nni_tcp_listener_get(l->l, name, buf, szp, t)); -} - -static int -tcp_listener_set( - void *arg, const char *name, const void *buf, size_t sz, nni_type t) -{ - tcp_listener *l = arg; - return (nni_tcp_listener_set(l->l, name, buf, sz, t)); -} - -static int -tcp_listener_alloc_addr(nng_stream_listener **lp, const nng_sockaddr *sa) -{ - tcp_listener *l; - int rv; - - if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { - return (NNG_ENOMEM); - } - if ((rv = nni_tcp_listener_init(&l->l)) != 0) { - NNI_FREE_STRUCT(l); - return (rv); - } - l->sa = *sa; - - l->ops.sl_free = tcp_listener_free; - l->ops.sl_close = tcp_listener_close; - l->ops.sl_stop = tcp_listener_stop; - l->ops.sl_listen = tcp_listener_listen; - l->ops.sl_accept = tcp_listener_accept; - l->ops.sl_get = tcp_listener_get; - l->ops.sl_set = tcp_listener_set; - - *lp = (void *) l; - return (0); -} - -int -nni_tcp_listener_alloc(nng_stream_listener **lp, const nng_url *url) -{ - int rv; - nng_sockaddr sa; - - if ((rv = nni_url_to_address(&sa, url)) != 0) { - return (rv); - } - - return (tcp_listener_alloc_addr(lp, &sa)); -} diff --git a/src/platform/posix/posix_tcplisten.c b/src/platform/posix/posix_tcplisten.c index b14114b7..6588fb78 100644 --- a/src/platform/posix/posix_tcplisten.c +++ b/src/platform/posix/posix_tcplisten.c @@ -38,37 +38,20 @@ #include "posix_tcp.h" -struct nni_tcp_listener { - nni_posix_pfd pfd; - nni_list acceptq; - bool started; - bool closed; - bool nodelay; - bool keepalive; - nni_mtx mtx; -}; - -int -nni_tcp_listener_init(nni_tcp_listener **lp) -{ - nni_tcp_listener *l; - if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { - return (NNG_ENOMEM); - } - - nni_mtx_init(&l->mtx); - - l->closed = false; - l->started = false; - l->nodelay = true; - - nni_aio_list_init(&l->acceptq); - *lp = l; - return (0); -} +typedef struct tcp_listener { + nng_stream_listener ops; + nng_sockaddr sa; + nni_posix_pfd pfd; + nni_list acceptq; + bool started; + bool closed; + bool nodelay; + bool keepalive; + nni_mtx mtx; +} tcp_listener; static void -tcp_listener_doclose(nni_tcp_listener *l) +tcp_listener_doclose(tcp_listener *l) { nni_aio *aio; @@ -82,15 +65,16 @@ tcp_listener_doclose(nni_tcp_listener *l) } void -nni_tcp_listener_close(nni_tcp_listener *l) +tcp_listener_close(void *arg) { + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); tcp_listener_doclose(l); nni_mtx_unlock(&l->mtx); } static void -tcp_listener_doaccept(nni_tcp_listener *l) +tcp_listener_doaccept(tcp_listener *l) { nni_aio *aio; @@ -161,7 +145,7 @@ tcp_listener_doaccept(nni_tcp_listener *l) static void tcp_listener_cb(void *arg, unsigned events) { - nni_tcp_listener *l = arg; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); if ((events & NNI_POLL_INVAL) != 0) { @@ -178,7 +162,7 @@ tcp_listener_cb(void *arg, unsigned events) static void tcp_listener_cancel(nni_aio *aio, void *arg, int rv) { - nni_tcp_listener *l = arg; + tcp_listener *l = arg; // This is dead easy, because we'll ignore the completion if there // isn't anything to do the accept on! @@ -191,15 +175,16 @@ tcp_listener_cancel(nni_aio *aio, void *arg, int rv) nni_mtx_unlock(&l->mtx); } -int -nni_tcp_listener_listen(nni_tcp_listener *l, const nni_sockaddr *sa) +static int +tcp_listener_listen(void *arg) { + tcp_listener *l = arg; socklen_t len; struct sockaddr_storage ss; int rv; int fd; - if (((len = nni_posix_nn2sockaddr(&ss, sa)) == 0) || + if (((len = nni_posix_nn2sockaddr(&ss, &l->sa)) == 0) || #ifdef NNG_ENABLE_IPV6 ((ss.ss_family != AF_INET) && (ss.ss_family != AF_INET6)) #else @@ -261,9 +246,10 @@ nni_tcp_listener_listen(nni_tcp_listener *l, const nni_sockaddr *sa) return (0); } -void -nni_tcp_listener_stop(nni_tcp_listener *l) +static void +tcp_listener_stop(void *arg) { + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); tcp_listener_doclose(l); nni_mtx_unlock(&l->mtx); @@ -271,18 +257,21 @@ nni_tcp_listener_stop(nni_tcp_listener *l) nni_posix_pfd_stop(&l->pfd); } -void -nni_tcp_listener_fini(nni_tcp_listener *l) +static void +tcp_listener_free(void *arg) { - nni_tcp_listener_stop(l); + tcp_listener *l = arg; + nni_posix_pfd_fini(&l->pfd); nni_mtx_fini(&l->mtx); NNI_FREE_STRUCT(l); } -void -nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) +static void +tcp_listener_accept(void *arg, nni_aio *aio) { + tcp_listener *l = arg; + // Accept is simpler than the connect case. With accept we just // need to wait for the socket to be readable to indicate an incoming // connection is ready for us. There isn't anything else for us to @@ -314,8 +303,8 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) static int tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) { - nni_tcp_listener *l = arg; - nng_sockaddr sa; + tcp_listener *l = arg; + nng_sockaddr sa; nni_mtx_lock(&l->mtx); if (l->started) { struct sockaddr_storage ss; @@ -333,9 +322,9 @@ tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) static int tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) { - nni_tcp_listener *l = arg; - int rv; - bool b; + tcp_listener *l = arg; + int rv; + bool b; if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { return (rv); @@ -349,8 +338,8 @@ tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) static int tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) { - bool b; - nni_tcp_listener *l = arg; + bool b; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); b = l->nodelay; nni_mtx_unlock(&l->mtx); @@ -360,9 +349,9 @@ tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) static int tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) { - nni_tcp_listener *l = arg; - int rv; - bool b; + tcp_listener *l = arg; + int rv; + bool b; if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { return (rv); @@ -376,14 +365,52 @@ tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) static int tcp_listener_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) { - bool b; - nni_tcp_listener *l = arg; + bool b; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); b = l->keepalive; nni_mtx_unlock(&l->mtx); return (nni_copyout_bool(b, buf, szp, t)); } +static int +tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t) +{ + tcp_listener *l = arg; + int rv; + nng_sockaddr sa; + size_t sz; + int port; + uint8_t *paddr; + + sz = sizeof(sa); + rv = tcp_listener_get_locaddr(l, &sa, &sz, NNI_TYPE_SOCKADDR); + if (rv != 0) { + return (rv); + } + + switch (sa.s_family) { + case NNG_AF_INET: + paddr = (void *) &sa.s_in.sa_port; + break; + + case NNG_AF_INET6: + paddr = (void *) &sa.s_in6.sa_port; + break; + + default: + paddr = NULL; + break; + } + + if (paddr == NULL) { + return (NNG_ESTATE); + } + + NNI_GET16(paddr, port); + return (nni_copyout_int(port, buf, szp, t)); +} + static const nni_option tcp_listener_options[] = { { .o_name = NNG_OPT_LOCADDR, @@ -400,20 +427,66 @@ static const nni_option tcp_listener_options[] = { .o_get = tcp_listener_get_keepalive, }, { + .o_name = NNG_OPT_TCP_BOUND_PORT, + .o_get = tcp_listener_get_port, + }, + { .o_name = NULL, }, }; -int -nni_tcp_listener_get( - nni_tcp_listener *l, const char *name, void *buf, size_t *szp, nni_type t) +static int +tcp_listener_get( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) { - return (nni_getopt(tcp_listener_options, name, l, buf, szp, t)); + return (nni_getopt(tcp_listener_options, name, arg, buf, szp, t)); +} + +static int +tcp_listener_set( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) +{ + return (nni_setopt(tcp_listener_options, name, arg, buf, sz, t)); +} + +static int +tcp_listener_alloc_addr(nng_stream_listener **lp, const nng_sockaddr *sa) +{ + tcp_listener *l; + + if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { + return (NNG_ENOMEM); + } + + nni_mtx_init(&l->mtx); + nni_aio_list_init(&l->acceptq); + + l->closed = false; + l->started = false; + l->nodelay = true; + l->sa = *sa; + + l->ops.sl_free = tcp_listener_free; + l->ops.sl_close = tcp_listener_close; + l->ops.sl_stop = tcp_listener_stop; + l->ops.sl_listen = tcp_listener_listen; + l->ops.sl_accept = tcp_listener_accept; + l->ops.sl_get = tcp_listener_get; + l->ops.sl_set = tcp_listener_set; + + *lp = (void *) l; + return (0); } int -nni_tcp_listener_set(nni_tcp_listener *l, const char *name, const void *buf, - size_t sz, nni_type t) +nni_tcp_listener_alloc(nng_stream_listener **lp, const nng_url *url) { - return (nni_setopt(tcp_listener_options, name, l, buf, sz, t)); + int rv; + nng_sockaddr sa; + + if ((rv = nni_url_to_address(&sa, url)) != 0) { + return (rv); + } + + return (tcp_listener_alloc_addr(lp, &sa)); } diff --git a/src/platform/windows/win_tcp.h b/src/platform/windows/win_tcp.h index d151b9a3..655a969c 100644 --- a/src/platform/windows/win_tcp.h +++ b/src/platform/windows/win_tcp.h @@ -17,27 +17,27 @@ #include "core/nng_impl.h" struct nni_tcp_conn { - nng_stream ops; - SOCKET s; - nni_win_io recv_io; - nni_win_io send_io; - nni_win_io conn_io; - nni_list recv_aios; - nni_list send_aios; - nni_aio *conn_aio; - SOCKADDR_STORAGE sockname; - SOCKADDR_STORAGE peername; - nni_tcp_dialer *dialer; - nni_tcp_listener *listener; - int recv_rv; - int send_rv; - int conn_rv; - bool closed; - char buf[512]; // to hold acceptex results - bool sending; - bool recving; - nni_mtx mtx; - nni_cv cv; + nng_stream ops; + SOCKET s; + nni_win_io recv_io; + nni_win_io send_io; + nni_win_io conn_io; + nni_list recv_aios; + nni_list send_aios; + nni_aio *conn_aio; + SOCKADDR_STORAGE sockname; + SOCKADDR_STORAGE peername; + nni_tcp_dialer *dialer; + void *listener; + int recv_rv; + int send_rv; + int conn_rv; + bool closed; + char buf[512]; // to hold acceptex results + bool sending; + bool recving; + nni_mtx mtx; + nni_cv cv; }; extern int nni_win_tcp_init(nni_tcp_conn **, SOCKET); diff --git a/src/platform/windows/win_tcplisten.c b/src/platform/windows/win_tcplisten.c index e7c7a966..d4ff7cbc 100644 --- a/src/platform/windows/win_tcplisten.c +++ b/src/platform/windows/win_tcplisten.c @@ -17,7 +17,9 @@ #include "win_tcp.h" -struct nni_tcp_listener { +typedef struct tcp_listener { + nng_stream_listener ops; + nng_sockaddr sa; SOCKET s; nni_list aios; bool closed; @@ -33,12 +35,12 @@ struct nni_tcp_listener { nni_win_io accept_io; int accept_rv; nni_tcp_conn *pend_conn; -}; +} tcp_listener; // tcp_listener_funcs looks up function pointers we need for advanced accept // functionality on Windows. Windows is weird. static int -tcp_listener_funcs(nni_tcp_listener *l) +tcp_listener_funcs(tcp_listener *l) { static SRWLOCK lock = SRWLOCK_INIT; static LPFN_ACCEPTEX acceptex; @@ -82,15 +84,16 @@ tcp_listener_funcs(nni_tcp_listener *l) return (0); } -static void tcp_listener_accepted(nni_tcp_listener *l); -static void tcp_listener_doaccept(nni_tcp_listener *l); +static void tcp_listener_accepted(tcp_listener *l); +static void tcp_listener_doaccept(tcp_listener *l); +static void tcp_listener_free(void *arg); static void tcp_accept_cb(nni_win_io *io, int rv, size_t cnt) { - nni_tcp_listener *l = io->ptr; - nni_aio *aio; - nni_tcp_conn *c; + tcp_listener *l = io->ptr; + nni_aio *aio; + nni_tcp_conn *c; NNI_ARG_UNUSED(cnt); @@ -120,39 +123,13 @@ tcp_accept_cb(nni_win_io *io, int rv, size_t cnt) nni_mtx_unlock(&l->mtx); } -int -nni_tcp_listener_init(nni_tcp_listener **lp) -{ - nni_tcp_listener *l; - int rv; - - if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { - return (NNG_ENOMEM); - } - ZeroMemory(l, sizeof(*l)); - nni_mtx_init(&l->mtx); - nni_aio_list_init(&l->aios); - nni_win_io_init(&l->accept_io, tcp_accept_cb, l); - l->accept_rv = 0; - if ((rv = tcp_listener_funcs(l)) != 0) { - nni_tcp_listener_fini(l); - return (rv); - } - - // We assume these defaults -- not everyone will agree, but anyone - // can change them. - l->keepalive = false; - l->nodelay = true; - - *lp = l; - return (0); -} - -void -nni_tcp_listener_close(nni_tcp_listener *l) +static void +tcp_listener_close(void *arg) { nni_aio *aio; nni_tcp_conn *conn; + tcp_listener *l = arg; + nni_mtx_lock(&l->mtx); if (!l->closed) { l->closed = true; @@ -173,21 +150,24 @@ nni_tcp_listener_close(nni_tcp_listener *l) } static nni_reap_list tcp_listener_reap_list = { - .rl_offset = offsetof(nni_tcp_listener, reap), - .rl_func = (nni_cb) nni_tcp_listener_fini, + .rl_offset = offsetof(tcp_listener, reap), + .rl_func = (nni_cb) tcp_listener_free, }; -void -nni_tcp_listener_stop(nni_tcp_listener *l) +static void +tcp_listener_stop(void *arg) { - nni_tcp_listener_close(l); + tcp_listener *l = arg; + tcp_listener_close(l); // TODO: maybe wait for l->l_accept_io.olpd to finish? } -void -nni_tcp_listener_fini(nni_tcp_listener *l) +static void +tcp_listener_free(void *arg) { - nni_tcp_listener_close(l); + tcp_listener *l = arg; + + tcp_listener_close(l); nni_mtx_lock(&l->mtx); if (l->running) { nni_mtx_unlock(&l->mtx); @@ -199,13 +179,14 @@ nni_tcp_listener_fini(nni_tcp_listener *l) NNI_FREE_STRUCT(l); } -int -nni_tcp_listener_listen(nni_tcp_listener *l, const nni_sockaddr *sa) +static int +tcp_listener_listen(void *arg) { - int rv; - BOOL yes; - DWORD no; - int len; + int rv; + BOOL yes; + DWORD no; + int len; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); if (l->closed) { @@ -216,7 +197,7 @@ nni_tcp_listener_listen(nni_tcp_listener *l, const nni_sockaddr *sa) nni_mtx_unlock(&l->mtx); return (NNG_EBUSY); } - if ((len = nni_win_nn2sockaddr(&l->ss, sa)) <= 0) { + if ((len = nni_win_nn2sockaddr(&l->ss, &l->sa)) <= 0) { nni_mtx_unlock(&l->mtx); return (NNG_EADDRINVAL); } @@ -266,7 +247,7 @@ nni_tcp_listener_listen(nni_tcp_listener *l, const nni_sockaddr *sa) static void tcp_accept_cancel(nni_aio *aio, void *arg, int rv) { - nni_tcp_listener *l = arg; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); if (aio == nni_list_first(&l->aios)) { @@ -286,7 +267,7 @@ tcp_accept_cancel(nni_aio *aio, void *arg, int rv) } static void -tcp_listener_accepted(nni_tcp_listener *l) +tcp_listener_accepted(tcp_listener *l) { int len1; int len2; @@ -324,7 +305,7 @@ tcp_listener_accepted(nni_tcp_listener *l) } static void -tcp_listener_doaccept(nni_tcp_listener *l) +tcp_listener_doaccept(tcp_listener *l) { nni_aio *aio; SOCKET s; @@ -377,10 +358,10 @@ tcp_listener_doaccept(nni_tcp_listener *l) l->running = false; } -void -nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) +static void +tcp_listener_accept(void *arg, nni_aio *aio) { - int rv; + tcp_listener *l = arg; nni_aio_reset(aio); @@ -390,14 +371,17 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) nni_aio_finish_error(aio, NNG_ESTATE); return; } - + if (l->closed) { + nni_mtx_unlock(&l->mtx); + nni_aio_finish_error(aio, NNG_ECLOSED); + return; + } if (!nni_aio_start(aio, tcp_accept_cancel, l)) { nni_mtx_unlock(&l->mtx); return; } nni_aio_list_append(&l->aios, aio); - if (aio == nni_list_first(&l->aios)) { tcp_listener_doaccept(l); } @@ -407,8 +391,8 @@ nni_tcp_listener_accept(nni_tcp_listener *l, nni_aio *aio) static int tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) { - nni_tcp_listener *l = arg; - nng_sockaddr sa; + tcp_listener *l = arg; + nng_sockaddr sa; nni_mtx_lock(&l->mtx); if (l->started) { nni_win_sockaddr2nn(&sa, &l->ss); @@ -422,9 +406,9 @@ tcp_listener_get_locaddr(void *arg, void *buf, size_t *szp, nni_type t) static int tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) { - nni_tcp_listener *l = arg; - int rv; - bool b; + tcp_listener *l = arg; + int rv; + bool b; if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { return (rv); @@ -438,8 +422,8 @@ tcp_listener_set_nodelay(void *arg, const void *buf, size_t sz, nni_type t) static int tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) { - bool b; - nni_tcp_listener *l = arg; + bool b; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); b = l->nodelay; nni_mtx_unlock(&l->mtx); @@ -449,9 +433,9 @@ tcp_listener_get_nodelay(void *arg, void *buf, size_t *szp, nni_type t) static int tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) { - nni_tcp_listener *l = arg; - int rv; - bool b; + tcp_listener *l = arg; + int rv; + bool b; if (((rv = nni_copyin_bool(&b, buf, sz, t)) != 0) || (l == NULL)) { return (rv); @@ -465,14 +449,52 @@ tcp_listener_set_keepalive(void *arg, const void *buf, size_t sz, nni_type t) static int tcp_listener_get_keepalive(void *arg, void *buf, size_t *szp, nni_type t) { - bool b; - nni_tcp_listener *l = arg; + bool b; + tcp_listener *l = arg; nni_mtx_lock(&l->mtx); b = l->keepalive; nni_mtx_unlock(&l->mtx); return (nni_copyout_bool(b, buf, szp, t)); } +static int +tcp_listener_get_port(void *arg, void *buf, size_t *szp, nni_type t) +{ + tcp_listener *l = arg; + int rv; + nng_sockaddr sa; + size_t sz; + int port; + uint8_t *paddr; + + sz = sizeof(sa); + rv = tcp_listener_get_locaddr(l, &sa, &sz, NNI_TYPE_SOCKADDR); + if (rv != 0) { + return (rv); + } + + switch (sa.s_family) { + case NNG_AF_INET: + paddr = (void *) &sa.s_in.sa_port; + break; + + case NNG_AF_INET6: + paddr = (void *) &sa.s_in6.sa_port; + break; + + default: + paddr = NULL; + break; + } + + if (paddr == NULL) { + return (NNG_ESTATE); + } + + NNI_GET16(paddr, port); + return (nni_copyout_int(port, buf, szp, t)); +} + static const nni_option tcp_listener_options[] = { { .o_name = NNG_OPT_LOCADDR, @@ -489,20 +511,77 @@ static const nni_option tcp_listener_options[] = { .o_get = tcp_listener_get_keepalive, }, { + .o_name = NNG_OPT_TCP_BOUND_PORT, + .o_get = tcp_listener_get_port, + }, + { .o_name = NULL, }, }; -int -nni_tcp_listener_get( - nni_tcp_listener *l, const char *name, void *buf, size_t *szp, nni_type t) +static int +tcp_listener_get( + void *arg, const char *name, void *buf, size_t *szp, nni_type t) +{ + return (nni_getopt(tcp_listener_options, name, arg, buf, szp, t)); +} + +static int +tcp_listener_set( + void *arg, const char *name, const void *buf, size_t sz, nni_type t) { - return (nni_getopt(tcp_listener_options, name, l, buf, szp, t)); + return (nni_setopt(tcp_listener_options, name, arg, buf, sz, t)); +} + +static int +tcp_listener_alloc_addr(nng_stream_listener **lp, const nng_sockaddr *sa) +{ + tcp_listener *l; + int rv; + + if ((l = NNI_ALLOC_STRUCT(l)) == NULL) { + return (NNG_ENOMEM); + } + + nni_mtx_init(&l->mtx); + nni_aio_list_init(&l->aios); + nni_win_io_init(&l->accept_io, tcp_accept_cb, l); + if ((rv = tcp_listener_funcs(l)) != 0) { + NNI_FREE_STRUCT(l); + return (rv); + } + + // We assume these defaults -- not everyone will agree, but anyone + // can change them. + l->keepalive = false; + l->nodelay = true; + l->closed = false; + l->started = false; + l->nodelay = true; + l->sa = *sa; + l->accept_rv = 0; + + l->ops.sl_free = tcp_listener_free; + l->ops.sl_close = tcp_listener_close; + l->ops.sl_stop = tcp_listener_stop; + l->ops.sl_listen = tcp_listener_listen; + l->ops.sl_accept = tcp_listener_accept; + l->ops.sl_get = tcp_listener_get; + l->ops.sl_set = tcp_listener_set; + + *lp = (void *) l; + return (0); } int -nni_tcp_listener_set(nni_tcp_listener *l, const char *name, const void *buf, - size_t sz, nni_type t) +nni_tcp_listener_alloc(nng_stream_listener **lp, const nng_url *url) { - return (nni_setopt(tcp_listener_options, name, l, buf, sz, t)); + int rv; + nng_sockaddr sa; + + if ((rv = nni_url_to_address(&sa, url)) != 0) { + return (rv); + } + + return (tcp_listener_alloc_addr(lp, &sa)); } |
