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) | |||
238 | } | 238 | } |
239 | 239 | ||
240 | 240 | ||
241 | /** | ||
242 | * Create pair of mutually connected TCP/IP sockets on loopback address | ||
243 | * @param sockets_pair array to receive resulted sockets | ||
244 | * @return non-zero if succeeded, zero otherwise | ||
245 | */ | ||
246 | int MHD_W32_socket_pair_(SOCKET sockets_pair[2]) | ||
247 | { | ||
248 | int i; | ||
249 | if (!sockets_pair) | ||
250 | { | ||
251 | WSASetLastError(WSAEFAULT); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | #define PAIRMAXTRYIES 800 | ||
256 | for (i = 0; i < PAIRMAXTRYIES; i++) | ||
257 | { | ||
258 | struct sockaddr_in listen_addr; | ||
259 | SOCKET listen_s; | ||
260 | static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */ | ||
261 | int addr_len = c_addinlen; | ||
262 | int opt = 1; | ||
263 | |||
264 | listen_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
265 | if (INVALID_SOCKET == listen_s) | ||
266 | break; /* can't create even single socket */ | ||
267 | |||
268 | listen_addr.sin_family = AF_INET; | ||
269 | listen_addr.sin_port = 0; /* same as htons(0) */ | ||
270 | listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
271 | if (0 == bind(listen_s, (struct sockaddr*) &listen_addr, c_addinlen) | ||
272 | && 0 == listen(listen_s, 1) | ||
273 | && 0 == getsockname(listen_s, (struct sockaddr*) &listen_addr, | ||
274 | &addr_len)) | ||
275 | { | ||
276 | SOCKET client_s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
277 | if (INVALID_SOCKET != client_s) | ||
278 | { | ||
279 | if (0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt) | ||
280 | && (0 == connect(client_s, (struct sockaddr*) &listen_addr, c_addinlen) | ||
281 | || WSAGetLastError() == WSAEWOULDBLOCK)) | ||
282 | { | ||
283 | struct sockaddr_in accepted_from_addr; | ||
284 | SOCKET server_s; | ||
285 | addr_len = c_addinlen; | ||
286 | server_s = accept(listen_s, | ||
287 | (struct sockaddr*) &accepted_from_addr, &addr_len); | ||
288 | if (INVALID_SOCKET != server_s) | ||
289 | { | ||
290 | struct sockaddr_in client_addr; | ||
291 | addr_len = c_addinlen; | ||
292 | opt = 0; | ||
293 | if (0 == getsockname(client_s, (struct sockaddr*) &client_addr, &addr_len) | ||
294 | && accepted_from_addr.sin_family == client_addr.sin_family | ||
295 | && accepted_from_addr.sin_port == client_addr.sin_port | ||
296 | && accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr | ||
297 | && 0 == ioctlsocket(client_s, FIONBIO, (u_long*) &opt) | ||
298 | && 0 == ioctlsocket(server_s, FIONBIO, (u_long*) &opt)) | ||
299 | { | ||
300 | closesocket(listen_s); | ||
301 | sockets_pair[0] = client_s; | ||
302 | sockets_pair[1] = server_s; | ||
303 | return !0; | ||
304 | } | ||
305 | closesocket(server_s); | ||
306 | } | ||
307 | } | ||
308 | closesocket(client_s); | ||
309 | } | ||
310 | } | ||
311 | closesocket(listen_s); | ||
312 | } | ||
313 | |||
314 | sockets_pair[0] = INVALID_SOCKET; | ||
315 | sockets_pair[1] = INVALID_SOCKET; | ||
316 | WSASetLastError(WSAECONNREFUSED); | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
241 | #endif /* MHD_WINSOCK_SOCKETS */ | 321 | #endif /* MHD_WINSOCK_SOCKETS */ |
242 | 322 | ||
243 | 323 | ||