Ver código fonte

Implemented virtual MultiTLS backend

Now the TLS backend selection can be set at runtime, individually
for every daemon.
Evgeny Grin (Karlson2k) 1 ano atrás
pai
commit
e16e516c44

+ 12 - 3
configure.ac

@@ -4870,6 +4870,7 @@ have_gnutls=no
 have_gnutls_pkgcfg=no
 have_openssl=no
 have_openssl_pkgcfg=no
+multiple_tls="no"
 AS_UNSET([MHD_TLS_LIB_CPPFLAGS])
 AS_UNSET([MHD_TLS_LIB_LDFLAGS])
 AS_UNSET([MHD_TLS_LIBDEPS])
@@ -5229,7 +5230,7 @@ choke me now
     AS_IF([test "x$have_gnutls" = "xyes" || test "x$have_openssl" = "xyes"],
       [
         enable_https="yes"
-        MSG_HTTPS="yes (single backend)"
+        multiple_tls="no"
         MSG_TLS_BACKENDS=""
 
         AS_VAR_IF([have_gnutls],["yes"],
@@ -5237,7 +5238,7 @@ choke me now
             AS_IF([test -n "${MSG_TLS_BACKENDS}"],
               [
                 MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}, "
-                MSG_HTTPS="yes (multiple backends)"
+                multiple_tls="yes"
               ]
             )
             AC_DEFINE([MHD_USE_GNUTLS],[1],[Define to '1' i][f GnuTLS library should be used])
@@ -5252,7 +5253,7 @@ choke me now
             AS_IF([test -n "${MSG_TLS_BACKENDS}"],
               [
                 MSG_TLS_BACKENDS="${MSG_TLS_BACKENDS}, "
-                MSG_HTTPS="yes (multiple backends)"
+                multiple_tls="yes"
               ]
             )
             AC_DEFINE([MHD_USE_OPENSSL],[1],[Define to '1' i][f OpenSSL library should be used])
@@ -5262,6 +5263,13 @@ choke me now
             MHD_PREPEND_FLAG_TO_VAR([MHD_TLS_LIBDEPS],[$OPENSSL_LIBS])
           ]
         )
+        AS_VAR_IF([multiple_tls],["yes"],
+          [
+            MSG_HTTPS="yes (multiple backends)"
+            AC_DEFINE([mhd_HAVE_SEVERAL_TLS_BACKENDS],[1],[Define to '1' if several TLS backend are linked])
+          ],
+          [MSG_HTTPS="yes (single backend)"]
+        )
         AS_IF([test -z "$MSG_TLS_BACKENDS"],[AC_MSG_FAILURE([configure internal error: no TLS backends])])
         AC_DEFINE([MHD_ENABLE_HTTPS],[1],[Define to '1' i][f HTTPS protocol should be enabled])
       ],
@@ -5309,6 +5317,7 @@ AM_CONDITIONAL([MHD_USE_OPENSSL], [[test "x$have_openssl" = "xyes"]])
 AC_SUBST([OPENSSL_CPPFLAGS])
 AC_SUBST([OPENSSL_LDFLAGS])
 AC_SUBST([OPENSSL_LIBS])
