diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/core/options.c | 2 | ||||
| -rw-r--r-- | src/platform/windows/win_impl.h | 6 | ||||
| -rw-r--r-- | src/platform/windows/win_sockaddr.c | 67 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.c (renamed from src/platform/windows/win_net.c) | 30 | ||||
| -rw-r--r-- | src/platform/windows/win_thread.c | 16 | ||||
| -rw-r--r-- | src/platform/windows/win_udp.c | 303 |
7 files changed, 389 insertions, 41 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 17b14d2e..ffcb2b7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -133,12 +133,14 @@ if (NNG_PLATFORM_WINDOWS) platform/windows/win_debug.c platform/windows/win_iocp.c platform/windows/win_ipc.c - platform/windows/win_net.c platform/windows/win_pipe.c platform/windows/win_rand.c platform/windows/win_resolv.c + platform/windows/win_sockaddr.c + platform/windows/win_tcp.c platform/windows/win_thread.c - ) + platform/windows/win_udp.c + ) endif() if (NNG_ENABLE_ZEROTIER) diff --git a/src/core/options.c b/src/core/options.c index d08ac1cb..aa744642 100644 --- a/src/core/options.c +++ b/src/core/options.c @@ -149,7 +149,7 @@ nni_getopt_int(int i, void *val, size_t *sizep) } int -nni_getopt_u64(const uint64_t u, void *val, size_t *sizep) +nni_getopt_u64(uint64_t u, void *val, size_t *sizep) { size_t sz = sizeof(u); diff --git a/src/platform/windows/win_impl.h b/src/platform/windows/win_impl.h index d1c5b2a2..c2549266 100644 --- a/src/platform/windows/win_impl.h +++ b/src/platform/windows/win_impl.h @@ -93,9 +93,15 @@ extern void nni_win_ipc_sysfini(void); extern int nni_win_tcp_sysinit(void); extern void nni_win_tcp_sysfini(void); +extern int nni_win_udp_sysinit(void); +extern void nni_win_udp_sysfini(void); + extern int nni_win_resolv_sysinit(void); extern void nni_win_resolv_sysfini(void); +extern int nni_win_sockaddr2nn(nni_sockaddr *, const SOCKADDR_STORAGE *); +extern int nni_win_nn2sockaddr(SOCKADDR_STORAGE *, const nni_sockaddr *); + #endif // NNG_PLATFORM_WINDOWS #endif // PLATFORM_WIN_IMPL_H diff --git a/src/platform/windows/win_sockaddr.c b/src/platform/windows/win_sockaddr.c new file mode 100644 index 00000000..0fa6dd51 --- /dev/null +++ b/src/platform/windows/win_sockaddr.c @@ -0,0 +1,67 @@ +// +// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2017 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" + +#ifdef NNG_PLATFORM_WINDOWS + +#include <string.h> + +int +nni_win_nn2sockaddr(SOCKADDR_STORAGE *ss, const nni_sockaddr *sa) +{ + SOCKADDR_IN * sin; + SOCKADDR_IN6 *sin6; + + switch (sa->s_un.s_family) { + case NNG_AF_INET: + sin = (void *) ss; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = PF_INET; + sin->sin_port = sa->s_un.s_in.sa_port; + sin->sin_addr.s_addr = sa->s_un.s_in.sa_addr; + return (sizeof(*sin)); + + case NNG_AF_INET6: + sin6 = (void *) ss; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = PF_INET6; + sin6->sin6_port = sa->s_un.s_in6.sa_port; + memcpy(sin6->sin6_addr.s6_addr, sa->s_un.s_in6.sa_addr, 16); + return (sizeof(*sin6)); + } + return (-1); +} + +int +nni_win_sockaddr2nn(nni_sockaddr *sa, const SOCKADDR_STORAGE *ss) +{ + SOCKADDR_IN * sin; + SOCKADDR_IN6 *sin6; + + switch (ss->ss_family) { + case PF_INET: + sin = (void *) ss; + sa->s_un.s_in.sa_family = NNG_AF_INET; + sa->s_un.s_in.sa_port = sin->sin_port; + sa->s_un.s_in.sa_addr = sin->sin_addr.s_addr; + return (0); + + case PF_INET6: + sin6 = (void *) ss; + sa->s_un.s_in6.sa_family = NNG_AF_INET6; + sa->s_un.s_in6.sa_port = sin6->sin6_port; + memcpy(sa->s_un.s_in6.sa_addr, sin6->sin6_addr.s6_addr, 16); + return (0); + } + return (-1); +} + +#endif // NNG_PLATFORM_WINDOWS
\ No newline at end of file diff --git a/src/platform/windows/win_net.c b/src/platform/windows/win_tcp.c index 07c30e11..d34ef7a6 100644 --- a/src/platform/windows/win_net.c +++ b/src/platform/windows/win_tcp.c @@ -93,32 +93,6 @@ nni_win_tcp_sockinit(SOCKET s) } static int -nni_win_tcp_addr(SOCKADDR_STORAGE *ss, const nni_sockaddr *sa) -{ - SOCKADDR_IN * sin; - SOCKADDR_IN6 *sin6; - - switch (sa->s_un.s_family) { - case NNG_AF_INET: - sin = (void *) ss; - memset(sin, 0, sizeof(*sin)); - sin->sin_family = PF_INET; - sin->sin_port = sa->s_un.s_in.sa_port; - sin->sin_addr.s_addr = sa->s_un.s_in.sa_addr; - return (sizeof(*sin)); - - case NNG_AF_INET6: - sin6 = (void *) ss; - memset(sin6, 0, sizeof(*sin6)); - sin6->sin6_family = PF_INET6; - sin6->sin6_port = sa->s_un.s_in6.sa_port; - memcpy(sin6->sin6_addr.s6_addr, sa->s_un.s_in6.sa_addr, 16); - return (sizeof(*sin6)); - } - return (-1); -} - -static int nni_win_tcp_pipe_start(nni_win_event *evt, nni_aio *aio) { int rv; @@ -303,10 +277,10 @@ nni_plat_tcp_ep_init(nni_plat_tcp_ep **epp, const nni_sockaddr *lsa, ep->s = INVALID_SOCKET; if (rsa->s_un.s_family != NNG_AF_UNSPEC) { - ep->remlen = nni_win_tcp_addr(&ep->remaddr, rsa); + ep->remlen = nni_win_nn2sockaddr(&ep->remaddr, rsa); } if (lsa->s_un.s_family != NNG_AF_UNSPEC) { - ep->loclen = nni_win_tcp_addr(&ep->locaddr, lsa); + ep->loclen = nni_win_nn2sockaddr(&ep->locaddr, lsa); } // Create a scratch socket for use with ioctl. diff --git a/src/platform/windows/win_thread.c b/src/platform/windows/win_thread.c index 12049139..41ba721c 100644 --- a/src/platform/windows/win_thread.c +++ b/src/platform/windows/win_thread.c @@ -154,16 +154,11 @@ nni_plat_init(int (*helper)(void)) AcquireSRWLockExclusive(&lock); if (!plat_inited) { - if ((rv = nni_win_iocp_sysinit()) != 0) { - goto out; - } - if ((rv = nni_win_ipc_sysinit()) != 0) { - goto out; - } - if ((rv = nni_win_tcp_sysinit()) != 0) { - goto out; - } - if ((rv = nni_win_resolv_sysinit()) != 0) { + if (((rv = nni_win_iocp_sysinit()) != 0) || + ((rv = nni_win_ipc_sysinit()) != 0) || + ((rv = nni_win_tcp_sysinit()) != 0) || + ((rv = nni_win_udp_sysinit()) != 0) || + ((rv = nni_win_resolv_sysinit()) != 0)) { goto out; } @@ -182,6 +177,7 @@ nni_plat_fini(void) { nni_win_resolv_sysfini(); nni_win_ipc_sysfini(); + nni_win_udp_sysfini(); nni_win_tcp_sysfini(); nni_win_iocp_sysfini(); WSACleanup(); diff --git a/src/platform/windows/win_udp.c b/src/platform/windows/win_udp.c new file mode 100644 index 00000000..678b4ae7 --- /dev/null +++ b/src/platform/windows/win_udp.c @@ -0,0 +1,303 @@ +// +// Copyright 2017 Garrett D'Amore <garrett@damore.org> +// Copyright 2017 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. +// + +// Silence complaints about inet_addr() +#define _WINSOCK_DEPRECATED_NO_WARNINGS 1 + +#include "core/nng_impl.h" + +#ifdef NNG_PLATFORM_WINDOWS + +#include <stdio.h> + +struct nni_plat_udp { + SOCKET s; + nni_mtx lk; + nni_win_event rxev; + nni_win_event txev; + SOCKADDR_STORAGE rxsa; + SOCKADDR_STORAGE txsa; + int rxsalen; + int txsalen; +}; + +static int nni_win_udp_start_rx(nni_win_event *, nni_aio *); +static int nni_win_udp_start_tx(nni_win_event *, nni_aio *); +static void nni_win_udp_finish_rx(nni_win_event *, nni_aio *); +static void nni_win_udp_finish_tx(nni_win_event *, nni_aio *); +static void nni_win_udp_cancel(nni_win_event *); + +static nni_win_event_ops nni_win_udp_rxo = { + .wev_start = nni_win_udp_start_rx, + .wev_finish = nni_win_udp_finish_rx, + .wev_cancel = nni_win_udp_cancel, +}; + +static nni_win_event_ops nni_win_udp_txo = { + .wev_start = nni_win_udp_start_tx, + .wev_finish = nni_win_udp_finish_tx, + .wev_cancel = nni_win_udp_cancel, +}; + +// nni_plat_udp_open initializes a UDP socket, binding to the local +// address specified specified in the AIO. The remote address is +// not used. The resulting nni_plat_udp structure is returned in the +// the aio's a_pipe. +int +nni_plat_udp_open(nni_plat_udp **udpp, nni_sockaddr *sa) +{ + nni_plat_udp * u; + SOCKADDR_STORAGE ss; + int sslen; + DWORD no; + int rv; + + if ((sslen = nni_win_nn2sockaddr(&ss, sa)) < 0) { + return (NNG_EADDRINVAL); + } + + if ((u = NNI_ALLOC_STRUCT(u)) == NULL) { + return (NNG_ENOMEM); + } + nni_mtx_init(&u->lk); + + u->s = socket(ss.ss_family, SOCK_DGRAM, IPPROTO_UDP); + if (u->s == INVALID_SOCKET) { + rv = nni_win_error(GetLastError()); + nni_plat_udp_close(u); + return (rv); + } + // Don't inherit the handle (CLOEXEC really). + SetHandleInformation((HANDLE) u->s, HANDLE_FLAG_INHERIT, 0); + no = 0; + (void) setsockopt( + u->s, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &no, sizeof(no)); + + if (((rv = nni_win_event_init(&u->rxev, &nni_win_udp_rxo, u)) != 0) || + ((rv = nni_win_event_init(&u->txev, &nni_win_udp_txo, u)) != 0) || + ((rv = nni_win_iocp_register((HANDLE) u->s)) != 0)) { + nni_plat_udp_close(u); + return (rv); + } + + // Bind the local address + if (bind(u->s, (struct sockaddr *) &ss, sslen) == SOCKET_ERROR) { + rv = nni_win_error(GetLastError()); + nni_plat_udp_close(u); + return (rv); + } + + *udpp = u; + return (rv); +} + +// nni_plat_udp_close closes the underlying UDP socket. +void +nni_plat_udp_close(nni_plat_udp *u) +{ + if (u->s != INVALID_SOCKET) { + closesocket(u->s); + } + nni_win_event_fini(&u->rxev); + nni_win_event_fini(&u->txev); + nni_mtx_fini(&u->lk); + NNI_FREE_STRUCT(u); +} + +// nni_plat_udp_send sends the data in the aio to the the +// destination specified in the nni_aio. The iovs are the +// UDP payload. +void +nni_plat_udp_send(nni_plat_udp *u, nni_aio *aio) +{ + nni_win_event_submit(&u->txev, aio); +} + +// nni_plat_udp_pipe_recv recvs a message, storing it in the iovs +// from the UDP payload. If the UDP payload will not fit, then +// NNG_EMSGSIZE results. +void +nni_plat_udp_recv(nni_plat_udp *u, nni_aio *aio) +{ + nni_win_event_submit(&u->rxev, aio); +} + +static int +nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) +{ + int rv; + SOCKET s; + WSABUF iov[4]; + DWORD niov; + DWORD flags; + nni_plat_udp *u = evt->ptr; + + if ((s = u->s) == INVALID_SOCKET) { + evt->status = NNG_ECLOSED; + evt->count = 0; + return (1); + } + + 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; + + // 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; + } + + // Note that the IOVs for the event were prepared on entry + // already. The actual aio's iov array we don't touch. + + evt->count = 0; + flags = 0; + + rv = WSARecvFrom(u->s, iov, niov, NULL, &flags, + (struct sockaddr *) &u->rxsa, &u->rxsalen, &evt->olpd, NULL); + + if ((rv == SOCKET_ERROR) && + ((rv = GetLastError()) != ERROR_IO_PENDING)) { + // Synchronous failure. + evt->status = nni_win_error(rv); + evt->count = 0; + return (1); + } + + // Wait for the I/O completion event. Note that when an I/O + // completes immediately, the I/O completion packet is still + // delivered. + return (0); +} + +static int +nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) +{ + int rv; + SOCKET s; + WSABUF iov[4]; + DWORD niov; + nni_plat_udp *u = evt->ptr; + int salen; + + if ((s = u->s) == INVALID_SOCKET) { + evt->status = NNG_ECLOSED; + evt->count = 0; + return (1); + } + + if ((salen = nni_win_nn2sockaddr(&u->txsa, aio->a_addr)) < 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; + + // 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; + } + + // Note that the IOVs for the event were prepared on entry + // already. The actual aio's iov array we don't touch. + + evt->count = 0; + + rv = WSASendTo(u->s, iov, niov, NULL, 0, (struct sockaddr *) &u->txsa, + salen, &evt->olpd, NULL); + + if ((rv == SOCKET_ERROR) && + ((rv = GetLastError()) != ERROR_IO_PENDING)) { + // Synchronous failure. + evt->status = nni_win_error(rv); + evt->count = 0; + return (1); + } + + // Wait for the I/O completion event. Note that when an I/O + // completes immediately, the I/O completion packet is still + // delivered. + return (0); +} + +static void +nni_win_udp_cancel(nni_win_event *evt) +{ + nni_plat_udp *u = evt->ptr; + + (void) CancelIoEx((HANDLE) u->s, &evt->olpd); +} + +static void +nni_win_udp_finish_rx(nni_win_event *evt, nni_aio *aio) +{ + int rv; + size_t cnt; + nni_plat_udp *u = evt->ptr; + + cnt = evt->count; + if ((rv = evt->status) == 0) { + // convert address from Windows form... + if (aio->a_addr != NULL) { + if (nni_win_sockaddr2nn(aio->a_addr, &u->rxsa) != 0) { + rv = NNG_EADDRINVAL; + cnt = 0; + } + } + } + + // All done; hopefully successfully. + nni_aio_finish(aio, rv, cnt); +} + +static void +nni_win_udp_finish_tx(nni_win_event *evt, nni_aio *aio) +{ + int rv; + size_t cnt; + + cnt = evt->count; + rv = evt->status; + + nni_aio_finish(aio, rv, cnt); +} + +int +nni_win_udp_sysinit(void) +{ + WSADATA data; + if (WSAStartup(MAKEWORD(2, 2), &data) != 0) { + NNI_ASSERT(LOBYTE(data.wVersion) == 2); + NNI_ASSERT(HIBYTE(data.wVersion) == 2); + return (nni_win_error(GetLastError())); + } + return (0); +} + +void +nni_win_udp_sysfini(void) +{ + WSACleanup(); +} + +#endif // NNG_PLATFORM_WINDOWS |
