mhd_sockets_funcs.c (8797B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2014-2024 Karlson2k (Evgeny Grin) 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/mhd_sockets_funcs.c 41 * @brief Implementations of sockets manipulating functions 42 * @author Karlson2k (Evgeny Grin) 43 */ 44 #include "mhd_sys_options.h" 45 #include "sys_sockets_types.h" 46 #include "mhd_sockets_funcs.h" 47 #include "sys_sockets_headers.h" 48 #include "sys_ip_headers.h" 49 #ifdef MHD_SOCKETS_KIND_POSIX 50 # ifdef HAVE_SYS_TYPES_H 51 # include <sys/types.h> 52 # endif 53 # ifdef HAVE_UNISTD_H 54 # include <unistd.h> 55 # else 56 # include <stdlib.h> 57 # endif 58 # include <fcntl.h> 59 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 60 # include <windows.h> 61 #endif 62 #ifndef INADDR_LOOPBACK 63 # include <string.h> /* For memcpy() */ 64 #endif 65 66 #include "mhd_sockets_macros.h" 67 68 69 MHD_INTERNAL bool 70 mhd_socket_nonblocking (MHD_Socket sckt) 71 { 72 #if defined(MHD_SOCKETS_KIND_POSIX) 73 // TODO: detect constants in configure 74 # if defined(F_GETFL) && defined(O_NONBLOCK) && defined(F_SETFL) 75 int get_flags; 76 int set_flags; 77 78 get_flags = fcntl (sckt, F_GETFL); 79 if (0 > get_flags) 80 return false; 81 82 set_flags = (get_flags | O_NONBLOCK); 83 if (get_flags == set_flags) 84 return true; 85 86 if (-1 != fcntl (sckt, F_SETFL, set_flags)) 87 return true; 88 # endif /* F_GETFL && O_NONBLOCK && F_SETFL */ 89 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 90 unsigned long set_flag = 1; 91 92 if (0 == ioctlsocket (sckt, (long)FIONBIO, &set_flag)) 93 return true; 94 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 95 96 return false; 97 } 98 99 100 MHD_INTERNAL bool 101 mhd_socket_noninheritable (MHD_Socket sckt) 102 { 103 #if defined(MHD_SOCKETS_KIND_POSIX) 104 // TODO: detect constants in configure 105 # if defined(F_GETFD) && defined(FD_CLOEXEC) && defined(F_SETFD) 106 int get_flags; 107 int set_flags; 108 109 get_flags = fcntl (sckt, F_GETFD); 110 if (0 > get_flags) 111 return false; 112 113 set_flags = (get_flags | FD_CLOEXEC); 114 if (get_flags == set_flags) 115 return true; 116 117 if (-1 != fcntl (sckt, F_SETFD, set_flags)) 118 return true; 119 # endif /* F_GETFD && FD_CLOEXEC && F_SETFD */ 120 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 121 if (SetHandleInformation ((HANDLE)sckt, HANDLE_FLAG_INHERIT, 0)) 122 return true; 123 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 124 return false; 125 } 126 127 128 MHD_INTERNAL bool 129 mhd_socket_set_nodelay (MHD_Socket sckt, 130 bool on) 131 { 132 #ifdef HAVE_DCLR_TCP_NODELAY 133 mhd_SCKT_OPT_BOOL value; 134 135 value = on ? 1 : 0; 136 137 return 0 == mhd_setsockopt (sckt, IPPROTO_TCP, TCP_NODELAY, 138 (const void *)&value, sizeof (value)); 139 #else /* ! TCP_NODELAY */ 140 (void)sckt; 141 (void)on; 142 return false; 143 #endif /* ! TCP_NODELAY */ 144 } 145 146 147 MHD_INTERNAL bool 148 mhd_socket_set_hard_close (MHD_Socket sckt) 149 { 150 #if defined(HAVE_DCLR_SOL_SOCKET) && defined(HAVE_DCLR_SO_LINGER) 151 struct linger par; 152 153 par.l_onoff = 1; 154 par.l_linger = 0; 155 156 return 0 == mhd_setsockopt (sckt, SOL_SOCKET, SO_LINGER, 157 (const void *)&par, sizeof (par)); 158 #else /* ! SOL_SOCKET || ! SO_LINGER */ 159 (void)sckt; 160 return false; 161 #endif /* ! SOL_SOCKET || ! SO_LINGER */ 162 } 163 164 165 MHD_INTERNAL bool 166 mhd_socket_shut_wr (MHD_Socket sckt) 167 { 168 #if defined(HAVE_DCLR_SHUT_WR) 169 return 0 == shutdown (sckt, SHUT_WR); 170 #elif defined(HAVE_DCLR_SD_SEND) 171 return 0 == shutdown (sckt, SD_SEND); 172 #else 173 return false; 174 #endif 175 } 176 177 178 #ifndef HAVE_SOCKETPAIR 179 180 static bool 181 mhd_socket_blocking (MHD_Socket sckt) 182 { 183 # if defined(MHD_SOCKETS_KIND_POSIX) 184 // TODO: detect constants in configure 185 # if defined(F_GETFL) && defined(O_NONBLOCK) && defined(F_SETFL) 186 int get_flags; 187 int set_flags; 188 189 get_flags = fcntl (sckt, F_GETFL); 190 if (0 > get_flags) 191 return false; 192 193 set_flags = (flags & ~O_NONBLOCK); 194 if (get_flags == set_flags) 195 return true; 196 197 if (-1 != fcntl (sckt, F_SETFL, set_flags)) 198 return true; 199 # endif /* F_GETFL && O_NONBLOCK && F_SETFL */ 200 # elif defined(MHD_SOCKETS_KIND_WINSOCK) 201 unsigned long set_flag = 0; 202 203 if (0 == ioctlsocket (sckt, (long)FIONBIO, &set_flag)) 204 return true; 205 # endif /* MHD_SOCKETS_KIND_WINSOCK */ 206 207 return false; 208 } 209 210 211 MHD_INTERNAL bool 212 mhd_socket_pair_func (MHD_Socket sckt[2], bool non_blk) 213 { 214 int i; 215 216 # define PAIR_MAX_TRIES 511 217 for (i = 0; i < PAIR_MAX_TRIES; i++) 218 { 219 struct sockaddr_in listen_addr; 220 MHD_Socket listen_s; 221 static const socklen_t c_addinlen = sizeof(struct sockaddr_in); /* Try to help compiler to optimise */ 222 socklen_t addr_len = c_addinlen; 223 224 listen_s = socket (AF_INET, 225 SOCK_STREAM, 226 0); 227 if (MHD_INVALID_SOCKET == listen_s) 228 break; /* can't create even single socket */ 229 230 listen_addr.sin_family = AF_INET; 231 listen_addr.sin_port = 0; /* same as htons(0) */ 232 # ifdef INADDR_LOOPBACK 233 listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 234 # else 235 memcpy (&(listen_addr.sin_addr.s_addr), "\x7F\x00\x00\x01", 4); 236 # endif 237 # ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 238 listen_addr.sin_len = sizeof(listen_addr); 239 # endif 240 241 if (((0 == bind (listen_s, 242 (struct sockaddr *)&listen_addr, 243 c_addinlen)) 244 && (0 == listen (listen_s, 245 1)) 246 && (0 == getsockname (listen_s, 247 (struct sockaddr *)&listen_addr, 248 &addr_len)))) 249 { 250 MHD_Socket client_s = socket (AF_INET, SOCK_STREAM, 0); 251 struct sockaddr_in accepted_from_addr; 252 struct sockaddr_in client_addr; 253 254 if (MHD_INVALID_SOCKET != client_s) 255 { 256 if (mhd_socket_nonblocking (client_s) 257 && ((0 == connect (client_s, 258 (struct sockaddr *)&listen_addr, 259 c_addinlen)) 260 || mhd_SCKT_LERR_IS_EAGAIN ())) 261 { 262 MHD_Socket server_s; 263 264 addr_len = c_addinlen; 265 server_s = accept (listen_s, 266 (struct sockaddr *)&accepted_from_addr, 267 &addr_len); 268 if (MHD_INVALID_SOCKET != server_s) 269 { 270 addr_len = c_addinlen; 271 if ((0 == getsockname (client_s, 272 (struct sockaddr *)&client_addr, 273 &addr_len)) 274 && (accepted_from_addr.sin_port == client_addr.sin_port) 275 && (accepted_from_addr.sin_addr.s_addr == 276 client_addr.sin_addr.s_addr)) 277 { 278 (void)mhd_socket_set_nodelay (server_s, true); 279 (void)mhd_socket_set_nodelay (client_s, true); 280 if (non_blk ? 281 mhd_socket_nonblocking (server_s) : 282 mhd_socket_blocking (client_s)) 283 { 284 mhd_socket_close (listen_s); 285 sckt[0] = server_s; 286 sckt[1] = client_s; 287 return true; 288 } 289 } 290 mhd_socket_close (server_s); 291 } 292 } 293 mhd_socket_close (client_s); 294 } 295 } 296 mhd_socket_close (listen_s); 297 } 298 299 sckt[0] = MHD_INVALID_SOCKET; 300 sckt[1] = MHD_INVALID_SOCKET; 301 302 return false; 303 } 304 305 306 #endif /* ! HAVE_SOCKETPAIR */