libmicrohttpd2

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

mhd_check_poll_quirks.m4 (10220B)


      1 # SPDX-License-Identifier: FSFAP
      2 #
      3 # SYNOPSIS
      4 #
      5 #   MHD_CHECK_POLL_QUIRKS
      6 #
      7 # DESCRIPTION
      8 #
      9 #   Check whether the system poll() (or WSAPoll()) function has any known
     10 #   quirks.
     11 #
     12 #   If any such quirks are detected, corresponding preprocessor macros
     13 #   are defined.
     14 #
     15 #   The configure.ac script must check for the presence of all headers
     16 #   used by this macro before "invoking" it.
     17 #
     18 # LICENSE
     19 #
     20 #   Copyright (c) 2025 Karlson2k (Evgeny Grin) <k2k@drgrin.dev>
     21 #
     22 #   Copying and distribution of this file, with or without modification, are
     23 #   permitted in any medium without royalty provided the copyright notice
     24 #   and this notice are preserved. This file is offered as-is, without any
     25 #   warranty.
     26 
     27 #serial 1
     28 
     29 AC_DEFUN([MHD_CHECK_POLL_QUIRKS],[dnl
     30   AC_PREREQ([2.64])dnl
     31   AC_REQUIRE([AC_CANONICAL_HOST])dnl
     32   AC_REQUIRE([AC_PROG_CC])dnl
     33   AC_LANG_ASSERT([C])dnl
     34   AS_IF([test -z "$use_itc"],[AC_MSG_FAILURE([\$use_itc is not set])])
     35   AS_VAR_IF([have_poll],["yes"],[:],[AC_MSG_FAILURE([\$have_poll is not 'yes'])])
     36   AC_CACHE_CHECK([[whether poll() clobbers fds.events]],
     37     [[mhd_cv_poll_clobbers_events]], [dnl
     38       AC_RUN_IFELSE([
     39           AC_LANG_SOURCE([[
     40 
     41 #ifdef HAVE_SYS_TYPES_H
     42 #  include <sys/types.h>
     43 #endif
     44 #ifdef HAVE_UNISTD_H
     45 #  include <unistd.h>
     46 #endif
     47 #ifdef HAVE_STDLIB_H
     48 #  include <stdlib.h>
     49 #endif
     50 #ifdef HAVE_SYS_SOCKET_H
     51 #  include <sys/socket.h>
     52 #endif
     53 #ifdef HAVE_SOCKLIB_H
     54 #  include <sockLib.h>
     55 #endif
     56 #ifdef HAVE_INETLIB_H
     57 #  include <inetLib.h>
     58 #endif
     59 #ifdef HAVE_NETINET_IN_H
     60 #  include <netinet/in.h>
     61 #endif
     62 #ifdef HAVE_SYS_UN_H
     63 #  include <sys/un.h>
     64 #endif
     65 #ifdef HAVE_ARPA_INET_H
     66 #  include <arpa/inet.h>
     67 #endif
     68 #if defined(HAVE_NETDB_H)
     69 #  include <netdb.h>
     70 #endif
     71 #ifdef HAVE_NETINET_TCP_H
     72 #  include <netinet/tcp.h>
     73 #endif
     74 #if !defined(_WIN32) || defined(__CYGWIN__)
     75 #  include <poll.h>
     76 #else
     77 #  include <winsock2.h>
     78 #  include <ws2tcpip.h>
     79 #  ifndef MHD_ITC_SOCKETPAIR_
     80 #error Only socketpair ITC supported on native W32
     81 choke me now
     82 #  endif
     83 #endif
     84 #include <stdio.h>
     85 
     86 #if defined(MHD_ITC_EVENTFD_)
     87 #  include <sys/eventfd.h>
     88 #elif defined(MHD_ITC_PIPE_)
     89 /* No Additional includes */
     90 #elif defined(MHD_ITC_SOCKETPAIR_)
     91 /* No Additional includes */
     92 #else
     93 #error No selected ITC type
     94 choke me now
     95 #endif
     96 
     97 #if defined(PF_INET)
     98 #  define my_PF_INET PF_INET
     99 #else
    100 #  define my_PF_INET AF_INET
    101 #endif
    102 
    103 #if !defined(_WIN32) || defined(__CYGWIN__)
    104 #  define CHECK_USE_POSIX_SOCKETS 1
    105 #  define my_sckt_type int
    106 #  define MY_INVALID_SOCKET (-1)
    107 #  define my_send3(s,b,l) send((s),(b),(l),0)
    108 #  define my_fd_close(skt) close((skt))
    109 #else
    110 #  define CHECK_USE_WINSOCK_SOCKETS 1
    111 #  define my_sckt_type SOCKET
    112 #  define MY_INVALID_SOCKET INVALID_SOCKET
    113 #  define my_send3(s,b,l) send((s),(const char *)(b),(l),0)
    114 #  define my_fd_close(skt) closesocket((skt))
    115 #endif
    116 
    117 #if defined(MHD_ITC_SOCKETPAIR_)
    118 #  ifdef CHECK_USE_POSIX_SOCKETS
    119 #    if defined(AF_UNIX)
    120 #      define my_socketpair(sk_arr) socketpair(AF_UNIX, SOCK_STREAM, 0, (sk_arr))
    121 #    elif defined(AF_LOCAL)
    122 #      define my_socketpair(sk_arr) socketpair(AF_LOCAL, SOCK_STREAM, 0, (sk_arr))
    123 #    else
    124 #      define my_socketpair(sk_arr) socketpair(AF_INET, SOCK_STREAM, 0, (sk_arr))
    125 #    endif
    126 #  else /* WinSock sockets */
    127 static int my_socket_nonblocking (SOCKET sckt);
    128 
    129 static int my_socketpair (my_sckt_type sckt[2])
    130 {
    131   int i;
    132 
    133 #define PAIR_MAX_TRIES 511
    134   for (i = 0; i < PAIR_MAX_TRIES; i++)
    135   {
    136     struct sockaddr_in listen_addr;
    137     my_sckt_type listen_s;
    138     static const socklen_t c_addinlen = sizeof(struct sockaddr_in);   /* Try to help compiler to optimise */
    139     socklen_t addr_len = c_addinlen;
    140 
    141     listen_s = socket (AF_INET,
    142                        SOCK_STREAM,
    143                        0);
    144     if (INVALID_SOCKET == listen_s)
    145       break;   /* can't create even single socket */
    146 
    147     listen_addr.sin_family = AF_INET;
    148     listen_addr.sin_port = 0;   /* same as htons(0) */
    149     listen_addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
    150 
    151     if ( ((0 == bind (listen_s,
    152                       (struct sockaddr *) &listen_addr,
    153                       c_addinlen)) &&
    154           (0 == listen (listen_s,
    155                         1) ) &&
    156           (0 == getsockname (listen_s,
    157                              (struct sockaddr *) &listen_addr,
    158                              &addr_len))) )
    159     {
    160       my_sckt_type client_s = socket (AF_INET, SOCK_STREAM, 0);
    161       struct sockaddr_in accepted_from_addr;
    162       struct sockaddr_in client_addr;
    163 
    164       if (INVALID_SOCKET != client_s)
    165       {
    166         if (my_socket_nonblocking (client_s) &&
    167             ( (0 == connect (client_s,
    168                              (struct sockaddr *) &listen_addr,
    169                              c_addinlen)) ||
    170               (WSAEWOULDBLOCK == WSAGetLastError()) ))
    171         {
    172           my_sckt_type server_s;
    173 
    174           addr_len = c_addinlen;
    175           server_s = accept (listen_s,
    176                              (struct sockaddr *) &accepted_from_addr,
    177                              &addr_len);
    178           if (INVALID_SOCKET != server_s)
    179           {
    180             addr_len = c_addinlen;
    181             if ( (0 == getsockname (client_s,
    182                                     (struct sockaddr *) &client_addr,
    183                                     &addr_len)) &&
    184                  (accepted_from_addr.sin_port == client_addr.sin_port) &&
    185                  (accepted_from_addr.sin_addr.s_addr ==
    186                   client_addr.sin_addr.s_addr) )
    187             {
    188               closesocket (listen_s);
    189               return 0;
    190             }
    191             closesocket (server_s);
    192           }
    193         }
    194         closesocket (client_s);
    195       }
    196     }
    197     closesocket (listen_s);
    198   }
    199 
    200   sckt[0] = INVALID_SOCKET;
    201   sckt[1] = INVALID_SOCKET;
    202 
    203   return -1;
    204 }
    205 
    206 static int my_socket_nonblocking (SOCKET sckt)
    207 {
    208   unsigned long set_flag = 1;
    209 
    210   if (0 == ioctlsocket (sckt, (long) FIONBIO, &set_flag))
    211     return !0;
    212 
    213   return 0;
    214 }
    215 
    216 #  endif
    217 #endif
    218 
    219 static int check_poll_fn(void)
    220 {
    221   int res;
    222   int err_res = 0;
    223   struct pollfd fds[2];
    224 #ifdef MHD_ITC_EVENTFD_
    225   my_sckt_type itc_fd;
    226 #else
    227   my_sckt_type itc_pair[2];
    228 #endif
    229   my_sckt_type listen_skt;
    230 
    231 #if defined(MHD_ITC_EVENTFD_)
    232   itc_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
    233   if (0 > itc_fd)
    234     err_res = 10;
    235   else
    236   {
    237     if (1) /* for local scope */
    238     {
    239       unsigned char val[8] = {1u, 0u, 0u, 0u, 0u, 0u, 0u, 0u};
    240       if (0 > write (itc_fd, (void *) val, 8)) /* "activate" ITC */
    241         (void) res; /* ignore result */
    242     }
    243     fds[0].fd = itc_fd;
    244 #elif defined(MHD_ITC_PIPE_)
    245 #  ifdef HAVE_PIPE2_FUNC
    246   res = pipe2(itc_pair, 0
    247 #    ifdef O_CLOEXEC
    248                         | O_CLOEXEC
    249 #    endif
    250 #    ifdef O_NONBLOCK
    251                         | O_NONBLOCK
    252 #    endif
    253               );
    254 #  else
    255   res = pipe(itc_pair);
    256 #  endif
    257   if (0 != res)
    258     err_res = 11;
    259   else
    260   {
    261     if (1) /* for local scope */
    262     {
    263       unsigned char val = 1u;
    264       if (0 > write (itc_pair[1], (void *) &val, 1)) /* "activate" ITC */
    265         (void) res; /* ignore result */
    266     }
    267     fds[0].fd = itc_pair[0];
    268 #elif defined(MHD_ITC_SOCKETPAIR_)
    269   res = my_socketpair(itc_pair);
    270   if (0 != res)
    271     err_res = 12;
    272   else
    273   {
    274     if (1) /* for local scope */
    275     {
    276       unsigned char val = 1u;
    277       if (0 > my_send3(itc_pair[1], (void *) &val, 1)) /* "activate" ITC */
    278         (void) 0; /* ignore result */
    279     }
    280     fds[0].fd = itc_pair[0];
    281 #endif
    282     fds[0].events = POLLIN;
    283 
    284 
    285     listen_skt = socket(my_PF_INET, SOCK_STREAM, 0);
    286     if (MY_INVALID_SOCKET == listen_skt)
    287       err_res = 13;
    288     else
    289     {
    290       if (1) /* for local scope */
    291       {
    292         struct sockaddr_in sk_addr;
    293 
    294         sk_addr.sin_family = AF_INET;
    295         sk_addr.sin_addr.s_addr = INADDR_ANY;
    296         sk_addr.sin_port = 0;
    297 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
    298         sk_addr.sin_len = sizeof(sk_addr);
    299 #endif
    300 
    301         res = bind(listen_skt, (struct sockaddr *) &sk_addr, sizeof(sk_addr));
    302         (void) res; /* ignore result */
    303       }
    304 
    305       res = listen(listen_skt, 8);
    306       (void) res; /* ignore result */
    307 
    308       fds[1].fd = listen_skt;
    309       fds[1].events = POLLIN;
    310 
    311 #ifdef CHECK_USE_POSIX_SOCKETS
    312       res = poll(fds, 2, 0);
    313 #else
    314       res = WSAPoll(fds, 2, 0);
    315 #endif
    316       if (0 > res)
    317         err_res = 14;
    318 
    319       if (POLLIN != fds[0].events)
    320       {
    321         fprintf (stderr, "fds[0].events changed from 0x%X to 0x%X\n", (unsigned int) POLLIN, (unsigned int) fds[0].events);
    322         err_res = 97; /* Magic number */
    323       }
    324       if (POLLIN != fds[1].events)
    325       {
    326         fprintf (stderr, "fds[1].events changed from 0x%X to 0x%X\n", (unsigned int) POLLIN, (unsigned int) fds[1].events);
    327         err_res = 97; /* Magic number */
    328       }
    329       res = my_fd_close(listen_skt);
    330       (void) res; /* Ignore result */
    331     }
    332 #if defined(MHD_ITC_EVENTFD_)
    333     res = my_fd_close(itc_fd);
    334     (void) res; /* Ignore result */
    335 #else
    336     res = my_fd_close(itc_pair[1]);
    337     (void) res; /* Ignore result */
    338     res = my_fd_close(itc_pair[0]);
    339     (void) res; /* Ignore result */
    340 #endif
    341   }
    342   return err_res;
    343 }
    344 
    345 int main(void)
    346 {
    347   int err_res;
    348 #ifdef CHECK_USE_WINSOCK_SOCKETS
    349   if (1) /* for local scope */
    350   {
    351     WSADATA wsa_d;
    352     if (0 != WSAStartup(MAKEWORD(2, 2), &wsa_d))
    353       return 5;
    354   }
    355 #endif
    356   err_res = check_poll_fn();
    357   if ((0 != err_res) && (97 != err_res))
    358     fprintf (stderr, "Failed to preform poll() checking.\n");
    359 
    360 #ifdef MHD_SOCKETS_KIND_WINSOCK
    361   (void) WSACleanup();
    362 #endif /* MHD_SOCKETS_KIND_WINSOCK */
    363 
    364   return err_res;
    365 }
    366 
    367             ]]
    368           )
    369         ],
    370         [mhd_cv_poll_clobbers_events="no"],
    371         [
    372           test_res="$?"
    373           AS_IF([test "$test_res" -eq 0],[AC_MSG_FAILURE()],
    374             [test "$test_res" -eq 97],[mhd_cv_poll_clobbers_events="yes"] # Test magic number
    375             ,[mhd_cv_poll_clobbers_events="assuming yes"]
    376           )
    377           AS_UNSET([test_res])
    378         ],
    379         [
    380           AS_CASE(["$host_os"],
    381             [haiku],[mhd_cv_poll_clobbers_events="assuming yes"],
    382             [mhd_cv_poll_clobbers_events="guessing no"]
    383           )
    384         ]
    385       )
    386     ]
    387   )
    388   AS_CASE([$mhd_cv_poll_clobbers_events],
    389     [*yes],
    390     [AC_DEFINE([HAVE_POLL_CLOBBERS_EVENTS],
    391                [1],[Define to '1' is poll() change value of 'events' member of array pointed by 'fds'])
    392     ]
    393   )
    394 ])