libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 */