aboutsummaryrefslogtreecommitdiff
path: root/src/platform/windows/win_tcp.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-12-28 16:10:48 -0800
committerGarrett D'Amore <garrett@damore.org>2024-12-28 16:24:49 -0800
commit6a414614d906999bd4eb6e9b2f96ca972b437ffc (patch)
tree6454a86b9c23a38056c72260e8d1e7d6fba38c8a /src/platform/windows/win_tcp.c
parent7b5515ca641f475dce8184a5d9fd67ceb860e843 (diff)
downloadnng-6a414614d906999bd4eb6e9b2f96ca972b437ffc.tar.gz
nng-6a414614d906999bd4eb6e9b2f96ca972b437ffc.tar.bz2
nng-6a414614d906999bd4eb6e9b2f96ca972b437ffc.zip
windows tcp: Lookup extended TCP function pointers at startup
This avoids the need for a lock during listener or dialer initialization, and it avoids the need to carry these pointers on those objects. It also eliminates a potential failure case "post startup".
Diffstat (limited to 'src/platform/windows/win_tcp.c')
-rw-r--r--src/platform/windows/win_tcp.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c
index 2ab6be0f..42667dea 100644
--- a/src/platform/windows/win_tcp.c
+++ b/src/platform/windows/win_tcp.c
@@ -1,5 +1,5 @@
//
-// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+// Copyright 2024 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
@@ -15,18 +15,87 @@
#include <malloc.h>
#include <stdio.h>
+static LPFN_ACCEPTEX acceptex;
+static LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs;
+static LPFN_CONNECTEX connectex;
+
int
nni_win_tcp_sysinit(void)
{
+ int rv;
+
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()));
}
+
+ DWORD nbytes;
+ GUID guid1 = WSAID_ACCEPTEX;
+ GUID guid2 = WSAID_GETACCEPTEXSOCKADDRS;
+ GUID guid3 = WSAID_CONNECTEX;
+
+ SOCKET s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+ if (s == INVALID_SOCKET) {
+ rv = nni_win_error(GetLastError());
+ WSACleanup();
+ return (rv);
+ }
+ if ((WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid1,
+ sizeof(guid1), &acceptex, sizeof(acceptex), &nbytes, NULL,
+ NULL) == SOCKET_ERROR) ||
+ (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid2,
+ sizeof(guid2), &getacceptexsockaddrs,
+ sizeof(getacceptexsockaddrs), &nbytes, NULL,
+ NULL) == SOCKET_ERROR) ||
+ (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid3,
+ sizeof(guid3), &connectex, sizeof(connectex), &nbytes, NULL,
+ NULL) == SOCKET_ERROR)) {
+ rv = nni_win_error(GetLastError());
+ closesocket(s);
+ WSACleanup();
+ return (rv);
+ }
+
+ closesocket(s);
return (0);
}
+int
+nni_win_acceptex(SOCKET listen, SOCKET child, void *buf, LPOVERLAPPED olpd)
+{
+ DWORD cnt = 0;
+ return (acceptex(listen, child, buf, 0, 256, 256, &cnt, olpd));
+}
+
+// This is called after a socket is accepted for the connection, and the buffer
+// contains the peers socket addresses. It is is kind of weird, windows
+// specific, and must be called only after acceptex. The caller should call
+// setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT) after calling this.
+void
+nni_win_get_acceptex_sockaddrs(
+ void *buf, SOCKADDR_STORAGE *self, SOCKADDR_STORAGE *peer)
+{
+ SOCKADDR *self_p;
+ SOCKADDR *peer_p;
+ int self_len;
+ int peer_len;
+
+ getacceptexsockaddrs(
+ buf, 0, 256, 256, &self_p, &self_len, &peer_p, &peer_len);
+
+ (void) memcpy(self, self_p, self_len);
+ (void) memcpy(peer, peer_p, peer_len);
+}
+
+int
+nni_win_connectex(SOCKET s, SOCKADDR *peer, int peer_len, LPOVERLAPPED olpd)
+{
+ return (connectex(s, peer, peer_len, NULL, 0, NULL, olpd));
+}
+
void
nni_win_tcp_sysfini(void)
{