libmicrohttpd2

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

mhd_lib_init.c (13831B)


      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) 2024 Evgeny Grin (Karlson2k)
      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_lib_init.c
     41  * @brief  Library global initialisers and de-initialisers
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 #include "mhd_sys_options.h"
     45 
     46 #include "mhd_panic.h"
     47 
     48 #include "sys_base_types.h"
     49 #include "sys_bool_type.h"
     50 
     51 #include "mhd_locks.h"
     52 
     53 #include "mhd_socket_type.h"
     54 #ifdef MHD_SOCKETS_KIND_WINSOCK
     55 #  include <winsock2.h>
     56 #endif
     57 
     58 #include "mhd_assert.h"
     59 
     60 #ifndef NDEBUG
     61 #  include <stdio.h>  /* For debug error reporting */
     62 #  include <stdlib.h> /* For debug error exit */
     63 #endif
     64 
     65 #include "mhd_mono_clock.h"
     66 #include "mhd_send.h"
     67 #ifdef MHD_SUPPORT_HTTPS
     68 #  include "mhd_tls_funcs.h"
     69 #endif
     70 #ifdef MHD_SUPPORT_HTTP2
     71 #  include "h2/hpack/h2_huffman_codec.h"
     72 #endif
     73 
     74 #include "mhd_lib_init.h"
     75 #include "mhd_lib_init_auto.h"
     76 
     77 #ifdef AIF_W32_USR_DLLMAIN_NAME
     78 #  include <windows.h> /* For DisableThreadLibraryCalls() */
     79 #endif
     80 
     81 #if defined(mhd_AUTOINIT_FUNCS_USE)
     82 /**
     83  * The function is automatically called to perform global lazy initialisation
     84  */
     85 #  define mhd_INIT_LAZY_BY_FUNC         1
     86 #elif defined(mhd_MUTEX_INITIALISER_STAT)
     87 /**
     88  * Global lazy initialisation is performed by defined variables with static
     89  * initialisation values
     90  */
     91 #  define mhd_INIT_LAZY_BY_STATIC       1
     92 #endif
     93 
     94 #if defined(mhd_INIT_LAZY_BY_FUNC) || defined(mhd_INIT_LAZY_BY_STATIC)
     95 /**
     96  * Global lazy initialisation is automatic (either by automatic functions or
     97  * by static initialisation)
     98  */
     99 #  define mhd_INIT_LAZY_AUTOMATIC       1
    100 #endif
    101 
    102 /*
    103  * *** Minimal (lazy) initialisation section ***
    104  */
    105 
    106 /**
    107  * The magic value to determine the library initialisation status
    108  */
    109 #define mhd_LIB_INIT_MARKER_VALUE 0xB167A105 /* "Big Talos" */
    110 
    111 
    112 #ifndef mhd_INIT_LAZY_BY_STATIC
    113 #  ifdef mhd_INIT_LAZY_BY_FUNC
    114 /* Markers of performed lazy initialisation */
    115 /* Do not initialise statically to avoid breaking by too early automatic
    116    initialisation in function, which is then overwritten by library or
    117    application initialisation. */
    118 /**
    119  * The indicator of performed global lazy initialisation.
    120  * Have #mhd_LIB_INIT_MARKER_VALUE value when initialised.
    121  */
    122 static volatile uint_fast32_t mhd_lib_global_init_marker;
    123 /**
    124  * The indicator of performed global lazy initialisation.
    125  * Have (~ #mhd_LIB_INIT_MARKER_VALUE) value when initialised.
    126  */
    127 static volatile uint_fast32_t mhd_lib_global_init_Nmarker;
    128 #  else  /* ! mhd_INIT_LAZY_BY_FUNC */
    129 /* Markers of performed lazy initialisation */
    130 /**
    131  * The indicator of performed global lazy initialisation.
    132  * Have #mhd_LIB_INIT_MARKER_VALUE value when initialised.
    133  */
    134 static volatile uint_fast32_t mhd_lib_global_init_marker = 0;
    135 /**
    136  * The indicator of performed global lazy initialisation.
    137  * Have (~ #mhd_LIB_INIT_MARKER_VALUE) value when initialised.
    138  */
    139 static volatile uint_fast32_t mhd_lib_global_init_Nmarker = 0;
    140 #  endif
    141 
    142 /* Variables used for full initialisation */
    143 /**
    144  * The number of user of library global resources.
    145  * In practice the value should correspond to number of running daemons plus
    146  * number of any possible executed functions with one use of global resources.
    147  */
    148 static volatile size_t mhd_lib_use_counter;
    149 /**
    150  * Indicates that library was already fully initialised at least one time.
    151  * Some resources that do not require re-initialisation, skipped from repeated
    152  * global initialisation (after deinitialisation).
    153  */
    154 static volatile bool mhd_lib_fully_inited_once;
    155 #  ifdef MHD_SUPPORT_THREADS
    156 
    157 /**
    158  * The mutex to control access to full global initialisers and deinitialisers
    159  */
    160 static mhd_mutex mhd_init_mutex;
    161 #  endif /* MHD_SUPPORT_THREADS */
    162 #else  /* mhd_INIT_LAZY_BY_STATIC */
    163 /* Markers of performed lazy initialisation */
    164 /**
    165  * The indicator of performed global lazy initialisation.
    166  * Have #mhd_LIB_INIT_MARKER_VALUE value when initialised.
    167  */
    168 static volatile uint_fast32_t mhd_lib_global_init_marker =
    169   (uint_fast32_t) mhd_LIB_INIT_MARKER_VALUE;
    170 /**
    171  * The indicator of performed global lazy initialisation.
    172  * Have (~ #mhd_LIB_INIT_MARKER_VALUE) value when initialised.
    173  */
    174 static volatile uint_fast32_t mhd_lib_global_init_Nmarker =
    175   (uint_fast32_t) ~((uint_fast32_t) mhd_LIB_INIT_MARKER_VALUE);
    176 /* Variables used for full initialisation */
    177 /**
    178  * The number of user of library global resources.
    179  * In practice the value should correspond to number of running daemons plus
    180  * number of any possible executed functions with one use of global resources.
    181  */
    182 static volatile size_t mhd_lib_use_counter = 0;
    183 /**
    184  * Indicates that library was already fully initialised at least one time.
    185  * Some resources that do not require re-initialisation, skipped from repeated
    186  * global initialisation (after deinitialisation).
    187  */
    188 static volatile bool mhd_lib_fully_inited_once = false;
    189 /**
    190  * The mutex to control access to full global initialisers and deinitialisers
    191  */
    192 mhd_MUTEX_STATIC_DEFN_INIT (mhd_init_mutex);
    193 #endif /* mhd_INIT_LAZY_BY_STATIC */
    194 
    195 
    196 /**
    197  * Check whether the markers of initialisation set to "initialised" values.
    198  */
    199 #define mhd_LIB_INIT_LAZY_IS_PERFORMED() \
    200         ((mhd_lib_global_init_marker == \
    201           ((uint_fast32_t) mhd_LIB_INIT_MARKER_VALUE)) \
    202          && (mhd_lib_global_init_marker == ~mhd_lib_global_init_Nmarker))
    203 
    204 /**
    205  * Perform global lazy initialisation.
    206  * If library is initialised statically, this function must never be called
    207  * unless automatic initialisation has failed.
    208  * This function does not perform any checking whether the library has been
    209  * initialised before.
    210  * @return 'true' if succeed,
    211  *         'false' if failed
    212  */
    213 static bool
    214 mhd_lib_global_lazy_init (void)
    215 {
    216   mhd_panic_init_default (); /* Just set a few variables to NULL */
    217   if (! mhd_mutex_init (&mhd_init_mutex))
    218     return false;
    219   mhd_lib_fully_inited_once = false;
    220   mhd_lib_use_counter = 0;
    221   mhd_lib_global_init_marker = (uint_fast32_t) mhd_LIB_INIT_MARKER_VALUE;
    222   mhd_lib_global_init_Nmarker = (uint_fast32_t) ~mhd_lib_global_init_marker;
    223   return true;
    224 }
    225 
    226 
    227 #ifdef mhd_AUTOINIT_FUNCS_USE
    228 
    229 /**
    230  * Perform de-initialisation of the resources previously initialised by
    231  * #mhd_lib_global_lazy_init().
    232  * This function does not perform any checking whether the library has been
    233  * initialised or de-initialised before.
    234  */
    235 static void
    236 mhd_lib_global_lazy_deinit (void)
    237 {
    238   mhd_lib_global_init_Nmarker = 0u;
    239   mhd_lib_global_init_marker = 0u;
    240   (void) mhd_mutex_destroy (&mhd_init_mutex);
    241 }
    242 
    243 
    244 #endif /* mhd_AUTOINIT_FUNCS_USE */
    245 
    246 
    247 /*
    248  * *** The automatically called functions section ***
    249  */
    250 
    251 #ifdef mhd_AUTOINIT_FUNCS_USE
    252 
    253 void
    254 mhd_lib_global_init_auto (void)
    255 {
    256   if (! mhd_lib_global_lazy_init ())
    257   {
    258     (void) 0;
    259     /* Do not abort in non-debug builds, weak workarounds will be used */
    260 #ifndef NDEBUG
    261     MHD_PANIC ("Failed to initialise the MHD library");
    262 #endif /* ! NDEBUG */
    263   }
    264 }
    265 
    266 
    267 void
    268 mhd_lib_global_deinit_auto (void)
    269 {
    270 #ifndef NDEBUG
    271   if (! mhd_LIB_INIT_LAZY_IS_PERFORMED ())
    272   {
    273     fprintf (stderr, "Automatic MHD library initialisation has not been "
    274              "performed, but the library de-initialisation is called.\n");
    275     fflush (stderr);
    276     abort ();
    277   }
    278   if (0 != mhd_lib_use_counter)
    279   {
    280     fprintf (stderr, "Automatic MHD library de-initialisation started, but "
    281              "some MHD resources are still in use by the application.\n");
    282     fflush (stderr);
    283   }
    284 #endif /* ! NDEBUG */
    285   mhd_lib_global_lazy_deinit ();
    286 }
    287 
    288 
    289 #  ifdef AIF_W32_USR_DLLMAIN_NAME
    290 
    291 AIF_DECL_USR_DLLMAIN /* Declare the function */
    292 
    293 /* MHD is used on W32 as DLL library with DLL runtime lib */
    294 /**
    295  * Special automatically called function for DLL initialisation on W32.
    296  * @param hinst the DLL module handle
    297  * @param reason the code of the call reason
    298  * @param pReserved NULL is statically loaded, non-NULL if loaded dynamically
    299  * @return TRUE if succeed (always),
    300  *         FALSE if failed
    301  */
    302 BOOL WINAPI
    303 AUTOINIT_FUNCS_USR_DLLMAIN_NAME (HINSTANCE hinst,
    304                                  DWORD reason,
    305                                  LPVOID pReserved)
    306 {
    307   (void) pReserved; /* Not used */
    308 
    309   /* Disable calls with DLL_THREAD_ATTACH and DLL_THREAD_DETACH messages */
    310   if (AIF_W32_DLL_PROCESS_ATTACH == reason)
    311     (void) DisableThreadLibraryCalls ((HMODULE) hinst);
    312 
    313   return TRUE;
    314 }
    315 
    316 
    317 #  endif /* AIF_W32_USR_DLLMAIN_NAME */
    318 
    319 #endif /* mhd_AUTOINIT_FUNCS_USE */
    320 
    321 
    322 /*
    323  * *** Full global initialisation, deinitialisation and re-initialisaion ***
    324  */
    325 
    326 #if defined(MHD_SOCKETS_KIND_WINSOCK)
    327 /**
    328  * Initialise W32 sockets
    329  * @return 'true' if succeed,
    330  *         'false' if failed
    331  */
    332 mhd_static_inline bool
    333 mhd_lib_sockets_init_w32 (void)
    334 {
    335   WSADATA wsd;
    336   if (0 != WSAStartup (MAKEWORD (2, 2), &wsd))
    337     return false;
    338   if (MAKEWORD (2, 2) != wsd.wVersion)
    339   {
    340     WSACleanup ();
    341     return false;
    342   }
    343   return true;
    344 }
    345 
    346 
    347 /**
    348  * De-initialise W32 sockets
    349  */
    350 mhd_static_inline void
    351 mhd_lib_sockets_deinit_w32 (void)
    352 {
    353   (void) WSACleanup ();
    354 }
    355 
    356 
    357 #else  /* ! MHD_SOCKETS_KIND_WINSOCK */
    358 /* No-op implementations */
    359 #  define mhd_lib_sockets_init_w32() (true)
    360 #  define mhd_lib_sockets_deinit_w32() ((void) 0)
    361 #endif /* ! MHD_SOCKETS_KIND_WINSOCK */
    362 
    363 /**
    364  * Perform full initialisation of MHD library global resources.
    365  * Must be called only with initialisation lock held.
    366  * @return 'true' if succeed,
    367  *         'false' if failed
    368  */
    369 static bool
    370 mhd_lib_global_full_init_once (void)
    371 {
    372   mhd_assert (mhd_LIB_INIT_LAZY_IS_PERFORMED ());
    373   mhd_assert (! mhd_lib_fully_inited_once);
    374   mhd_assert (0 == mhd_lib_use_counter);
    375 
    376   if (! mhd_lib_sockets_init_w32 ())
    377     return false;
    378   mhd_mclock_init_once ();
    379   mhd_send_init_once ();
    380 #ifdef MHD_SUPPORT_HTTPS
    381   mhd_tls_global_init_once ();
    382 #endif /* MHD_SUPPORT_HTTPS */
    383 #ifdef MHD_SUPPORT_HTTP2
    384   mhd_h2_huffman_init ();
    385 #endif /* MHD_SUPPORT_HTTP2 */
    386 
    387   mhd_lib_fully_inited_once = true;
    388 
    389   return true;
    390 }
    391 
    392 
    393 /**
    394  * Release library global resources allocated
    395  * by #mhd_lib_global_full_init_once()
    396  */
    397 static void
    398 mhd_lib_global_full_deinit (void)
    399 {
    400 #ifdef MHD_SUPPORT_HTTPS
    401   mhd_tls_global_deinit ();
    402 #endif /* MHD_SUPPORT_HTTPS */
    403   mhd_mclock_deinit ();
    404   mhd_lib_sockets_deinit_w32 ();
    405 }
    406 
    407 
    408 /**
    409  * Re-initialise library global resources after
    410  * de-initialistion by #mhd_lib_global_full_deinit().
    411  * This function can be called many times.
    412  * @return 'true' if succeed,
    413  *         'false' if failed
    414  */
    415 static bool
    416 mhd_lib_global_full_re_init (void)
    417 {
    418   mhd_assert (mhd_lib_fully_inited_once);
    419   if (! mhd_lib_sockets_init_w32 ())
    420     return false;
    421   mhd_mclock_re_init ();
    422 #ifdef MHD_SUPPORT_HTTPS
    423   mhd_tls_global_re_init ();
    424 #endif /* MHD_SUPPORT_HTTPS */
    425 
    426   return true;
    427 }
    428 
    429 
    430 /*
    431  * *** Automatic global initialisation and deinitialisation for daemons ***
    432  */
    433 
    434 MHD_INTERNAL bool
    435 mhd_lib_init_global_if_needed (void)
    436 {
    437   bool ret;
    438   if (! mhd_LIB_INIT_LAZY_IS_PERFORMED ())
    439   {
    440 #if defined (mhd_INIT_LAZY_AUTOMATIC) && ! defined(NDEBUG)
    441     /* Problem detected: the library must be already initialised
    442        automatically, but it is not.  */
    443     abort (); /* abort if this is a debug build */
    444 #else  /* !mhd_INIT_LAZY_AUTOMATIC || NDEBUG */
    445     if (! mhd_lib_global_lazy_init ()) /* Not thread safe, but no choice here */
    446       return false;
    447 #endif /* !mhd_INIT_LAZY_AUTOMATIC || NDEBUG */
    448   }
    449 
    450   if (! mhd_mutex_lock (&mhd_init_mutex))
    451     return false;
    452   if (0 == mhd_lib_use_counter)
    453   {
    454     if (! mhd_lib_fully_inited_once)
    455       ret = mhd_lib_global_full_init_once ();
    456     else
    457       ret = mhd_lib_global_full_re_init ();
    458   }
    459   else
    460   {
    461     mhd_assert (mhd_lib_fully_inited_once);
    462     ret = true;
    463   }
    464   if (ret)
    465     ++mhd_lib_use_counter;
    466   mhd_mutex_unlock_chk (&mhd_init_mutex);
    467 
    468   return ret;
    469 }
    470 
    471 
    472 MHD_INTERNAL void
    473 mhd_lib_deinit_global_if_needed (void)
    474 {
    475   mhd_assert (0 != mhd_lib_use_counter);
    476 
    477   mhd_mutex_lock_chk (&mhd_init_mutex);
    478   if (0 == --mhd_lib_use_counter)
    479     mhd_lib_global_full_deinit ();
    480   mhd_mutex_unlock_chk (&mhd_init_mutex);
    481 }
    482 
    483 
    484 MHD_INTERNAL bool
    485 mhd_lib_is_fully_initialised_once (void)
    486 {
    487   return mhd_LIB_INIT_LAZY_IS_PERFORMED () && mhd_lib_fully_inited_once;
    488 }
    489 
    490 
    491 MHD_INTERNAL bool
    492 mhd_lib_is_fully_initialised_now (void)
    493 {
    494   return mhd_lib_is_fully_initialised_once () && (0 != mhd_lib_use_counter);
    495 }