Coverage Report

Created: 2025-11-11 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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 */