diff options
Diffstat (limited to 'src/lib/mhd_sockets.c')
-rw-r--r-- | src/lib/mhd_sockets.c | 523 |
1 files changed, 523 insertions, 0 deletions
diff --git a/src/lib/mhd_sockets.c b/src/lib/mhd_sockets.c new file mode 100644 index 00000000..ddcc1f25 --- /dev/null +++ b/src/lib/mhd_sockets.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2014-2016 Karlson2k (Evgeny Grin) | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file microhttpd/mhd_sockets.c | ||
23 | * @brief Implementation for sockets functions | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | ||
26 | |||
27 | #include "mhd_sockets.h" | ||
28 | #ifdef HAVE_UNISTD_H | ||
29 | #include <unistd.h> | ||
30 | #endif /* HAVE_UNISTD_H */ | ||
31 | #include <fcntl.h> | ||
32 | |||
33 | #ifdef MHD_WINSOCK_SOCKETS | ||
34 | |||
35 | /** | ||
36 | * Return pointer to string description of specified WinSock error | ||
37 | * @param err the WinSock error code. | ||
38 | * @return pointer to string description of specified WinSock error. | ||
39 | */ | ||
40 | const char* MHD_W32_strerror_winsock_(int err) | ||
41 | { | ||
42 | switch (err) | ||
43 | { | ||
44 | case 0: | ||
45 | return "No error"; | ||
46 | case WSA_INVALID_HANDLE: | ||
47 | return "Specified event object handle is invalid"; | ||
48 | case WSA_NOT_ENOUGH_MEMORY: | ||
49 | return "Insufficient memory available"; | ||
50 | case WSA_INVALID_PARAMETER: | ||
51 | return "One or more parameters are invalid"; | ||
52 | case WSA_OPERATION_ABORTED: | ||
53 | return "Overlapped operation aborted"; | ||
54 | case WSA_IO_INCOMPLETE: | ||
55 | return "Overlapped I/O event object not in signaled state"; | ||
56 | case WSA_IO_PENDING: | ||
57 | return "Overlapped operations will complete later"; | ||
58 | case WSAEINTR: | ||
59 | return "Interrupted function call"; | ||
60 | case WSAEBADF: | ||
61 | return "File handle is not valid"; | ||
62 | case WSAEACCES: | ||
63 | return "Permission denied"; | ||
64 | case WSAEFAULT: | ||
65 | return "Bad address"; | ||
66 | case WSAEINVAL: | ||
67 | return "Invalid argument"; | ||
68 | case WSAEMFILE: | ||
69 | return "Too many open files"; | ||
70 | case WSAEWOULDBLOCK: | ||
71 | return "Resource temporarily unavailable"; | ||
72 | case WSAEINPROGRESS: | ||
73 | return "Operation now in progress"; | ||
74 | case WSAEALREADY: | ||
75 | return "Operation already in progress"; | ||
76 | case WSAENOTSOCK: | ||
77 | return "Socket operation on nonsocket"; | ||
78 | case WSAEDESTADDRREQ: | ||
79 | return "Destination address required"; | ||
80 | case WSAEMSGSIZE: | ||
81 | return "Message too long"; | ||
82 | case WSAEPROTOTYPE: | ||
83 | return "Protocol wrong type for socket"; | ||
84 | case WSAENOPROTOOPT: | ||
85 | return "Bad protocol option"; | ||
86 | case WSAEPROTONOSUPPORT: | ||
87 | return "Protocol not supported"; | ||
88 | case WSAESOCKTNOSUPPORT: | ||
89 | return "Socket type not supported"; | ||
90 | case WSAEOPNOTSUPP: | ||
91 | return "Operation not supported"; | ||
92 | case WSAEPFNOSUPPORT: | ||
93 | return "Protocol family not supported"; | ||
94 | case WSAEAFNOSUPPORT: | ||
95 | return "Address family not supported by protocol family"; | ||
96 | case WSAEADDRINUSE: | ||
97 | return "Address already in use"; | ||
98 | case WSAEADDRNOTAVAIL: | ||
99 | return "Cannot assign requested address"; | ||
100 | case WSAENETDOWN: | ||
101 | return "Network is down"; | ||
102 | case WSAENETUNREACH: | ||
103 | return "Network is unreachable"; | ||
104 | case WSAENETRESET: | ||
105 | return "Network dropped connection on reset"; | ||
106 | case WSAECONNABORTED: | ||
107 | return "Software caused connection abort"; | ||
108 | case WSAECONNRESET: | ||
109 | return "Connection reset by peer"; | ||
110 | case WSAENOBUFS: | ||
111 | return "No buffer space available"; | ||
112 | case WSAEISCONN: | ||
113 | return "Socket is already connected"; | ||
114 | case WSAENOTCONN: | ||
115 | return "Socket is not connected"; | ||
116 | case WSAESHUTDOWN: | ||
117 | return "Cannot send after socket shutdown"; | ||
118 | case WSAETOOMANYREFS: | ||
119 | return "Too many references"; | ||
120 | case WSAETIMEDOUT: | ||
121 | return "Connection timed out"; | ||
122 | case WSAECONNREFUSED: | ||
123 | return "Connection refused"; | ||
124 | case WSAELOOP: | ||
125 | return "Cannot translate name"; | ||
126 | case WSAENAMETOOLONG: | ||
127 | return "Name too long"; | ||
128 | case WSAEHOSTDOWN: | ||
129 | return "Host is down"; | ||
130 | case WSAEHOSTUNREACH: | ||
131 | return "No route to host"; | ||
132 | case WSAENOTEMPTY: | ||
133 | return "Directory not empty"; | ||
134 | case WSAEPROCLIM: | ||
135 | return "Too many processes"; | ||
136 | case WSAEUSERS: | ||
137 | return "User quota exceeded"; | ||
138 | case WSAEDQUOT: | ||
139 | return "Disk quota exceeded"; | ||
140 | case WSAESTALE: | ||
141 | return "Stale file handle reference"; | ||
142 | case WSAEREMOTE: | ||
143 | return "Item is remote"; | ||
144 | case WSASYSNOTREADY: | ||
145 | return "Network subsystem is unavailable"; | ||
146 | case WSAVERNOTSUPPORTED: | ||
147 | return "Winsock.dll version out of range"; | ||
148 | case WSANOTINITIALISED: | ||
149 | return "Successful WSAStartup not yet performed"; | ||
150 | case WSAEDISCON: | ||
151 | return "Graceful shutdown in progress"; | ||
152 | case WSAENOMORE: | ||
153 | return "No more results"; | ||
154 | case WSAECANCELLED: | ||
155 | return "Call has been canceled"; | ||
156 | case WSAEINVALIDPROCTABLE: | ||
157 | return "Procedure call table is invalid"; | ||
158 | case WSAEINVALIDPROVIDER: | ||
159 | return "Service provider is invalid"; | ||
160 | case WSAEPROVIDERFAILEDINIT: | ||
161 | return "Service provider failed to initialize"; | ||
162 | case WSASYSCALLFAILURE: | ||
163 | return "System call failure"; | ||
164 | case WSASERVICE_NOT_FOUND: | ||
165 | return "Service not found"; | ||
166 | case WSATYPE_NOT_FOUND: | ||
167 | return "Class type not found"; | ||
168 | case WSA_E_NO_MORE: | ||
169 | return "No more results"; | ||
170 | case WSA_E_CANCELLED: | ||
171 | return "Call was canceled"; | ||
172 | case WSAEREFUSED: | ||
173 | return "Database query was refused"; | ||
174 | case WSAHOST_NOT_FOUND: | ||
175 | return "Host not found"; | ||
176 | case WSATRY_AGAIN: | ||
177 | return "Nonauthoritative host not found"; | ||
178 | case WSANO_RECOVERY: | ||
179 | return "This is a nonrecoverable error"; | ||
180 | case WSANO_DATA: | ||
181 | return "Valid name, no data record of requested type"; | ||
182 | case WSA_QOS_RECEIVERS: | ||
183 | return "QoS receivers"; | ||
184 | case WSA_QOS_SENDERS: | ||
185 | return "QoS senders"; | ||
186 | case WSA_QOS_NO_SENDERS: | ||
187 | return "No QoS senders"; | ||
188 | case WSA_QOS_NO_RECEIVERS: | ||
189 | return "QoS no receivers"; | ||
190 | case WSA_QOS_REQUEST_CONFIRMED: | ||
191 | return "QoS request confirmed"; | ||
192 | case WSA_QOS_ADMISSION_FAILURE: | ||
193 | return "QoS admission error"; | ||
194 | case WSA_QOS_POLICY_FAILURE: | ||
195 | return "QoS policy failure"; | ||
196 | case WSA_QOS_BAD_STYLE: | ||
197 | return "QoS bad style"; | ||
198 | case WSA_QOS_BAD_OBJECT: | ||
199 | return "QoS bad object"; | ||
200 | case WSA_QOS_TRAFFIC_CTRL_ERROR: | ||
201 | return "QoS traffic control error"; | ||
202 | case WSA_QOS_GENERIC_ERROR: | ||
203 | return "QoS generic error"; | ||
204 | case WSA_QOS_ESERVICETYPE: | ||
205 | return "QoS service type error"; | ||
206 | case WSA_QOS_EFLOWSPEC: | ||
207 | return "QoS flowspec error"; | ||
208 | case WSA_QOS_EPROVSPECBUF: | ||
209 | return "Invalid QoS provider buffer"; | ||
210 | case WSA_QOS_EFILTERSTYLE: | ||
211 | return "Invalid QoS filter style"; | ||
212 | case WSA_QOS_EFILTERTYPE: | ||
213 | return "Invalid QoS filter type"; | ||
214 | case WSA_QOS_EFILTERCOUNT: | ||
215 | return "Incorrect QoS filter count"; | ||
216 | case WSA_QOS_EOBJLENGTH: | ||
217 | return "Invalid QoS object length"; | ||
218 | case WSA_QOS_EFLOWCOUNT: | ||
219 | return "Incorrect QoS flow count"; | ||
220 | case WSA_QOS_EUNKOWNPSOBJ: | ||
221 | return "Unrecognized QoS object"; | ||
222 | case WSA_QOS_EPOLICYOBJ: | ||
223 | return "Invalid QoS policy object"; | ||
224 | case WSA_QOS_EFLOWDESC: | ||
225 | return "Invalid QoS flow descriptor"; | ||
226 | case WSA_QOS_EPSFLOWSPEC: | ||
227 | return "Invalid QoS provider-specific flowspec"; | ||
228 | case WSA_QOS_EPSFILTERSPEC: | ||
229 | return "Invalid QoS provider-specific filterspec"; | ||
230 | case WSA_QOS_ESDMODEOBJ: | ||
231 | return "Invalid QoS shape discard mode object"; | ||
232 | case WSA_QOS_ESHAPERATEOBJ: | ||
233 | return "Invalid QoS shaping rate object"; | ||
234 | case WSA_QOS_RESERVED_PETYPE: | ||
235 | return "Reserved policy QoS element type"; | ||
236 | } | ||
237 | return "Unknown winsock error"; | ||
238 | } | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Create pair of mutually connected TCP/IP sockets on loopback address | ||
243 | * @param sockets_pair array to receive resulted sockets | ||
244 | * @param non_blk if set to non-zero value, sockets created in non-blocking mode | ||
245 | * otherwise sockets will be in blocking mode | ||
246 | * @return non-zero if succeeded, zero otherwise | ||
247 | */ | ||
248 | int | ||
249 | MHD_W32_socket_pair_(SOCKET sockets_pair[2], int non_blk) | ||
250 | { | ||
251 | int i; | ||
252 | |||
253 | if (! sockets_pair) | ||
254 | { | ||
255 | WSASetLastError (WSAEFAULT); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | #define PAIRMAXTRYIES 800 | ||
260 | for (i = 0; i < PAIRMAXTRYIES; i++) | ||
261 | { | ||
262 | struct sockaddr_in listen_addr; | ||
263 | SOCKET listen_s; | ||
264 | static const int c_addinlen = sizeof(struct sockaddr_in); /* help compiler to optimize */ | ||
265 | int addr_len = c_addinlen; | ||
266 | unsigned long on_val = 1; | ||
267 | unsigned long off_val = 0; | ||
268 | |||
269 | listen_s = socket (AF_INET, | ||
270 | SOCK_STREAM, | ||
271 | IPPROTO_TCP); | ||
272 | if (INVALID_SOCKET == listen_s) | ||
273 | break; /* can't create even single socket */ | ||
274 | |||
275 | listen_addr.sin_family = AF_INET; | ||
276 | listen_addr.sin_port = 0; /* same as htons(0) */ | ||
277 | listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
278 | if ( (0 == bind (listen_s, | ||
279 | (struct sockaddr*) &listen_addr, | ||
280 | c_addinlen) && | ||
281 | (0 == listen (listen_s, | ||
282 | 1) ) && | ||
283 | (0 == getsockname (listen_s, | ||
284 | (struct sockaddr*) &listen_addr, | ||
285 | &addr_len))) ) | ||
286 | { | ||
287 | SOCKET client_s = socket(AF_INET, | ||
288 | SOCK_STREAM, | ||
289 | IPPROTO_TCP); | ||
290 | struct sockaddr_in accepted_from_addr; | ||
291 | struct sockaddr_in client_addr; | ||
292 | SOCKET server_s; | ||
293 | |||
294 | if (INVALID_SOCKET == client_s) | ||
295 | { | ||
296 | /* try again */ | ||
297 | closesocket (listen_s); | ||
298 | continue; | ||
299 | } | ||
300 | |||
301 | if ( (0 != ioctlsocket (client_s, | ||
302 | FIONBIO, | ||
303 | &on_val)) || | ||
304 | ( (0 != connect (client_s, | ||
305 | (struct sockaddr*) &listen_addr, | ||
306 | c_addinlen)) && | ||
307 | (WSAGetLastError() != WSAEWOULDBLOCK)) ) | ||
308 | { | ||
309 | /* try again */ | ||
310 | closesocket (listen_s); | ||
311 | closesocket (client_s); | ||
312 | continue; | ||
313 | } | ||
314 | |||
315 | addr_len = c_addinlen; | ||
316 | server_s = accept (listen_s, | ||
317 | (struct sockaddr*) &accepted_from_addr, | ||
318 | &addr_len); | ||
319 | if (INVALID_SOCKET == server_s) | ||
320 | { | ||
321 | /* try again */ | ||
322 | closesocket (listen_s); | ||
323 | closesocket (client_s); | ||
324 | continue; | ||
325 | } | ||
326 | |||
327 | addr_len = c_addinlen; | ||
328 | if ( (0 == getsockname (client_s, | ||
329 | (struct sockaddr*) &client_addr, | ||
330 | &addr_len)) && | ||
331 | (accepted_from_addr.sin_family == client_addr.sin_family) && | ||
332 | (accepted_from_addr.sin_port == client_addr.sin_port) && | ||
333 | (accepted_from_addr.sin_addr.s_addr == client_addr.sin_addr.s_addr) && | ||
334 | ( (0 != non_blk) ? | ||
335 | (0 == ioctlsocket(server_s, | ||
336 | FIONBIO, | ||
337 | &on_val)) : | ||
338 | (0 == ioctlsocket(client_s, | ||
339 | FIONBIO, | ||
340 | &off_val)) ) ) | ||
341 | { | ||
342 | closesocket (listen_s); | ||
343 | sockets_pair[0] = server_s; | ||
344 | sockets_pair[1] = client_s; | ||
345 | return !0; | ||
346 | } | ||
347 | closesocket (server_s); | ||
348 | closesocket (client_s); | ||
349 | } | ||
350 | closesocket(listen_s); | ||
351 | } | ||
352 | |||
353 | sockets_pair[0] = INVALID_SOCKET; | ||
354 | sockets_pair[1] = INVALID_SOCKET; | ||
355 | WSASetLastError(WSAECONNREFUSED); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
361 | |||
362 | |||
363 | /** | ||
364 | * Add @a fd to the @a set. If @a fd is | ||
365 | * greater than @a max_fd, set @a max_fd to @a fd. | ||
366 | * | ||
367 | * @param fd file descriptor to add to the @a set | ||
368 | * @param set set to modify | ||
369 | * @param max_fd maximum value to potentially update | ||
370 | * @param fd_setsize value of FD_SETSIZE | ||
371 | * @return non-zero if succeeded, zero otherwise | ||
372 | */ | ||
373 | int | ||
374 | MHD_add_to_fd_set_ (MHD_socket fd, | ||
375 | fd_set *set, | ||
376 | MHD_socket *max_fd, | ||
377 | unsigned int fd_setsize) | ||
378 | { | ||
379 | if ( (NULL == set) || | ||
380 | (MHD_INVALID_SOCKET == fd) ) | ||
381 | return 0; | ||
382 | if (! MHD_SCKT_FD_FITS_FDSET_SETSIZE_ (fd, | ||
383 | set, | ||
384 | fd_setsize)) | ||
385 | return 0; | ||
386 | MHD_SCKT_ADD_FD_TO_FDSET_SETSIZE_(fd, | ||
387 | set, | ||
388 | fd_setsize); | ||
389 | if ( (NULL != max_fd) && | ||
390 | ( (fd > *max_fd) || | ||
391 | (MHD_INVALID_SOCKET == *max_fd) ) ) | ||
392 | *max_fd = fd; | ||
393 | return ! 0; | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Change socket options to be non-blocking. | ||
399 | * | ||
400 | * @param sock socket to manipulate | ||
401 | * @return non-zero if succeeded, zero otherwise | ||
402 | */ | ||
403 | int | ||
404 | MHD_socket_nonblocking_ (MHD_socket sock) | ||
405 | { | ||
406 | #if defined(MHD_POSIX_SOCKETS) | ||
407 | int flags; | ||
408 | |||
409 | flags = fcntl (sock, | ||
410 | F_GETFL); | ||
411 | if (-1 == flags) | ||
412 | return 0; | ||
413 | |||
414 | if ( ((flags | O_NONBLOCK) != flags) && | ||
415 | (0 != fcntl (sock, | ||
416 | F_SETFL, | ||
417 | flags | O_NONBLOCK)) ) | ||
418 | return 0; | ||
419 | #elif defined(MHD_WINSOCK_SOCKETS) | ||
420 | unsigned long flags = 1; | ||
421 | |||
422 | if (0 != ioctlsocket (sock, | ||
423 | FIONBIO, | ||
424 | &flags)) | ||
425 | return 0; | ||
426 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
427 | return !0; | ||
428 | } | ||
429 | |||
430 | |||
431 | /** | ||
432 | * Change socket options to be non-inheritable. | ||
433 | * | ||
434 | * @param sock socket to manipulate | ||
435 | * @return non-zero if succeeded, zero otherwise | ||
436 | * @warning Does not set socket error on W32. | ||
437 | */ | ||
438 | int | ||
439 | MHD_socket_noninheritable_ (MHD_socket sock) | ||
440 | { | ||
441 | #if defined(MHD_POSIX_SOCKETS) | ||
442 | int flags; | ||
443 | |||
444 | flags = fcntl (sock, | ||
445 | F_GETFD); | ||
446 | if (-1 == flags) | ||
447 | return 0; | ||
448 | |||
449 | if ( ((flags | FD_CLOEXEC) != flags) && | ||
450 | (0 != fcntl (sock, | ||
451 | F_SETFD, | ||
452 | flags | FD_CLOEXEC)) ) | ||
453 | return 0; | ||
454 | #elif defined(MHD_WINSOCK_SOCKETS) | ||
455 | if (! SetHandleInformation ((HANDLE)sock, | ||
456 | HANDLE_FLAG_INHERIT, | ||
457 | 0)) | ||
458 | return 0; | ||
459 | #endif /* MHD_WINSOCK_SOCKETS */ | ||
460 | return !0; | ||
461 | } | ||
462 | |||
463 | |||
464 | /** | ||
465 | * Create a listen socket, with noninheritable flag if possible. | ||
466 | * | ||
467 | * @param use_ipv6 if set to non-zero IPv6 is used | ||
468 | * @return created socket or MHD_INVALID_SOCKET in case of errors | ||
469 | */ | ||
470 | MHD_socket | ||
471 | MHD_socket_create_listen_ (bool use_ipv6) | ||
472 | { | ||
473 | int domain; | ||
474 | MHD_socket fd; | ||
475 | int cloexec_set; | ||
476 | |||
477 | #ifdef HAVE_INET6 | ||
478 | domain = (use_ipv6) ? PF_INET6 : PF_INET; | ||
479 | #else /* ! HAVE_INET6 */ | ||
480 | if (use_ipv6) | ||
481 | return MHD_INVALID_SOCKET; | ||
482 | domain = PF_INET; | ||
483 | #endif /* ! HAVE_INET6 */ | ||
484 | |||
485 | #if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC) | ||
486 | fd = socket (domain, | ||
487 | SOCK_STREAM | SOCK_CLOEXEC, | ||
488 | 0); | ||
489 | cloexec_set = !0; | ||
490 | #elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT) | ||
491 | fd = WSASocketW (domain, | ||
492 | SOCK_STREAM, | ||
493 | 0, | ||
494 | NULL, | ||
495 | 0, | ||
496 | WSA_FLAG_NO_HANDLE_INHERIT); | ||
497 | cloexec_set = !0; | ||
498 | #else /* !SOCK_CLOEXEC */ | ||
499 | fd = MHD_INVALID_SOCKET; | ||
500 | #endif /* !SOCK_CLOEXEC */ | ||
501 | if (MHD_INVALID_SOCKET == fd) | ||
502 | { | ||
503 | fd = socket (domain, | ||
504 | SOCK_STREAM, | ||
505 | 0); | ||
506 | cloexec_set = 0; | ||
507 | } | ||
508 | if (MHD_INVALID_SOCKET == fd) | ||
509 | return MHD_INVALID_SOCKET; | ||
510 | #ifdef MHD_socket_nosignal_ | ||
511 | if(! MHD_socket_nosignal_(fd)) | ||
512 | { | ||
513 | const int err = MHD_socket_get_error_ (); | ||
514 | (void) MHD_socket_close_ (fd); | ||
515 | MHD_socket_fset_error_ (err); | ||
516 | return MHD_INVALID_SOCKET; | ||
517 | } | ||
518 | #endif /* MHD_socket_nosignal_ */ | ||
519 | if (! cloexec_set) | ||
520 | (void) MHD_socket_noninheritable_ (fd); | ||
521 | |||
522 | return fd; | ||
523 | } | ||