summaryrefslogtreecommitdiff
path: root/src/microhttpd/mhd_sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/microhttpd/mhd_sockets.c')
-rw-r--r--src/microhttpd/mhd_sockets.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/microhttpd/mhd_sockets.c b/src/microhttpd/mhd_sockets.c
index 64b45f9c..1023017f 100644
--- a/src/microhttpd/mhd_sockets.c
+++ b/src/microhttpd/mhd_sockets.c
@@ -238,6 +238,86 @@ const char* MHD_W32_strerror_winsock_(int err)
}
+/**
+ * Create pair of mutually connected TCP/IP sockets on loopback address
+ * @param sockets_pair array to receive resulted sockets
+ * @return non-zero if succeeded, zero otherwise
+ */
+int MHD_W32_socket_pair_(SOCKET sockets_pair[2])
+{
+ int i;
+ if (!sockets_pair)
+ {
+ WSASetLastError(WSAEFAULT);
+ return 0;
+ }
+
+#define PAIRMAXTRYIES 800
+ for (i = 0; i < PAIRMAXTRYIES; i++)
+ {
+ struct sockaddr_in listen_addr;
+ SOCKET listen_s;
+ static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */
+ int addr_len = c_addinlen;
+ int opt = 1;
+
+ listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (INVALID_SOCKET == listen_s)
+ break; /* can't create even single socket */
+
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_port = 0; /* same as htons(0) */
+ listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ if (0 == bind(listen_s, (struct sockaddr*) &listen_addr, c_addinlen)
+ && 0 == listen(listen_s, 1)
+ && 0 == getsockname(listen_s, (struct sockaddr*) &listen_addr,
+ &addr_len))
+ {
+ SOCKET client_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (INVALID_SOCKET != client_s)
+ {
+ if (0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
+ && (0 == connect(client_s, (struct sockaddr*) &listen_addr, c_addinlen)
+ || WSAGetLastError() == WSAEWOULDBLOCK))
+ {
+ struct sockaddr_in accepted_from_addr;
+ SOCKET server_s;
+ addr_len = c_addinlen;
+ server_s = accept(listen_s,
+ (struct sockaddr*) &accepted_from_addr, &addr_len);
+ if (INVALID_SOCKET != server_s)
+ {
+ struct sockaddr_in client_addr;
+ addr_len = c_addinlen;
+ opt = 0;
+ if (0 == getsockname(client_s, (struct sockaddr*) &client_addr, &addr_len)
+ && accepted_from_addr.sin_family == client_addr.sin_family
+ && accepted_from_addr.sin_port == client_addr.sin_port
+ && accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr
+ && 0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt)
+ && 0 == ioctlsocket(server_s, FIONBIO, (u_long*) &opt))
+ {
+ closesocket(listen_s);
+ sockets_pair[0] = client_s;
+ sockets_pair[1] = server_s;
+ return !0;
+ }
+ closesocket(server_s);
+ }
+ }
+ closesocket(client_s);
+ }
+ }
+ closesocket(listen_s);
+ }
+
+ sockets_pair[0] = INVALID_SOCKET;
+ sockets_pair[1] = INVALID_SOCKET;
+ WSASetLastError(WSAECONNREFUSED);
+
+ return 0;
+}
+
#endif /* MHD_WINSOCK_SOCKETS */