+AM_CONDITIONAL([MHD_ENABLE_MULTITLS], [test "x$multiple_tls" = "xyes"])
 AM_CONDITIONAL([MHD_ENABLE_HTTPS], [test "x$enable_https" = "xyes"])
 
 AS_VAR_IF([have_gnutls], ["yes"],

+ 8 - 0
src/mhd2/Makefile.am

@@ -113,6 +113,10 @@ tls_common_files = \
   tls_dh_params.h \
   conn_tls_check.c          conn_tls_check.h
 
+tls_multi_files = \
+  tls_multi_tls_lib.h       tls_multi_daemon_data.h   tls_multi_conn_data.h \
+  tls_multi_funcs.c         tls_multi_funcs.h
+
 tls_gnu_files = \
   tls_gnu_tls_lib.h         tls_gnu_daemon_data.h     tls_gnu_conn_data.h \
   tls_gnu_funcs.c           tls_gnu_funcs.h
@@ -132,6 +136,10 @@ endif
 if MHD_ENABLE_HTTPS
   libmicrohttpd2_la_SOURCES += $(tls_common_files)
 
+if MHD_ENABLE_MULTITLS
+  libmicrohttpd2_la_SOURCES += $(tls_multi_files)
+endif
+
 if MHD_USE_GNUTLS
   libmicrohttpd2_la_SOURCES += $(tls_gnu_files)
 endif

+ 20 - 1
src/mhd2/mhd_tls_choice.h

@@ -102,6 +102,14 @@
 #  define MHD_USE_MULTITLS
 #endif
 
+/* Sanity check */
+#if defined(MHD_USE_MULTITLS) && ! defined(mhd_HAVE_SEVERAL_TLS_BACKENDS)
+#error several TLS backends set by configure, but only one available for code
+#endif
+#if ! defined(MHD_USE_MULTITLS) && defined(mhd_HAVE_SEVERAL_TLS_BACKENDS)
+#error several TLS backends available for code, but ony one set by configure
+#endif
+
 #ifdef MHD_USE_MULTITLS
 /**
  * Defined to one if Multi-TLS is enabled at build time or
@@ -122,7 +130,18 @@
 
 
 #if defined(MHD_USE_MULTITLS)
-// TODO: Multi-TLS implementation
+/**
+ * The TLS back-end identifier for function names
+ */
+#  define mhd_TLS_FUNC_NAME_ID multi
+/**
+ * The TLS back-end identifier for data names
+ */
+#  define mhd_TLS_DATA_NAME_ID Multi
+/**
+ * The TLS back-end identifier for macro names
+ */
+#  define mhd_TLS_MACRO_NAME_ID MULTI
 #elif defined(MHD_USE_GNUTLS)
 /**
  * The TLS back-end identifier for function names

+ 9 - 1
src/mhd2/mhd_tls_funcs.c

@@ -20,7 +20,7 @@
 
 /**
  * @file src/mhd2/mhd_tls_funcs.c
- * @brief  The TLS backend generic functions
+ * @brief  The TLS backend generic functions implementation
  * @author Karlson2k (Evgeny Grin)
  */
 
@@ -28,6 +28,14 @@
 
 #include "mhd_tls_funcs.h"
 
+/* Include all supported TLS backends headers */
+#if defined(MHD_USE_GNUTLS)
+#  include "tls_gnu_funcs.h"
+#endif
+#if defined(MHD_USE_OPENSSL)
+#  include "tls_open_funcs.h"
+#endif
+
 #include "mhd_assert.h"
 
 #include "mhd_public_api.h"

+ 8 - 1
src/mhd2/mhd_tls_funcs.h

@@ -38,7 +38,7 @@
 #endif
 
 #if defined(MHD_USE_MULTITLS)
-// TODO: Multi-TLS implementation
+#  include "tls_multi_funcs.h"
 #elif defined(MHD_USE_GNUTLS)
 #  include "tls_gnu_funcs.h"
 #elif defined(MHD_USE_OPENSSL)
@@ -59,6 +59,13 @@
 #  define mhd_tls_open_is_inited_fine() (0)
 #endif
 
+#ifndef MHD_USE_MULTITLS
+/**
+ * Check whether MultiTLS backend was successfully initialised globally
+ */
+#  define mhd_tls_multi_is_inited_fine() (0)
+#endif
+
 /* ** Global initialisation / de-initialisation ** */
 
 /**

+ 80 - 0
src/mhd2/tls_multi_conn_data.h

@@ -0,0 +1,80 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_multi_conn_data.h
+ * @brief  The definition of MultiTLS daemon-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MULTI_CONN_DATA_H
+#define MHD_TLS_MULTI_CONN_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#include "tls_multi_tls_lib.h"
+
+#ifndef MHD_USE_MULTITLS
+#error This header can be used only if MultiTLS is enabled
+#endif
+
+#ifdef MHD_USE_GNUTLS
+struct mhd_TlsGnuConnData;      /* forward declaration */
+#endif
+#ifdef MHD_USE_OPENSSL
+struct mhd_TlsOpenConnData;     /* forward declaration */
+#endif
+
+/**
+ * The pointer to the underlying TLS backend connection data
+ */
+struct mhd_TlsMultiConnRoutePtr
+{
+#ifdef MHD_USE_GNUTLS
+  /**
+   * Pointer to GnuTLS connection-specific data
+   */
+  struct mhd_TlsGnuConnData *gnutls;
+#endif
+#ifdef MHD_USE_OPENSSL
+  /**
+   * Pointer to OpenSSL connection-specific data
+   */
+  struct mhd_TlsOpenConnData *openssl;
+#endif
+};
+
+/**
+ * The structure with connection-specific MultiTLS data
+ */
+struct mhd_TlsMultiConnData
+{
+  /**
+   * The underlying TLS backend choice
+   */
+  enum mhd_TlsMultiRoute choice;
+
+  /**
+   * The pointer to the underlying TLS backend connection data
+   */
+  struct mhd_TlsMultiConnRoutePtr data;
+};
+
+#endif /* ! MHD_TLS_MULTI_CONN_DATA_H */

+ 80 - 0
src/mhd2/tls_multi_daemon_data.h

@@ -0,0 +1,80 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_multi_daemon_data.h
+ * @brief  The definition of MultiTLS daemon-specific data structures
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MULTI_DAEMON_DATA_H
+#define MHD_TLS_MULTI_DAEMON_DATA_H 1
+
+#include "mhd_sys_options.h"
+
+#include "tls_multi_tls_lib.h"
+
+#ifndef MHD_USE_MULTITLS
+#error This header can be used only if MultiTLS is enabled
+#endif
+
+#ifdef MHD_USE_GNUTLS
+struct mhd_TlsGnuDaemonData;    /* forward declaration */
+#endif
+#ifdef MHD_USE_OPENSSL
+struct mhd_TlsOpenDaemonData;   /* forward declaration */
+#endif
+
+/**
+ * The pointer to the underlying TLS backend daemon data
+ */
+struct mhd_TlsMultiDaemonRoutePtr
+{
+#ifdef MHD_USE_GNUTLS
+  /**
+   * Pointer to GnuTLS daemon-specific data
+   */
+  struct mhd_TlsGnuDaemonData *gnutls;
+#endif
+#ifdef MHD_USE_OPENSSL
+  /**
+   * Pointer to OpenSSL daemon-specific data
+   */
+  struct mhd_TlsOpenDaemonData *openssl;
+#endif
+};
+
+/**
+ * The structure with daemon-specific MultiTLS data
+ */
+struct mhd_TlsMultiDaemonData
+{
+  /**
+   * The underlying TLS backend choice
+   */
+  enum mhd_TlsMultiRoute choice;
+
+  /**
+   * The pointer to the underlying TLS backend daemon data
+   */
+  struct mhd_TlsMultiDaemonRoutePtr data;
+};
+
+#endif /* ! MHD_TLS_MULTI_DAEMON_DATA_H */

+ 558 - 0
src/mhd2/tls_multi_funcs.c

@@ -0,0 +1,558 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_multi_funcs.c
+ * @brief  The implementation of MultiTLS wrapper functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#include "mhd_sys_options.h"
+
+#include "sys_bool_type.h"
+
+#include "compat_calloc.h"
+#include "sys_malloc.h"
+#include "mhd_assert.h"
+
+#include "mhd_arr_num_elems.h"
+
+#include "tls_multi_tls_lib.h"
+
+#include "tls_multi_daemon_data.h"
+#include "tls_multi_conn_data.h"
+#include "tls_multi_funcs.h"
+
+/* Include all supported TLS backends headers */
+#if defined(MHD_USE_GNUTLS)
+#  include "tls_gnu_funcs.h"
+#endif
+#if defined(MHD_USE_OPENSSL)
+#  include "tls_open_funcs.h"
+#endif
+
+#include "daemon_options.h"
+
+#include "mhd_public_api.h"
+#include "daemon_logger.h"
+
+#ifdef mhd_USE_TLS_DEBUG_MESSAGES
+#  include <stdio.h> /* For TLS debug printing */
+#endif
+
+#ifdef mhd_USE_TLS_DEBUG_MESSAGES
+#  define mhd_M_DEBUG_PRINT(msg) \
+        do { fprintf (stderr, "## MultiTLS: " msg "\n"); \
+             fflush (stderr); } while (0)
+#  define mhd_M_DEBUG_PRINT1(msg,arg1) \
+        do { fprintf (stderr, "## MultiTLS: " msg "\n", arg1); \
+             fflush (stderr); } while (0)
+#else
+#  define mhd_M_DEBUG_PRINT(msg)        ((void) 0)
+#  define mhd_M_DEBUG_PRINT1(msg,arg1)  ((void) 0)
+#endif
+
+
+/* ** Global initialisation / de-initialisation ** */
+
+MHD_INTERNAL void
+mhd_tls_multi_global_init_once (void)
+{
+#if defined(MHD_USE_GNUTLS)
+  mhd_tls_gnu_global_init_once ();
+#endif
+#if defined(MHD_USE_OPENSSL)
+  mhd_tls_open_global_init_once ();
+#endif
+}
+
+
+MHD_INTERNAL void
+mhd_tls_multi_global_deinit (void)
+{
+  /* Note: the order is reversed to match the initialisation */
+#if defined(MHD_USE_OPENSSL)
+  mhd_tls_open_global_deinit ();
+#endif
+#if defined(MHD_USE_GNUTLS)
+  mhd_tls_gnu_global_deinit ();
+#endif
+}
+
+
+MHD_INTERNAL void
+mhd_tls_multi_global_re_init (void)
+{
+#if defined(MHD_USE_GNUTLS)
+  mhd_tls_gnu_global_re_init ();
+#endif
+#if defined(MHD_USE_OPENSSL)
+  mhd_tls_open_global_re_init ();
+#endif
+}
+
+
+/* ** Daemon initialisation / de-initialisation ** */
+
+/**
+ * Initialise selected TLS backend for the daemon
+ * @param route the selected TLS backend
+ * @param d the daemon handle
+ * @param s the daemon settings
+ * @param d_tls the daemon's TLS settings, backend-specific data is allocated
+ *              and initialised
+ * @return #MHD_SC_OK on success (the backend-specific data is allocated),
+ *         error code otherwise
+ */
+static MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (4) mhd_StatusCodeInt
+tls_daemon_init_try (enum mhd_TlsMultiRoute route,
+                     struct MHD_Daemon *restrict d,
+                     struct DaemonOptions *restrict s,
+                     struct mhd_TlsMultiDaemonData *restrict d_tls)
+{
+  mhd_StatusCodeInt res;
+
+  switch (route)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    res = mhd_tls_gnu_daemon_init (d,
+                                   s,
+                                   &(d_tls->data.gnutls));
+    if (MHD_SC_OK == res)
+    {
+      mhd_M_DEBUG_PRINT ("GnuTLS backend initialised successfully " \
+                         "for the daemon");
+      d_tls->choice = route;
+      return MHD_SC_OK;
+    }
+    mhd_M_DEBUG_PRINT1 ("Failed to initialise GnuTLS backend for " \
+                        "the daemon, error code: %u", (unsigned) res);
+    return res;
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    res = mhd_tls_open_daemon_init (d,
+                                    s,
+                                    &(d_tls->data.openssl));
+    if (MHD_SC_OK == res)
+    {
+      mhd_M_DEBUG_PRINT ("OpenSSL backend initialised successfully " \
+                         "for the daemon");
+      d_tls->choice = route;
+      return MHD_SC_OK;
+    }
+    mhd_M_DEBUG_PRINT1 ("Failed to initialise OpenSSL backend for " \
+                        "the daemon, error code: %u", (unsigned) res);
+    return res;
+#endif
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+  }
+  mhd_assert (0 && "Impossible value");
+  MHD_UNREACHABLE_;
+  return MHD_SC_INTERNAL_ERROR;
+}
+
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (3) mhd_StatusCodeInt
+mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
+                           struct DaemonOptions *restrict s,
+                           struct mhd_TlsMultiDaemonData **restrict p_d_tls)
+{
+  mhd_StatusCodeInt res;
+  struct mhd_TlsMultiDaemonData *restrict d_tls;
+  d_tls = (struct mhd_TlsMultiDaemonData *)
+          mhd_calloc (1,
+                      sizeof (struct mhd_TlsMultiDaemonData));
+  if (NULL == d_tls)
+    return MHD_SC_DAEMON_MALLOC_FAILURE;
+
+  switch (s->tls)
+  {
+  case MHD_TLS_BACKEND_ANY:
+    if (1)
+    {
+      size_t i;
+      enum mhd_TlsMultiRoute backends[] = {
+        mhd_TLS_MULTI_ROUTE_NONE  /* Not used */
+#ifdef MHD_USE_GNUTLS
+        ,
+        mhd_TLS_MULTI_ROUTE_GNU
+#endif
+#ifdef MHD_USE_OPENSSL
+        ,
+        mhd_TLS_MULTI_ROUTE_OPEN
+#endif
+      };
+      /* Try backends one-by-one */
+      for (i = 1; i < mhd_ARR_NUM_ELEMS (backends); ++i)
+      {
+        res = tls_daemon_init_try (backends[i],
+                                   d,
+                                   s,
+                                   d_tls);
+        if (MHD_SC_OK == res)
+          break;
+      }
+    }
+    break;
+#ifdef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+    res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_GNU,
+                               d,
+                               s,
+                               d_tls);
+    break;
+#endif /* MHD_USE_GNUTLS */
+#ifdef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+    res = tls_daemon_init_try (mhd_TLS_MULTI_ROUTE_OPEN,
+                               d,
+                               s,
+                               d_tls);
+#endif /* MHD_USE_OPENSSL */
+    break;
+
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case MHD_TLS_BACKEND_NONE:
+  default:
+    break;
+    mhd_assert (0 && "Should not be reachable");
+    MHD_UNREACHABLE_;
+    return MHD_SC_TLS_BACKEND_UNSUPPORTED;
+  }
+  mhd_assert (NULL != d_tls);
+  if (MHD_SC_OK == res)
+  {
+    *p_d_tls = d_tls;
+    return MHD_SC_OK;
+  }
+  free (d_tls);
+  return res;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_INOUT_ (1) void
+mhd_tls_multi_daemon_deinit (struct mhd_TlsMultiDaemonData *restrict d_tls)
+{
+  switch (d_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    mhd_tls_gnu_daemon_deinit (d_tls->data.gnutls);
+    break;
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    mhd_tls_open_daemon_deinit (d_tls->data.openssl);
+    break;
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  free (d_tls);
+}
+
+
+/* ** Connection initialisation / de-initialisation ** */
+
+MHD_INTERNAL size_t
+mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls)
+{
+  size_t data_size;
+
+  data_size = sizeof(struct mhd_TlsMultiConnData);
+  switch (d_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    data_size += mhd_tls_gnu_conn_get_tls_size (d_tls->data.gnutls);
+    break;
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    data_size += mhd_tls_open_conn_get_tls_size (d_tls->data.openssl);
+    break;
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+
+  return data_size;
+}
+
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_ (3) bool
+mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
+                         const struct mhd_ConnSocket *sk,
+                         struct mhd_TlsMultiConnData *restrict c_tls)
+{
+  c_tls->choice = d_tls->choice;
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    /* Assume the same alignment requirements for both structures */
+    c_tls->data.gnutls = (struct mhd_TlsGnuConnData *) (c_tls + 1);
+    return mhd_tls_gnu_conn_init (d_tls->data.gnutls,
+                                  sk,
+                                  c_tls->data.gnutls);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    /* Assume the same alignment requirements for both structures */
+    c_tls->data.openssl = (struct mhd_TlsOpenConnData *) (c_tls + 1);
+    return mhd_tls_open_conn_init (d_tls->data.openssl,
+                                   sk,
+                                   c_tls->data.openssl);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+
+  return false;
+}
+
+
+/**
+ * De-initialise connection TLS settings.
+ * The provided pointer is not freed/deallocated.
+ * @param c_tls the initialised connection TLS settings
+ */
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ void
+mhd_tls_multi_conn_deinit (struct mhd_TlsMultiConnData *restrict c_tls)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    mhd_tls_gnu_conn_deinit (c_tls->data.gnutls);
+    break;
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    mhd_tls_open_conn_deinit (c_tls->data.openssl);
+    break;
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+}
+
+
+/* ** TLS connection establishing ** */
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+enum mhd_TlsProcedureResult
+mhd_tls_multi_conn_handshake (struct mhd_TlsMultiConnData *restrict c_tls)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    return mhd_tls_gnu_conn_handshake (c_tls->data.gnutls);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    return mhd_tls_open_conn_handshake (c_tls->data.openssl);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  return mhd_TLS_PROCED_FAILED;
+}
+
+
+MHD_INTERNAL MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_
+enum mhd_TlsProcedureResult
+mhd_tls_multi_conn_shutdown (struct mhd_TlsMultiConnData *restrict c_tls)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    return mhd_tls_gnu_conn_shutdown (c_tls->data.gnutls);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    return mhd_tls_open_conn_shutdown (c_tls->data.openssl);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  return mhd_TLS_PROCED_FAILED;
+}
+
+
+/* ** Data receiving and sending ** */
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_OUT_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+mhd_tls_multi_conn_recv (struct mhd_TlsMultiConnData *restrict c_tls,
+                         size_t buf_size,
+                         char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+                         size_t *restrict received)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    return mhd_tls_gnu_conn_recv (c_tls->data.gnutls,
+                                  buf_size,
+                                  buf,
+                                  received);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    return mhd_tls_open_conn_recv (c_tls->data.openssl,
+                                   buf_size,
+                                   buf,
+                                   received);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  return mhd_SOCKET_ERR_INTERNAL;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_ bool
+mhd_tls_multi_conn_has_data_in (struct mhd_TlsMultiConnData *restrict c_tls)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    return mhd_tls_gnu_conn_has_data_in (c_tls->data.gnutls);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    return mhd_tls_open_conn_has_data_in (c_tls->data.openssl);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  return false;
+}
+
+
+MHD_INTERNAL MHD_FN_PAR_NONNULL_ALL_
+MHD_FN_PAR_IN_SIZE_ (3,2)
+MHD_FN_PAR_OUT_ (4) enum mhd_SocketError
+mhd_tls_multi_conn_send (struct mhd_TlsMultiConnData *restrict c_tls,
+                         size_t buf_size,
+                         const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+                         size_t *restrict sent)
+{
+  switch (c_tls->choice)
+  {
+#ifdef MHD_USE_GNUTLS
+  case mhd_TLS_MULTI_ROUTE_GNU:
+    return mhd_tls_gnu_conn_send (c_tls->data.gnutls,
+                                  buf_size,
+                                  buf,
+                                  sent);
+#endif
+#ifdef MHD_USE_OPENSSL
+  case mhd_TLS_MULTI_ROUTE_OPEN:
+    return mhd_tls_open_conn_send (c_tls->data.openssl,
+                                   buf_size,
+                                   buf,
+                                   sent);
+#endif
+#ifndef MHD_USE_GNUTLS
+  case MHD_TLS_BACKEND_GNUTLS:
+#endif /* ! MHD_USE_GNUTLS */
+#ifndef MHD_USE_OPENSSL
+  case MHD_TLS_BACKEND_OPENSSL:
+#endif /* ! MHD_USE_OPENSSL */
+  case mhd_TLS_MULTI_ROUTE_NONE:
+  default:
+    MHD_UNREACHABLE_;
+  }
+  return mhd_SOCKET_ERR_INTERNAL;
+}

