libmicrohttpd2

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

daemon_get_info.c (11177B)


      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_MILSEC:
    195     if (sizeof(output_buf->v_default_timeout_milsec_uint32) > output_buf_size)
    196       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    197     output_buf->v_default_timeout_milsec_uint32 =
    198       daemon->conns.cfg.timeout_milsec;
    199     return MHD_SC_OK;
    200   case MHD_DAEMON_INFO_FIXED_GLOBAL_CONNECTION_LIMIT:
    201     if (sizeof(output_buf->v_global_connection_limit_uint) > output_buf_size)
    202       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    203     output_buf->v_global_connection_limit_uint =
    204       daemon->conns.cfg.count_limit;
    205     return MHD_SC_OK;
    206   case MHD_DAEMON_INFO_FIXED_PER_IP_LIMIT:
    207     if (sizeof(output_buf->v_per_ip_limit_uint) > output_buf_size)
    208       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    209     output_buf->v_per_ip_limit_uint = daemon->conns.cfg.per_ip_limit;
    210     return MHD_SC_OK;
    211   case MHD_DAEMON_INFO_FIXED_SUPPRESS_DATE_HEADER:
    212     if (sizeof(output_buf->v_suppress_date_header_bool) > output_buf_size)
    213       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    214     output_buf->v_suppress_date_header_bool =
    215       daemon->req_cfg.suppress_date ? MHD_YES : MHD_NO;
    216     return MHD_SC_OK;
    217   case MHD_DAEMON_INFO_FIXED_CONN_MEMORY_LIMIT:
    218     if (sizeof(output_buf->v_conn_memory_limit_sizet) > output_buf_size)
    219       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    220     output_buf->v_conn_memory_limit_sizet = daemon->conns.cfg.mem_pool_size;
    221     return MHD_SC_OK;
    222   case MHD_DAEMON_INFO_FIXED_FD_NUMBER_LIMIT:
    223 #ifdef MHD_SOCKETS_KIND_POSIX
    224     if (sizeof(output_buf->v_fd_number_limit_socket) > output_buf_size)
    225       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    226     output_buf->v_fd_number_limit_socket = daemon->net.cfg.max_fd_num;
    227     return MHD_SC_OK;
    228 #else  /* ! MHD_SOCKETS_KIND_POSIX */
    229     return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    230 #endif /* ! MHD_SOCKETS_KIND_POSIX */
    231 
    232   case MHD_DAEMON_INFO_FIXED_SENTINEL:
    233   default:
    234     break;
    235   }
    236   return MHD_SC_INFO_GET_TYPE_UNKNOWN;
    237 }
    238 
    239 
    240 MHD_EXTERN_ MHD_FN_MUST_CHECK_RESULT_
    241 MHD_FN_PAR_NONNULL_ (1)
    242 MHD_FN_PAR_NONNULL_ (3) MHD_FN_PAR_OUT_ (3) enum MHD_StatusCode
    243 MHD_daemon_get_info_dynamic_sz (
    244   struct MHD_Daemon *MHD_RESTRICT daemon,
    245   enum MHD_DaemonInfoDynamicType info_type,
    246   union MHD_DaemonInfoDynamicData *MHD_RESTRICT output_buf,
    247   size_t output_buf_size)
    248 {
    249   mhd_assert (! mhd_D_HAS_MASTER (daemon));
    250   if (mhd_DAEMON_STATE_STARTED > daemon->state)
    251     return MHD_SC_TOO_EARLY;
    252   if (mhd_DAEMON_STATE_STARTED < daemon->state)
    253     return MHD_SC_TOO_LATE;
    254 
    255   switch (info_type)
    256   {
    257   case MHD_DAEMON_INFO_DYNAMIC_MAX_TIME_TO_WAIT:
    258     if (mhd_WM_INT_HAS_THREADS (daemon->wmode_int))
    259       return MHD_SC_INFO_GET_TYPE_NOT_APPLICABLE;
    260     if (sizeof(output_buf->v_max_time_to_wait_uint64) > output_buf_size)
    261       return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    262     output_buf->v_max_time_to_wait_uint64 = mhd_daemon_get_wait_max (daemon);
    263     return MHD_SC_OK;
    264   case MHD_DAEMON_INFO_DYNAMIC_HAS_CONNECTIONS:
    265     if (sizeof(output_buf->v_has_connections_bool) <= output_buf_size)
    266     {
    267       enum MHD_Bool res;
    268       /*
    269          Reading number of connection from the daemon member could be non-atomic
    270          and may give wrong result (if it is modified in other thread), however
    271          test against zero/non-zero value is valid even if reading is
    272          non-atomic.
    273        */
    274       if (! mhd_D_HAS_WORKERS (daemon))
    275         res = (0 != daemon->conns.count) ? MHD_YES : MHD_NO;
    276       else
    277       {
    278 #ifdef MHD_SUPPORT_THREADS
    279         unsigned int i;
    280         res = MHD_NO;
    281         mhd_assert (NULL != daemon->threading.hier.pool.workers);
    282         for (i = 0; i < daemon->threading.hier.pool.num; ++i)
    283         {
    284           if (0 != daemon->threading.hier.pool.workers[i].conns.count)
    285           {
    286             res = MHD_YES;
    287             break;
    288           }
    289         }
    290 #else  /* ! MHD_SUPPORT_THREADS */
    291         res = MHD_NO; /* No used, mute compiler waring */
    292 #endif /* ! MHD_SUPPORT_THREADS */
    293       }
    294       output_buf->v_has_connections_bool = res;
    295       return MHD_SC_OK;
    296     }
    297     return MHD_SC_INFO_GET_BUFF_TOO_SMALL;
    298   case MHD_DAEMON_INFO_DYNAMIC_SENTINEL:
    299   default:
    300     break;
    301   }
    302   return MHD_SC_INFO_GET_TYPE_UNKNOWN;
    303 }