mhd_sockets_funcs.c (8777B)
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; (void) on; 141 return false; 142 #endif /* ! TCP_NODELAY */ 143 } 144 145 146 MHD_INTERNAL bool 147 mhd_socket_set_hard_close (MHD_Socket sckt) 148 { 149 #if defined(HAVE_DCLR_SOL_SOCKET) && defined(HAVE_DCLR_SO_LINGER) 150 struct linger par; 151 152 par.l_onoff = 1; 153 par.l_linger = 0; 154 155 return 0 == mhd_setsockopt (sckt, SOL_SOCKET, SO_LINGER, 156 (const void *) &par, sizeof (par)); 157 #else /* ! SOL_SOCKET || ! SO_LINGER */ 158 (void) sckt; 159 return false; 160 #endif /* ! SOL_SOCKET || ! SO_LINGER */ 161 } 162 163 164 MHD_INTERNAL bool 165 mhd_socket_shut_wr (MHD_Socket sckt) 166 { 167 #if defined(HAVE_DCLR_SHUT_WR) 168 return 0 == shutdown (sckt, SHUT_WR); 169 #elif defined(HAVE_DCLR_SD_SEND) 170 return 0 == shutdown (sckt, SD_SEND); 171 #else 172 return false; 173 #endif 174 } 175 176 177 #ifndef HAVE_SOCKETPAIR 178 179 static bool 180 mhd_socket_blocking (MHD_Socket sckt) 181 { 182 #if defined(MHD_SOCKETS_KIND_POSIX) 183 // TODO: detect constants in configure 184 #if defined(F_GETFL) && defined(O_NONBLOCK) && defined(F_SETFL) 185 int get_flags; 186 int set_flags; 187 188 get_flags = fcntl (sckt, F_GETFL); 189 if (0 > get_flags) 190 return false; 191 192 set_flags = (flags & ~O_NONBLOCK); 193 if (get_flags == set_flags) 194 return true; 195 196 if (-1 != fcntl (sckt, F_SETFL, set_flags)) 197 return true; 198 #endif /* F_GETFL && O_NONBLOCK && F_SETFL */ 199 #elif defined(MHD_SOCKETS_KIND_WINSOCK) 200 unsigned long set_flag = 0; 201 202 if (0 == ioctlsocket (sckt, (long) FIONBIO, &set_flag)) 203 return true; 204 #endif /* MHD_SOCKETS_KIND_WINSOCK */ 205 206 return false; 207 } 208 209 210 MHD_INTERNAL bool 211 mhd_socket_pair_func (MHD_Socket sckt[2], bool non_blk) 212 { 213 int i; 214 215 #define PAIR_MAX_TRIES 511 216 for (i = 0; i < PAIR_MAX_TRIES; i++) 217 { 218 struct sockaddr_in listen_addr; 219 MHD_Socket listen_s; 220 static const socklen_t c_addinlen = sizeof(struct sockaddr_in); /* Try to help compiler to optimise */ 221 socklen_t addr_len = c_addinlen; 222 223 listen_s = socket (AF_INET, 224 SOCK_STREAM, 225 0); 226 if (MHD_INVALID_SOCKET == listen_s) 227 break; /* can't create even single socket */ 228 229 listen_addr.sin_family = AF_INET; 230 listen_addr.sin_port = 0; /* same as htons(0) */ 231 #ifdef INADDR_LOOPBACK 232 listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 233 #else 234 memcpy (&(listen_addr.sin_addr.s_addr), "\x7F\x00\x00\x01", 4); 235 #endif 236 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 237 listen_addr.sin_len = sizeof(listen_addr); 238 #endif 239 240 if ( ((0 == bind (listen_s, 241 (struct sockaddr *) &listen_addr, 242 c_addinlen)) && 243 (0 == listen (listen_s, 244 1) ) && 245 (0 == getsockname (listen_s, 246 (struct sockaddr *) &listen_addr, 247 &addr_len))) ) 248 { 249 MHD_Socket client_s = socket (AF_INET, SOCK_STREAM, 0); 250 struct sockaddr_in accepted_from_addr; 251 struct sockaddr_in client_addr; 252 253 if (MHD_INVALID_SOCKET != client_s) 254 { 255 if (mhd_socket_nonblocking (client_s) && 256 ( (0 == connect (client_s, 257 (struct sockaddr *) &listen_addr, 258 c_addinlen)) || 259 mhd_SCKT_LERR_IS_EAGAIN () )) 260 { 261 MHD_Socket server_s; 262 263 addr_len = c_addinlen; 264 server_s = accept (listen_s, 265 (struct sockaddr *) &accepted_from_addr, 266 &addr_len); 267 if (MHD_INVALID_SOCKET != server_s) 268 { 269 addr_len = c_addinlen; 270 if ( (0 == getsockname (client_s, 271 (struct sockaddr *) &client_addr, 272 &addr_len)) && 273 (accepted_from_addr.sin_port == client_addr.sin_port) && 274 (accepted_from_addr.sin_addr.s_addr == 275 client_addr.sin_addr.s_addr) ) 276 { 277 (void) mhd_socket_set_nodelay (server_s, true); 278 (void) mhd_socket_set_nodelay (client_s, true); 279 if (non_blk ? 280 mhd_socket_nonblocking (server_s) : 281 mhd_socket_blocking (client_s)) 282 { 283 mhd_socket_close (listen_s); 284 sckt[0] = server_s; 285 sckt[1] = client_s; 286 return true; 287 } 288 } 289 mhd_socket_close (server_s); 290 } 291 } 292 mhd_socket_close (client_s); 293 } 294 } 295 mhd_socket_close (listen_s); 296 } 297 298 sckt[0] = MHD_INVALID_SOCKET; 299 sckt[1] = MHD_INVALID_SOCKET; 300 301 return false; 302 } 303 304 305 #endif /* ! HAVE_SOCKETPAIR */