libmicrohttpd2

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

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