aboutsummaryrefslogtreecommitdiff
path: root/src/lib/mhd_sockets.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/mhd_sockets.c')
-rw-r--r--src/lib/mhd_sockets.c523
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 */
40const 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 */
248int
249MHD_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 */
373int
374MHD_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 */
403int
404MHD_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 */
438int
439MHD_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 */
470MHD_socket
471MHD_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}