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