/src/mhd2/src/mhd2/mhd_sockets_funcs.c
Line | Count | Source |
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 | 0 | { |
72 | 0 | #if defined(MHD_SOCKETS_KIND_POSIX) |
73 | | // TODO: detect constants in configure |
74 | 0 | #if defined(F_GETFL) && defined(O_NONBLOCK) && defined(F_SETFL) |
75 | 0 | int get_flags; |
76 | 0 | int set_flags; |
77 | |
|
78 | 0 | get_flags = fcntl (sckt, F_GETFL); |
79 | 0 | if (0 > get_flags) |
80 | 0 | return false; |
81 | | |
82 | 0 | set_flags = (get_flags | O_NONBLOCK); |
83 | 0 | if (get_flags == set_flags) |
84 | 0 | return true; |
85 | | |
86 | 0 | if (-1 != fcntl (sckt, F_SETFL, set_flags)) |
87 | 0 | return true; |
88 | 0 | #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 | 0 | return false; |
97 | 0 | } |
98 | | |
99 | | |
100 | | MHD_INTERNAL bool |
101 | | mhd_socket_noninheritable (MHD_Socket sckt) |
102 | 0 | { |
103 | 0 | #if defined(MHD_SOCKETS_KIND_POSIX) |
104 | | // TODO: detect constants in configure |
105 | 0 | #if defined(F_GETFD) && defined(FD_CLOEXEC) && defined(F_SETFD) |
106 | 0 | int get_flags; |
107 | 0 | int set_flags; |
108 | |
|
109 | 0 | get_flags = fcntl (sckt, F_GETFD); |
110 | 0 | if (0 > get_flags) |
111 | 0 | return false; |
112 | | |
113 | 0 | set_flags = (get_flags | FD_CLOEXEC); |
114 | 0 | if (get_flags == set_flags) |
115 | 0 | return true; |
116 | | |
117 | 0 | if (-1 != fcntl (sckt, F_SETFD, set_flags)) |
118 | 0 | return true; |
119 | 0 | #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 | 0 | return false; |
125 | 0 | } |
126 | | |
127 | | |
128 | | MHD_INTERNAL bool |
129 | | mhd_socket_set_nodelay (MHD_Socket sckt, |
130 | | bool on) |
131 | 0 | { |
132 | 0 | #ifdef HAVE_DCLR_TCP_NODELAY |
133 | 0 | mhd_SCKT_OPT_BOOL value; |
134 | |
|
135 | 0 | value = on ? 1 : 0; |
136 | |
|
137 | 0 | return 0 == mhd_setsockopt (sckt, IPPROTO_TCP, TCP_NODELAY, |
138 | 0 | (const void *) &value, sizeof (value)); |
139 | | #else /* ! TCP_NODELAY */ |
140 | | (void) sckt; (void) on; |
141 | | return false; |
142 | | #endif /* ! TCP_NODELAY */ |
143 | 0 | } |
144 | | |
145 | | |
146 | | MHD_INTERNAL bool |
147 | | mhd_socket_set_hard_close (MHD_Socket sckt) |
148 | 4.85k | { |
149 | 4.85k | #if defined(HAVE_DCLR_SOL_SOCKET) && defined(HAVE_DCLR_SO_LINGER) |
150 | 4.85k | struct linger par; |
151 | | |
152 | 4.85k | par.l_onoff = 1; |
153 | 4.85k | par.l_linger = 0; |
154 | | |
155 | 4.85k | return 0 == mhd_setsockopt (sckt, SOL_SOCKET, SO_LINGER, |
156 | 4.85k | (const void *) &par, sizeof (par)); |
157 | | #else /* ! SOL_SOCKET || ! SO_LINGER */ |
158 | | (void) sckt; |
159 | | return false; |
160 | | #endif /* ! SOL_SOCKET || ! SO_LINGER */ |
161 | 4.85k | } |
162 | | |
163 | | |
164 | | MHD_INTERNAL bool |
165 | | mhd_socket_shut_wr (MHD_Socket sckt) |
166 | 0 | { |
167 | 0 | #if defined(HAVE_DCLR_SHUT_WR) |
168 | 0 | 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 | 0 | } |
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 */ |