libmicrohttpd

HTTP/1.x server C library (MHD 1.x, stable)
Log | Files | Refs | Submodules | README | LICENSE

mhd_itc.h (10972B)


      1 /*
      2   This file is part of libmicrohttpd
      3   Copyright (C) 2016-2023 Karlson2k (Evgeny Grin)
      4 
      5   This library is free software; you can redistribute it and/or
      6   modify it under the terms of the GNU Lesser General Public
      7   License as published by the Free Software Foundation; either
      8   version 2.1 of the License, or (at your option) any later version.
      9 
     10   This library is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13   Lesser General Public License for more details.
     14 
     15   You should have received a copy of the GNU Lesser General Public
     16   License along with this library; if not, write to the Free Software
     17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     18 
     19 */
     20 
     21 /**
     22  * @file microhttpd/mhd_itc.h
     23  * @brief  Header for platform-independent inter-thread communication
     24  * @author Karlson2k (Evgeny Grin)
     25  * @author Christian Grothoff
     26  *
     27  * Provides basic abstraction for inter-thread communication.
     28  * Any functions can be implemented as macro on some platforms
     29  * unless explicitly marked otherwise.
     30  * Any function argument can be skipped in macro, so avoid
     31  * variable modification in function parameters.
     32  */
     33 #ifndef MHD_ITC_H
     34 #define MHD_ITC_H 1
     35 #include "mhd_itc_types.h"
     36 
     37 #include <fcntl.h>
     38 
     39 #ifndef MHD_PANIC
     40 #  include <stdio.h>
     41 #  ifdef HAVE_STDLIB_H
     42 #    include <stdlib.h>
     43 #  endif /* HAVE_STDLIB_H */
     44 /* Simple implementation of MHD_PANIC, to be used outside lib */
     45 #  define MHD_PANIC(msg)                                             \
     46   do { fprintf (stderr,                                              \
     47                 "Abnormal termination at %d line in file %s: %s\n",  \
     48                 (int) __LINE__, __FILE__, msg); abort ();            \
     49      } while (0)
     50 #endif /* ! MHD_PANIC */
     51 
     52 #if defined(_MHD_ITC_EVENTFD)
     53 
     54 /* **************** Optimized GNU/Linux ITC implementation by eventfd ********** */
     55 #include <sys/eventfd.h>
     56 #include <stdint.h>      /* for uint64_t */
     57 #ifdef HAVE_UNISTD_H
     58 #include <unistd.h>      /* for read(), write() */
     59 #endif /* HAVE_UNISTD_H */
     60 #ifdef HAVE_STRING_H
     61 #include <string.h> /* for strerror() */
     62 #include <errno.h>
     63 #endif
     64 
     65 /**
     66  * Number of FDs used by every ITC.
     67  */
     68 #define MHD_ITC_NUM_FDS_ (1)
     69 
     70 /**
     71  * Initialise ITC by generating eventFD
     72  * @param itc the itc to initialise
     73  * @return non-zero if succeeded, zero otherwise
     74  */
     75 #define MHD_itc_init_(itc) \
     76   (-1 != ((itc).fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK)))
     77 
     78 /**
     79  * Get description string of last errno for itc operations.
     80  */
     81 #define MHD_itc_last_strerror_() strerror (errno)
     82 
     83 /**
     84  * Internal static const helper for MHD_itc_activate_()
     85  */
     86 static const uint64_t _MHD_itc_wr_data = 1;
     87 
     88 /**
     89  * Activate signal on @a itc
     90  * @param itc the itc to use
     91  * @param str ignored
     92  * @return non-zero if succeeded, zero otherwise
     93  */
     94 #define MHD_itc_activate_(itc, str)                    \
     95   ((write ((itc).fd, (const void*) &_MHD_itc_wr_data,  \
     96            sizeof(_MHD_itc_wr_data)) > 0) || (EAGAIN == errno))
     97 
     98 /**
     99  * Return read FD of @a itc which can be used for poll(), select() etc.
    100  * @param itc the itc to get FD
    101  * @return FD of read side
    102  */
    103 #define MHD_itc_r_fd_(itc) ((itc).fd)
    104 
    105 /**
    106  * Return write FD of @a itc
    107  * @param itc the itc to get FD
    108  * @return FD of write side
    109  */
    110 #define MHD_itc_w_fd_(itc) ((itc).fd)
    111 
    112 /**
    113  * Clear signaled state on @a itc
    114  * @param itc the itc to clear
    115  */
    116 #define MHD_itc_clear_(itc)                               \
    117   do { uint64_t __b;                                      \
    118        (void) read ((itc).fd, (void*)&__b, sizeof(__b));  \
    119      } while (0)
    120 
    121 /**
    122  * Destroy previously initialised ITC.  Note that close()
    123  * on some platforms returns odd errors, so we ONLY fail
    124  * if the errno is EBADF.
    125  * @param itc the itc to destroy
    126  * @return non-zero if succeeded, zero otherwise
    127  */
    128 #define MHD_itc_destroy_(itc) \
    129   ((0 == close ((itc).fd)) || (EBADF != errno))
    130 
    131 /**
    132  * Check whether ITC has valid value.
    133  *
    134  * Macro check whether @a itc value is valid (allowed),
    135  * macro does not check whether @a itc was really initialised.
    136  * @param itc the itc to check
    137  * @return boolean true if @a itc has valid value,
    138  *         boolean false otherwise.
    139  */
    140 #define MHD_ITC_IS_VALID_(itc)  (-1 != ((itc).fd))
    141 
    142 /**
    143  * Set @a itc to invalid value.
    144  * @param itc the itc to set
    145  */
    146 #define MHD_itc_set_invalid_(itc) ((itc).fd = -1)
    147 
    148 
    149 #elif defined(_MHD_ITC_PIPE)
    150 
    151 /* **************** Standard UNIX ITC implementation by pipe ********** */
    152 
    153 #if defined(HAVE_PIPE2_FUNC) && defined(HAVE_FCNTL_H)
    154 #  include <fcntl.h>     /* for O_CLOEXEC, O_NONBLOCK */
    155 #endif /* HAVE_PIPE2_FUNC && HAVE_FCNTL_H */
    156 #ifdef HAVE_UNISTD_H
    157 #include <unistd.h>      /* for read(), write(), errno */
    158 #endif /* HAVE_UNISTD_H */
    159 #ifdef HAVE_STRING_H
    160 #include <string.h> /* for strerror() */
    161 #endif
    162 
    163 
    164 /**
    165  * Number of FDs used by every ITC.
    166  */
    167 #define MHD_ITC_NUM_FDS_ (2)
    168 
    169 /**
    170  * Initialise ITC by generating pipe
    171  * @param itc the itc to initialise
    172  * @return non-zero if succeeded, zero otherwise
    173  */
    174 #ifdef HAVE_PIPE2_FUNC
    175 #  define MHD_itc_init_(itc) (! pipe2 ((itc).fd, O_CLOEXEC | O_NONBLOCK))
    176 #else  /* ! HAVE_PIPE2_FUNC */
    177 #  define MHD_itc_init_(itc)          \
    178   ( (! pipe ((itc).fd)) ?             \
    179     (MHD_itc_nonblocking_ ((itc)) ?   \
    180      (! 0) :                          \
    181      (MHD_itc_destroy_ ((itc)), 0) )  \
    182     : (0) )
    183 #endif /* ! HAVE_PIPE2_FUNC */
    184 
    185 /**
    186  * Get description string of last errno for itc operations.
    187  */
    188 #define MHD_itc_last_strerror_() strerror (errno)
    189 
    190 /**
    191  * Activate signal on @a itc
    192  * @param itc the itc to use
    193  * @param str one-symbol string, useful only for strace debug
    194  * @return non-zero if succeeded, zero otherwise
    195  */
    196 #define MHD_itc_activate_(itc, str) \
    197   ((write ((itc).fd[1], (const void*) (str), 1) > 0) || (EAGAIN == errno))
    198 
    199 
    200 /**
    201  * Return read FD of @a itc which can be used for poll(), select() etc.
    202  * @param itc the itc to get FD
    203  * @return FD of read side
    204  */
    205 #define MHD_itc_r_fd_(itc) ((itc).fd[0])
    206 
    207 /**
    208  * Return write FD of @a itc
    209  * @param itc the itc to get FD
    210  * @return FD of write side
    211  */
    212 #define MHD_itc_w_fd_(itc) ((itc).fd[1])
    213 
    214 /**
    215  * Clear signaled state on @a itc
    216  * @param itc the itc to clear
    217  */
    218 #define MHD_itc_clear_(itc) do                                 \
    219   { long __b;                                                  \
    220     while (0 < read ((itc).fd[0], (void*) &__b, sizeof(__b)))  \
    221     {(void)0;} } while (0)
    222 
    223 /**
    224  * Destroy previously initialised ITC
    225  * @param itc the itc to destroy
    226  * @return non-zero if succeeded, zero otherwise
    227  */
    228 #define MHD_itc_destroy_(itc)     \
    229   ( (0 == close ((itc).fd[0])) ?  \
    230     (0 == close ((itc).fd[1])) :  \
    231     ((close ((itc).fd[1])), 0) )
    232 
    233 /**
    234  * Check whether ITC has valid value.
    235  *
    236  * Macro check whether @a itc value is valid (allowed),
    237  * macro does not check whether @a itc was really initialised.
    238  * @param itc the itc to check
    239  * @return boolean true if @a itc has valid value,
    240  *         boolean false otherwise.
    241  */
    242 #define MHD_ITC_IS_VALID_(itc)  (-1 != (itc).fd[0])
    243 
    244 /**
    245  * Set @a itc to invalid value.
    246  * @param itc the itc to set
    247  */
    248 #define MHD_itc_set_invalid_(itc) ((itc).fd[0] = (itc).fd[1] = -1)
    249 
    250 #ifndef HAVE_PIPE2_FUNC
    251 /**
    252  * Change itc FD options to be non-blocking.
    253  *
    254  * @param fd the FD to manipulate
    255  * @return non-zero if succeeded, zero otherwise
    256  */
    257 int
    258 MHD_itc_nonblocking_ (struct MHD_itc_ itc);
    259 
    260 #endif /* ! HAVE_PIPE2_FUNC */
    261 
    262 
    263 #elif defined(_MHD_ITC_SOCKETPAIR)
    264 
    265 /* **************** ITC implementation by socket pair ********** */
    266 
    267 #include "mhd_sockets.h"
    268 
    269 
    270 /**
    271  * Number of FDs used by every ITC.
    272  */
    273 #define MHD_ITC_NUM_FDS_ (2)
    274 
    275 /**
    276  * Initialise ITC by generating socketpair
    277  * @param itc the itc to initialise
    278  * @return non-zero if succeeded, zero otherwise
    279  */
    280 #ifdef MHD_socket_pair_nblk_
    281 #  define MHD_itc_init_(itc) MHD_socket_pair_nblk_ ((itc).sk)
    282 #else  /* ! MHD_socket_pair_nblk_ */
    283 #  define MHD_itc_init_(itc)         \
    284   (MHD_socket_pair_ ((itc).sk) ?     \
    285    (MHD_itc_nonblocking_ ((itc)) ?   \
    286     (! 0) :                          \
    287     (MHD_itc_destroy_ ((itc)), 0) )  \
    288    : (0))
    289 #endif /* ! MHD_socket_pair_nblk_ */
    290 
    291 /**
    292  * Get description string of last error for itc operations.
    293  */
    294 #define MHD_itc_last_strerror_() MHD_socket_last_strerr_ ()
    295 
    296 /**
    297  * Activate signal on @a itc
    298  * @param itc the itc to use
    299  * @param str one-symbol string, useful only for strace debug
    300  * @return non-zero if succeeded, zero otherwise
    301  */
    302 #define MHD_itc_activate_(itc, str)            \
    303   ((MHD_send_ ((itc).sk[1], (str), 1) > 0) ||  \
    304    (MHD_SCKT_ERR_IS_EAGAIN_ (MHD_socket_get_error_ ())))
    305 
    306 /**
    307  * Return read FD of @a itc which can be used for poll(), select() etc.
    308  * @param itc the itc to get FD
    309  * @return FD of read side
    310  */
    311 #define MHD_itc_r_fd_(itc) ((itc).sk[0])
    312 
    313 /**
    314  * Return write FD of @a itc
    315  * @param itc the itc to get FD
    316  * @return FD of write side
    317  */
    318 #define MHD_itc_w_fd_(itc) ((itc).sk[1])
    319 
    320 /**
    321  * Clear signaled state on @a itc
    322  * @param itc the itc to clear
    323  */
    324 #define MHD_itc_clear_(itc) do                                    \
    325   { long __b;                                                     \
    326     while (0 < recv ((itc).sk[0], (void*) &__b, sizeof(__b), 0))  \
    327     {(void)0;} } while (0)
    328 
    329 /**
    330  * Destroy previously initialised ITC
    331  * @param itc the itc to destroy
    332  * @return non-zero if succeeded, zero otherwise
    333  */
    334 #define MHD_itc_destroy_(itc)         \
    335   (MHD_socket_close_ ((itc).sk[0]) ?  \
    336    MHD_socket_close_ ((itc).sk[1]) :  \
    337    ((void) MHD_socket_close_ ((itc).sk[1]), 0) )
    338 
    339 
    340 /**
    341  * Check whether ITC has valid value.
    342  *
    343  * Macro check whether @a itc value is valid (allowed),
    344  * macro does not check whether @a itc was really initialised.
    345  * @param itc the itc to check
    346  * @return boolean true if @a itc has valid value,
    347  *         boolean false otherwise.
    348  */
    349 #define MHD_ITC_IS_VALID_(itc)  (MHD_INVALID_SOCKET != (itc).sk[0])
    350 
    351 /**
    352  * Set @a itc to invalid value.
    353  * @param itc the itc to set
    354  */
    355 #define MHD_itc_set_invalid_(itc) \
    356   ((itc).sk[0] = (itc).sk[1] = MHD_INVALID_SOCKET)
    357 
    358 #ifndef MHD_socket_pair_nblk_
    359 #  define MHD_itc_nonblocking_(pip)          \
    360   (MHD_socket_nonblocking_ ((pip).sk[0]) &&  \
    361    MHD_socket_nonblocking_ ((pip).sk[1]))
    362 #endif /* ! MHD_socket_pair_nblk_ */
    363 
    364 #endif /* _MHD_ITC_SOCKETPAIR */
    365 
    366 /**
    367  * Destroy previously initialised ITC and abort execution
    368  * if error is detected.
    369  * @param itc the itc to destroy
    370  */
    371 #define MHD_itc_destroy_chk_(itc) do {             \
    372     if (! MHD_itc_destroy_ (itc))                  \
    373       MHD_PANIC (_ ("Failed to destroy ITC.\n"));  \
    374 } while (0)
    375 
    376 /**
    377  * Check whether ITC has invalid value.
    378  *
    379  * Macro check whether @a itc value is invalid,
    380  * macro does not check whether @a itc was destroyed.
    381  * @param itc the itc to check
    382  * @return boolean true if @a itc has invalid value,
    383  *         boolean false otherwise.
    384  */
    385 #define MHD_ITC_IS_INVALID_(itc)  (! MHD_ITC_IS_VALID_ (itc))
    386 
    387 #endif /* MHD_ITC_H */