diff options
Diffstat (limited to 'src/microhttpd/mhd_sockets.c')
-rw-r--r-- | src/microhttpd/mhd_sockets.c | 80 |
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 */ |