libmicrohttpd2

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

daemon_get_info.c (11284B)


      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-2025 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/daemon_get_info.c
     41  * @brief  The implementation of MHD_daemon_get_info_*() functions
     42  * @author Karlson2k (Evgeny Grin)
     43  */
     44 
     45 #include "mhd_sys_options.h"
     46 
     47 #include "mhd_assert.h"
     48 #include "mhd_unreachable.h"
     49 
     50 #include "sys_base_types.h"
     51 #include "sys_sockets_types.h"
     52 
     53 #include "mhd_socket_type.h"
     54 #include "mhd_daemon.h"
     55 #include "events_process.h"
     56 #ifdef MHD_SUPPORT_HTTPS
     57 #  include "mhd_tls_choice.h"
     58 #  ifdef MHD_USE_MULTITLS
     59 #    include "tls_multi_daemon_data.h"
     60 #  endif
     61 #endif
     62 
     63 #include "mhd_public_api.h"
     64 
     65 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_
     66 MHD_FN_PAR_NONNULL_ (1)
     67 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode
     68 MHD_daemon_get_info_fixed_sz (
     69   struct MHD_Daemon *MHD_RESTRICT daemon,
     70   enum MHD_DaemonInfoFixedType info_type,
     71   union MHD_DaemonInfoFixedData *MHD_RESTRICT output_buf,
     72   size_t output_buf_size)
     73 {
     74   mhd_assert (! mhd_D_HAS_MASTER (daemon));
     75   if (mhd_DAEMON_STATE_STARTED > daemon->state)
     76     return MHD_SC_TOO_EARLY;
     77   if (mhd_DAEMON_STATE_STARTED < daemon->state)
     78     return MHD_SC_TOO_LATE;
     79 
     80   switch (info_type)
     81   {
     82   case MHD_DAEMON_INFO_FIXED_POLL_SYSCALL:
     83     if (mhd_WM_INT_HAS_EXT_EVENTS (daemon->wmode_int))
     84       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
     85     if (sizeof(output_buf->v_poll_syscall) > output_buf_size)
     86       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
     87     output_buf->v_poll_syscall =
     88       (enum MHD_SockPollSyscall) daemon->events.poll_type;
     89     return MHD_SC_OK;
     90   case MHD_DAEMON_INFO_FIXED_NUM_WORK_THREADS:
     91 #ifdef MHD_SUPPORT_THREADS
     92     if (! mhd_WM_INT_HAS_THREADS (daemon->wmode_int))
     93       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
     94     if (mhd_WM_INT_INTERNAL_EVENTS_THREAD_PER_CONNECTION == daemon->wmode_int)
     95       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
     96     if (sizeof(output_buf->v_num_work_threads_uint) > output_buf_size)
     97       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
     98     if (mhd_DAEMON_TYPE_SINGLE == daemon->threading.d_type)
     99       output_buf->v_num_work_threads_uint = 1;
    100     else
    101     {
    102       mhd_assert (mhd_DAEMON_TYPE_MASTER_CONTROL_ONLY == \
    103                   daemon->threading.d_type);
    104       output_buf->v_num_work_threads_uint = daemon->threading.hier.pool.num;
    105     }
    106     return MHD_SC_OK;
    107 #else  /* ! MHD_SUPPORT_THREADS */
    108     return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    109 #endif /* ! MHD_SUPPORT_THREADS */
    110   case MHD_DAEMON_INFO_FIXED_BIND_PORT:
    111     if ((MHD_INVALID_SOCKET == daemon->net.listen.fd)
    112         && ! daemon->net.listen.is_broken)
    113       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    114     if (mhd_SOCKET_TYPE_UNKNOWN > daemon->net.listen.type)
    115       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    116     if (0 == daemon->net.listen.port)
    117     {
    118       if (mhd_SOCKET_TYPE_IP != daemon->net.listen.type)
    119         return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    120       return MHD_SC_INFO_GET_TYPE_UNOBTAINABLE;
    121     }
    122     if (sizeof(output_buf->v_bind_port_uint16) > output_buf_size)
    123       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    124     output_buf->v_bind_port_uint16 = daemon->net.listen.port;
    125     return MHD_SC_OK;
    126   case MHD_DAEMON_INFO_FIXED_LISTEN_SOCKET:
    127     if (1)
    128     {
    129       MHD_Socket listen_fd = daemon->net.listen.fd;
    130       if (MHD_INVALID_SOCKET == listen_fd)
    131         return daemon->net.listen.is_broken ?
    132                MHD_SC_INFO_GET_TYPE_UNOBTAINABLE :
    133                MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    134       if (sizeof(output_buf->v_listen_socket) > output_buf_size)
    135         return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    136       output_buf->v_listen_socket = listen_fd;
    137     }
    138     return MHD_SC_OK;
    139   case MHD_DAEMON_INFO_FIXED_AGGREAGATE_FD:
    140 #ifdef MHD_SUPPORT_EPOLL
    141     if (! mhd_D_IS_USING_EPOLL (daemon))
    142       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    143     if (sizeof(output_buf->v_aggreagate_fd) > output_buf_size)
    144       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    145     output_buf->v_aggreagate_fd = daemon->events.data.epoll.e_fd;
    146     return MHD_SC_OK;
    147 #else
    148     return MHD_SC_INFO_GET_TYPE_NOT_SUPP_BY_BUILD;
    149 #endif
    150     break;
    151   case MHD_DAEMON_INFO_FIXED_TLS_BACKEND:
    152     if (sizeof(output_buf->v_tls_backend) > output_buf_size)
    153       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    154     if (! mhd_D_HAS_TLS (daemon))
    155       output_buf->v_tls_backend = MHD_TLS_BACKEND_NONE;
    156     else
    157     {
    158 #if ! defined(MHD_SUPPORT_HTTPS)
    159       mhd_UNREACHABLE ();
    160 #elif defined(MHD_USE_MULTITLS)
    161       switch (daemon->tls->choice)
    162       {
    163 #  ifdef MHD_SUPPORT_GNUTLS
    164       case mhd_TLS_MULTI_ROUTE_GNU:
    165         output_buf->v_tls_backend = MHD_TLS_BACKEND_GNUTLS;
    166         break;
    167 #  endif
    168 #  ifdef MHD_SUPPORT_OPENSSL
    169       case mhd_TLS_MULTI_ROUTE_OPEN:
    170         output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL;
    171         break;
    172 #  endif
    173 #  ifdef MHD_SUPPORT_MBEDTLS
    174       case mhd_TLS_MULTI_ROUTE_MBED:
    175         output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS;
    176         break;
    177 #  endif
    178       case mhd_TLS_MULTI_ROUTE_NONE:
    179       default:
    180         mhd_UNREACHABLE ();
    181         break;
    182       }
    183 #elif defined(MHD_SUPPORT_GNUTLS)
    184       output_buf->v_tls_backend = MHD_TLS_BACKEND_GNUTLS;
    185 #elif defined(MHD_SUPPORT_OPENSSL)
    186       output_buf->v_tls_backend = MHD_TLS_BACKEND_OPENSSL;
    187 #elif defined(MHD_SUPPORT_MBEDTLS)
    188       output_buf->v_tls_backend = MHD_TLS_BACKEND_MBEDTLS;
    189 #else
    190 #error No TLS backends enabled, while TLS support is enabled
    191 #endif
    192     }
    193     return MHD_SC_OK;
    194   case MHD_DAEMON_INFO_FIXED_DEFAULT_TIMEOUT:
    195     if (sizeof(output_buf->v_default_timeout_uint) > output_buf_size)
    196       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    197     output_buf->v_default_timeout_uint =
    198       (unsigned int) (daemon->conns.cfg.timeout_ms / 1000u);
    199     mhd_assert (output_buf->v_default_timeout_uint * 1000u == \
    200                 daemon->conns.cfg.timeout_ms);
    201     return MHD_SC_OK;
    202   case MHD_DAEMON_INFO_FIXED_GLOBAL_CONNECTION_LIMIT:
    203     if (sizeof(output_buf->v_global_connection_limit_uint) > output_buf_size)
    204       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    205     output_buf->v_global_connection_limit_uint =
    206       daemon->conns.cfg.count_limit;
    207     return MHD_SC_OK;
    208   case MHD_DAEMON_INFO_FIXED_PER_IP_LIMIT:
    209     if (sizeof(output_buf->v_per_ip_limit_uint) > output_buf_size)
    210       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    211     output_buf->v_per_ip_limit_uint = daemon->conns.cfg.per_ip_limit;
    212     return MHD_SC_OK;
    213   case MHD_DAEMON_INFO_FIXED_SUPPRESS_DATE_HEADER:
    214     if (sizeof(output_buf->v_suppress_date_header_bool) > output_buf_size)
    215       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    216     output_buf->v_suppress_date_header_bool =
    217       daemon->req_cfg.suppress_date ? MHD_YES : MHD_NO;
    218     return MHD_SC_OK;
    219   case MHD_DAEMON_INFO_FIXED_CONN_MEMORY_LIMIT:
    220     if (sizeof(output_buf->v_conn_memory_limit_sizet) > output_buf_size)
    221       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    222     output_buf->v_conn_memory_limit_sizet = daemon->conns.cfg.mem_pool_size;
    223     return MHD_SC_OK;
    224   case MHD_DAEMON_INFO_FIXED_FD_NUMBER_LIMIT:
    225 #ifdef MHD_SOCKETS_KIND_POSIX
    226     if (sizeof(output_buf->v_fd_number_limit_socket) > output_buf_size)
    227       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    228     output_buf->v_fd_number_limit_socket = daemon->net.cfg.max_fd_num;
    229     return MHD_SC_OK;
    230 #else  /* ! MHD_SOCKETS_KIND_POSIX */
    231     return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    232 #endif /* ! MHD_SOCKETS_KIND_POSIX */
    233 
    234   case MHD_DAEMON_INFO_FIXED_SENTINEL:
    235   default:
    236     break;
    237   }
    238   return MHD_SC_INFO_GET_TYPE_UNKNOWN;
    239 }
    240 
    241 
    242 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_
    243 MHD_FN_PAR_NONNULL_ (1)
    244 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode
    245 MHD_daemon_get_info_dynamic_sz (
    246   struct MHD_Daemon *MHD_RESTRICT daemon,
    247   enum MHD_DaemonInfoDynamicType info_type,
    248   union MHD_DaemonInfoDynamicData *MHD_RESTRICT output_buf,
    249   size_t output_buf_size)
    250 {
    251   mhd_assert (! mhd_D_HAS_MASTER (daemon));
    252   if (mhd_DAEMON_STATE_STARTED > daemon->state)
    253     return MHD_SC_TOO_EARLY;
    254   if (mhd_DAEMON_STATE_STARTED < daemon->state)
    255     return MHD_SC_TOO_LATE;
    256 
    257   switch (info_type)
    258   {
    259   case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT:
    260     if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int))
    261       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    262     if (sizeof(output_buf->v_max_time_to_wait_uint64) > output_buf_size)
    263       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    264     output_buf->v_max_time_to_wait_uint64 = mhd_daemon_get_wait_max (daemon);
    265     return MHD_SC_OK;
    266   case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS:
    267     if (sizeof(output_buf->v_has_connections_bool) <= output_buf_size)
    268     {
    269       enum MHD_Bool res;
    270       /*
    271          Reading number of connection from the daemon member could be non-atomic
    272          and may give wrong result (if it is modified in other thread), however
    273          test against zero/non-zero value is valid even if reading is
    274          non-atomic.
    275        */
    276       if (! mhd_D_HAS_WORKERS (daemon))
    277         res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO;
    278       else
    279       {
    280 #ifdef MHD_SUPPORT_THREADS
    281         unsigned int i;
    282         res = MHD_NO;
    283         mhd_assert (NULL != daemon->threading.hier.pool.workers);
    284         for (i = 0; i < daemon->threading.hier.pool.num; ++i)
    285         {
    286           if (0 != daemon->threading.hier.pool.workers[i].conns.count)
    287           {
    288             res = MHD_YES;
    289             break;
    290           }
    291         }
    292 #else  /* ! MHD_SUPPORT_THREADS */
    293         res = MHD_NO; /* No used, mute compiler waring */
    294 #endif /* ! MHD_SUPPORT_THREADS */
    295       }
    296       output_buf->v_has_connections_bool = res;
    297       return MHD_SC_OK;
    298     }
    299     return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    300   case MHD_DAEMON_INFO_DYNAMIC_SENTINEL:
    301   default:
    302     break;
    303   }
    304   return MHD_SC_INFO_GET_TYPE_UNKNOWN;
    305 }