+ 219 - 0
src/mhd2/tls_multi_funcs.h

@@ -0,0 +1,219 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_multi_funcs.h
+ * @brief  The declarations of MultiTLS wrapper functions
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MULTI_FUNCS_H
+#define MHD_TLS_MULTI_FUNCS_H 1
+
+#include "mhd_sys_options.h"
+
+#include "mhd_tls_choice.h"
+
+#ifndef MHD_USE_MULTITLS
+#error This header can be used only when MultiTLS is enabled
+#endif
+
+#include "sys_bool_type.h"
+#include "sys_base_types.h"
+
+#include "mhd_status_code_int.h"
+
+#include "mhd_tls_enums.h"
+#include "mhd_socket_error.h"
+
+/**
+ * The structure with daemon-specific MultiTLS data
+ */
+struct mhd_TlsMultiDaemonData;  /* Forward declaration */
+
+/**
+ * The structure with connection-specific MultiTLS data
+ */
+struct mhd_TlsMultiConnData;    /* Forward declaration */
+
+
+/* ** Global initialisation / de-initialisation ** */
+
+/**
+ * Globally initialise MultiTLS backend
+ */
+
+/**
+ * Perform one-time global initialisation of MultiTLS backend
+ */
+MHD_INTERNAL void
+mhd_tls_multi_global_init_once (void);
+
+/**
+ * Perform de-initialisation of MultiTLS backend
+ */
+MHD_INTERNAL void
+mhd_tls_multi_global_deinit (void);
+
+/**
+ * Perform re-initialisation of MultiTLS backend
+ */
+MHD_INTERNAL void
+mhd_tls_multi_global_re_init (void);
+
+
+/* ** Daemon initialisation / de-initialisation ** */
+
+struct MHD_Daemon;      /* Forward declaration */
+struct DaemonOptions;   /* Forward declaration */
+
+/**
+ * Allocate and initialise daemon TLS parameters
+ * @param d the daemon handle
+ * @param s the daemon settings
+ * @param p_d_tls the pointer to variable to set the pointer to
+ *                the daemon's TLS settings (allocated by this function)
+ * @return #MHD_SC_OK on success (p_d_tls set to the allocated settings),
+ *         error code otherwise
+ */
+MHD_INTERNAL mhd_StatusCodeInt
+mhd_tls_multi_daemon_init (struct MHD_Daemon *restrict d,
+                           struct DaemonOptions *restrict s,
+                           struct mhd_TlsMultiDaemonData **restrict p_d_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (3);
+
+/**
+ * De-initialise daemon TLS parameters (and free memory allocated for TLS
+ * settings)
+ * @param d_tls the pointer to  the daemon's TLS settings
+ */
+MHD_INTERNAL void
+mhd_tls_multi_daemon_deinit (struct mhd_TlsMultiDaemonData *restrict d_tls)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_INOUT_ (1);
+
+
+/* ** Connection initialisation / de-initialisation ** */
+
+struct mhd_ConnSocket; /* Forward declaration */
+
+/**
+ * Get size size of the connection's TLS settings
+ */
+MHD_INTERNAL size_t
+mhd_tls_multi_conn_get_tls_size (struct mhd_TlsMultiDaemonData *restrict d_tls);
+
+/**
+ * Initialise connection TLS settings
+ * @param d_tls the daemon TLS settings
+ * @param sk data about the socket for the connection
+ * @param[out] c_tls the pointer to the allocated space for
+ *                   the connection TLS settings
+ * @return 'true' on success,
+ *         'false' otherwise
+ */
+MHD_INTERNAL bool
+mhd_tls_multi_conn_init (const struct mhd_TlsMultiDaemonData *restrict d_tls,
+                         const struct mhd_ConnSocket *sk,
+                         struct mhd_TlsMultiConnData *restrict c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_ (3);
+
+/**
+ * De-initialise connection TLS settings.
+ * The provided pointer is not freed/deallocated.
+ * @param c_tls the initialised connection TLS settings
+ */
+MHD_INTERNAL void
+mhd_tls_multi_conn_deinit (struct mhd_TlsMultiConnData *restrict c_tls)
+MHD_FN_PAR_NONNULL_ALL_;
+
+
+/* ** TLS connection establishing ** */
+
+/**
+ * Perform TLS handshake
+ * @param c_tls the connection TLS handle
+ * @return #mhd_TLS_PROCED_SUCCESS if completed successfully
+ *         or other enum mhd_TlsProcedureResult values
+ */
+MHD_INTERNAL enum mhd_TlsProcedureResult
+mhd_tls_multi_conn_handshake (struct mhd_TlsMultiConnData *restrict c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Perform shutdown of TLS layer
+ * @param c_tls the connection TLS handle
+ * @return #mhd_TLS_PROCED_SUCCESS if completed successfully
+ *         or other enum mhd_TlsProcedureResult values
+ */
+MHD_INTERNAL enum mhd_TlsProcedureResult
+mhd_tls_multi_conn_shutdown (struct mhd_TlsMultiConnData *restrict c_tls)
+MHD_FN_MUST_CHECK_RESULT_ MHD_FN_PAR_NONNULL_ALL_;
+
+
+/* ** Data sending and receiving over TLS connection ** */
+
+/**
+ * Receive the data from the remote side over TLS connection
+ *
+ * @param c_tls the connection TLS handle
+ * @param buf_size the size of the @a buf buffer
+ * @param[out] buf the buffer to fill with the received data
+ * @param[out] received the pointer to variable to get the size of the data
+ *                      actually put to the @a buffer
+ * @return mhd_SOCKET_ERR_NO_ERROR if receive succeed (the @a received gets
+ *         the received size) or socket error
+ */
+MHD_INTERNAL enum mhd_SocketError
+mhd_tls_multi_conn_recv (struct mhd_TlsMultiConnData *restrict c_tls,
+                         size_t buf_size,
+                         char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+                         size_t *restrict received)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_OUT_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
+
+/**
+ * Check whether any incoming data is pending in the TLS buffers
+ *
+ * @param c_tls the connection TLS handle
+ * @return 'true' if any incoming remote data is already pending (the TLS recv()
+ *          call can be performed),
+ *         'false' otherwise
+ */
+MHD_INTERNAL bool
+mhd_tls_multi_conn_has_data_in (struct mhd_TlsMultiConnData *restrict c_tls)
+MHD_FN_PAR_NONNULL_ALL_;
+
+/**
+ * Send data to the remote side over TLS connection
+ *
+ * @param c_tls the connection TLS handle
+ * @param buffer_size the size of the @a buffer (in bytes)
+ * @param buffer content of the buffer to send
+ * @param[out] sent the pointer to get amount of actually sent bytes
+ * @return mhd_SOCKET_ERR_NO_ERROR if send succeed (the @a sent gets
+ *         the sent size) or socket error
+ */
+MHD_INTERNAL enum mhd_SocketError
+mhd_tls_multi_conn_send (struct mhd_TlsMultiConnData *restrict c_tls,
+                         size_t buf_size,
+                         const char buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)],
+                         size_t *restrict sent)
+MHD_FN_PAR_NONNULL_ALL_ MHD_FN_PAR_IN_SIZE_ (3,2) MHD_FN_PAR_OUT_ (4);
+
+#endif /* ! MHD_TLS_MULTI_FUNCS_H */

+ 64 - 0
src/mhd2/tls_multi_tls_lib.h

@@ -0,0 +1,64 @@
+/*
+  This file is part of GNU libmicrohttpd
+  Copyright (C) 2024 Evgeny Grin (Karlson2k)
+
+  GNU libmicrohttpd is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  GNU libmicrohttpd is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
+
+/**
+ * @file src/mhd2/tls_multi_tls_lib.h
+ * @brief  The header for virtual "MultiTLS" backend
+ * @author Karlson2k (Evgeny Grin)
+ */
+
+#ifndef MHD_TLS_MULTI_TLS_LIB_H
+#define MHD_TLS_MULTI_TLS_LIB_H 1
+
+#include "mhd_sys_options.h"
+
+#include "mhd_tls_choice.h"
+
+#ifndef MHD_USE_MULTITLS
+#error This header can be used only when MultiTLS is enabled
+#endif
+
+/**
+ * The underlying TLS backend choice
+ */
+enum mhd_TlsMultiRoute
+{
+  /**
+   * No TLS backend.
+   * Invalid value if TLS is used.
+   */
+  mhd_TLS_MULTI_ROUTE_NONE = 0
+#ifdef MHD_USE_GNUTLS
+  ,
+  /**
+   * Use GnuTLS backend
+   */
+  mhd_TLS_MULTI_ROUTE_GNU
+#endif
+#ifdef MHD_USE_OPENSSL
+  ,
+  /**
+   * Use OpenSSL backend
+   */
+  mhd_TLS_MULTI_ROUTE_OPEN
+#endif
+};
+
+#endif /* ! MHD_TLS_MULTI_TLS_LIB_H */