commit c935fd0f80fb5758f3d28f42fbc5d3d70950e3bd
parent 5bf3e1ef50add1654ac0da42ca67412b4c6d39a9
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 16 Apr 2026 09:33:32 +0200
use libtalermhd to remove code duplication
Diffstat:
3 files changed, 92 insertions(+), 389 deletions(-)
diff --git a/configure.ac b/configure.ac
@@ -305,17 +305,6 @@ AC_ARG_ENABLE(linker-hardening,
fi])
-# logging
-extra_logging=0
-AC_ARG_ENABLE([logging],
- AS_HELP_STRING([--enable-logging@<:@=value@:>@],[Enable logging calls. Possible values: yes,no,verbose ('yes' is the default)]),
- [AS_IF([test "x$enableval" = "xyes"], [],
- [test "x$enableval" = "xno"], [AC_DEFINE([GNUNET_CULL_LOGGING],[],[Define to cull all logging calls])],
- [test "x$enableval" = "xverbose"], [extra_logging=1]
- [test "x$enableval" = "xveryverbose"], [extra_logging=2])
- ], [])
-AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise])
-
# gcov compilation
AC_MSG_CHECKING(whether to compile with support for code coverage analysis)
AC_ARG_ENABLE([coverage],
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
@@ -14,6 +14,7 @@ paivana_httpd_SOURCES = \
paivana_pd.c paivana_pd.h
paivana_httpd_LDADD = \
$(LIBGCRYPT_LIBS) \
+ -ltalermhd \
-lmicrohttpd \
-lcurl \
-ljansson \
diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c
@@ -27,14 +27,11 @@
* @brief HTTP proxy that acts as a GNU Taler paywall
*/
#include "platform.h"
-#include <microhttpd.h>
#include <curl/curl.h>
#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
+#include <taler/taler_mhd_lib.h>
#include "paivana_pd.h"
-typedef enum MHD_Result MHD_RESULT;
-
#define PAIVANA_LOG_INFO(...) \
GNUNET_log (GNUNET_ERROR_TYPE_INFO, __VA_ARGS__)
#define PAIVANA_LOG_DEBUG(...) \
@@ -258,9 +255,9 @@ static struct HttpRequest *hr_tail;
static CURLM *curl_multi;
/**
- * The daemon handle
+ * Set to true if we started a daemon.
*/
-static struct MHD_Daemon *mhd_daemon;
+static bool have_daemons;
/**
* Static paywall response.
@@ -268,11 +265,6 @@ static struct MHD_Daemon *mhd_daemon;
static struct MHD_Response *paywall;
/**
- * The task ID
- */
-static struct GNUNET_SCHEDULER_Task *httpd_task;
-
-/**
* Response we return on cURL failures.
*/
static struct MHD_Response *curl_failure_response;
@@ -288,6 +280,11 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
static int no_check;
/**
+ * Value to return from main()
+ */
+static int global_ret;
+
+/**
* Destination to which HTTP server we forward requests to.
* Of the format "http://servername:PORT"
*/
@@ -850,7 +847,7 @@ curl_download_prepare ()
* @param value field value
* @return #MHD_YES to continue to iterate
*/
-static MHD_RESULT
+static enum MHD_Result
con_val_iter (void *cls,
enum MHD_ValueKind kind,
const char *key,
@@ -1022,7 +1019,7 @@ curl_task_download (void *cls)
* #MHD_NO if the socket must be closed due to a serious
* error while handling the request
*/
-static MHD_RESULT
+static enum MHD_Result
create_response (void *cls,
struct MHD_Connection *con,
const char *url,
@@ -1466,130 +1463,12 @@ mhd_log_callback (void *cls,
/**
- * Kill the MHD daemon.
- */
-static void
-kill_httpd (void)
-{
- MHD_stop_daemon (mhd_daemon);
- mhd_daemon = NULL;
- if (NULL != httpd_task)
- {
- GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = NULL;
- }
-}
-
-
-/**
- * Task run whenever HTTP server operations are pending.
- *
- * @param cls the `struct MhdHttpList *`
- * of the daemon that is being run
- */
-static void
-do_httpd (void *cls);
-
-
-/**
- * Schedule MHD. This function should be called initially when an
- * MHD is first getting its client socket, and will then
- * automatically always be called later whenever there is work to
- * be done.
- */
-static void
-schedule_httpd (void)
-{
- fd_set rs;
- fd_set ws;
- fd_set es;
- struct GNUNET_NETWORK_FDSet *wrs;
- struct GNUNET_NETWORK_FDSet *wws;
- int max;
- int haveto;
- MHD_UNSIGNED_LONG_LONG timeout;
- struct GNUNET_TIME_Relative tv;
-
- FD_ZERO (&rs);
- FD_ZERO (&ws);
- FD_ZERO (&es);
- max = -1;
- if (MHD_YES !=
- MHD_get_fdset (mhd_daemon,
- &rs,
- &ws,
- &es,
- &max))
- {
- kill_httpd ();
- return;
- }
- haveto = MHD_get_timeout (mhd_daemon,
- &timeout);
- if (MHD_YES == haveto)
- tv.rel_value_us = (uint64_t) timeout * 1000LL;
- else
- tv = GNUNET_TIME_UNIT_FOREVER_REL;
- if (-1 != max)
- {
- wrs = GNUNET_NETWORK_fdset_create ();
- wws = GNUNET_NETWORK_fdset_create ();
- GNUNET_NETWORK_fdset_copy_native (wrs,
- &rs,
- max + 1);
- GNUNET_NETWORK_fdset_copy_native (wws,
- &ws,
- max + 1);
- }
- else
- {
- wrs = NULL;
- wws = NULL;
- }
- if (NULL != httpd_task)
- {
- GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = NULL;
- }
- httpd_task =
- GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- tv,
- wrs,
- wws,
- &do_httpd,
- NULL);
- if (NULL != wrs)
- GNUNET_NETWORK_fdset_destroy (wrs);
- if (NULL != wws)
- GNUNET_NETWORK_fdset_destroy (wws);
-}
-
-
-/**
- * Task run whenever HTTP server operations are pending.
- *
- * @param cls NULL
- */
-static void
-do_httpd (void *cls)
-{
- (void) cls;
- httpd_task = NULL;
- MHD_run (mhd_daemon);
- schedule_httpd ();
-}
-
-
-/**
* Run MHD now, we have extra data ready for the callback.
*/
static void
run_mhd_now (void)
{
- if (NULL != httpd_task)
- GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
- NULL);
+ TALER_MHD_daemon_trigger ();
}
@@ -1607,6 +1486,7 @@ do_shutdown (void *cls)
(void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Shutting down...\n");
+ TALER_MHD_daemons_halt ();
/* MHD requires resuming before destroying the daemons */
for (struct HttpRequest *hr = hr_head;
NULL != hr;
@@ -1618,7 +1498,7 @@ do_shutdown (void *cls)
MHD_resume_connection (hr->con);
}
}
- kill_httpd ();
+ TALER_MHD_daemons_destroy ();
if (NULL != curl_multi)
{
curl_multi_cleanup (curl_multi);
@@ -1634,202 +1514,10 @@ do_shutdown (void *cls)
/**
- * Connect to a unix domain socket.
- *
- * @param path the IPC path
- * @param mode the IPC path mode
- * @return the file descriptor of the connection.
- */
-static int
-open_unix_path (const char *path,
- mode_t mode)
-{
-
- struct GNUNET_NETWORK_Handle *nh;
- struct sockaddr_un *un;
- int fd;
-
- if (sizeof (un->sun_path) <= strlen (path))
- {
- fprintf (stderr,
- "path `%s' too long\n",
- path);
- return -1;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Creating listen socket '%s' with mode %o\n",
- path,
- mode);
-
- if (GNUNET_OK !=
- GNUNET_DISK_directory_create_for_file (path))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "mkdir",
- path);
- }
-
- un = GNUNET_new (struct sockaddr_un);
- un->sun_family = AF_UNIX;
-
- strncpy (un->sun_path,
- path,
- sizeof (un->sun_path) - 1);
- GNUNET_NETWORK_unix_precheck (un);
-
- if (NULL == (nh = GNUNET_NETWORK_socket_create (AF_UNIX,
- SOCK_STREAM,
- 0)))
- {
- fprintf (stderr,
- "create failed for AF_UNIX\n");
- GNUNET_free (un);
- return -1;
- }
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_bind (nh,
- (void *) un,
- sizeof (struct sockaddr_un)))
- {
- fprintf (stderr,
- "bind failed for AF_UNIX\n");
- GNUNET_free (un);
- GNUNET_NETWORK_socket_close (nh);
- return -1;
- }
- GNUNET_free (un);
- if (GNUNET_OK !=
- GNUNET_NETWORK_socket_listen (nh,
- UNIX_BACKLOG))
- {
- fprintf (stderr,
- "listen failed for AF_UNIX\n");
- GNUNET_NETWORK_socket_close (nh);
- return -1;
- }
-
- if (0 != chmod (path,
- mode))
- {
- fprintf (stderr,
- "chmod failed: %s\n",
- strerror (errno));
- GNUNET_NETWORK_socket_close (nh);
- return -1;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "set socket '%s' to mode %o\n",
- path,
- mode);
- fd = GNUNET_NETWORK_get_fd (nh);
- GNUNET_NETWORK_socket_free_memory_only_ (nh);
- return fd;
-}
-
-
-/**
- * Crawl the configuration file and extracts the serving
- * method, TCP vs IPC, and the respective details (port/path/mode)
- *
- * @param ccfg configuration handle.
- * @param port[out] port number to use
- * @param path[out] unix path for IPC.
- * @param mode[out] mode string for @a path.
- * @return #GNUNET_SYSERR if the parsing didn't succeed.
- */
-// FIXME: replace by helper function of Taler?
-static enum GNUNET_GenericReturnValue
-parse_serving_mean (const struct GNUNET_CONFIGURATION_Handle *ccfg,
- uint16_t *port,
- char **path,
- mode_t *mode)
-{
-
- const char *serve;
- const char *choices[] = {"tcp", "unix", NULL};
- char *modestring;
- unsigned long long port_ull;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_choice (ccfg,
- "paivana",
- "SERVE",
- choices,
- &serve))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paivana",
- "SERVE");
- return GNUNET_SYSERR;
- }
-
- if (0 == strcmp ("tcp", serve))
- {
- *path = NULL;
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (ccfg,
- "paivana",
- "HTTP_PORT",
- &port_ull))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paivana",
- "HTTP_PORT");
- return GNUNET_SYSERR;
- }
- *port = (uint16_t) port_ull;
- return GNUNET_OK;
- }
-
- /* serving via unix */
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (ccfg,
- "paivana",
- "SERVE_UNIXPATH",
- path))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paivana",
- "SERVE_UNIXPATH");
- return GNUNET_SYSERR;
- }
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (ccfg,
- "paivana",
- "SERVE_UNIXMODE",
- &modestring))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "paivana",
- "SERVE_UNIXMODE");
- return GNUNET_SYSERR;
- }
-
- errno = 0;
- *mode = (mode_t) strtoul (modestring, NULL, 8);
-
- if (0 != errno)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "paivana",
- "SERVE_UNIXMODE",
- "must be octal number");
- GNUNET_free (modestring);
- return GNUNET_SYSERR;
- }
- GNUNET_free (modestring);
- return GNUNET_OK;
-}
-
-
-/**
* Try to initialize the paywall response.
*/
static bool
-load_paywall ()
+load_paywall (void)
{
char *tpath;
char *fn;
@@ -1877,6 +1565,46 @@ load_paywall ()
/**
+ * Callback invoked on every listen socket to start the
+ * respective MHD HTTP daemon.
+ *
+ * @param cls unused
+ * @param lsock the listen socket
+ */
+static void
+start_daemon (void *cls,
+ int lsock)
+{
+ struct MHD_Daemon *mhd;
+
+ (void) cls;
+ GNUNET_assert (-1 != lsock);
+ mhd = MHD_start_daemon (
+ MHD_USE_DEBUG
+ | MHD_ALLOW_SUSPEND_RESUME
+ | MHD_USE_DUAL_STACK,
+ 0,
+ NULL, NULL,
+ &create_response, NULL,
+ MHD_OPTION_LISTEN_SOCKET,
+ lsock,
+ MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
+ MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
+ MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
+ MHD_OPTION_END);
+
+ if (NULL == mhd)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ have_daemons = true;
+ TALER_MHD_daemon_start (mhd);
+}
+
+
+/**
* Main function that will be run. Main tasks are (1) init. the
* curl infrastructure (curl_global_init() / curl_multi_init()),
* then fetch the HTTP port where its Web service should listen at,
@@ -1893,18 +1621,13 @@ run (void *cls,
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *c)
{
- uint16_t port = 0;
- int fh = -1;
- char *serve_unixpath = NULL;
- mode_t serve_unixmode = 0;
+ enum GNUNET_GenericReturnValue ret;
char *secret;
(void) cls;
(void) args;
(void) cfgfile;
cfg = c;
- // FIXME: initialize database logic!
-
if (0 != curl_global_init (CURL_GLOBAL_WIN32))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1986,48 +1709,32 @@ run (void *cls,
&paivana_secret);
GNUNET_free (secret);
}
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
+ NULL);
- if (GNUNET_SYSERR ==
- parse_serving_mean (c,
- &port,
- &serve_unixpath,
- &serve_unixmode))
- {
- GNUNET_break (0);
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
-
- if (NULL != serve_unixpath)
- {
- /* Connect the 'fh' socket. */
- fh = open_unix_path (serve_unixpath,
- serve_unixmode);
-
- GNUNET_assert (-1 != fh);
- }
-
- /* start MHD daemon for HTTP */
- mhd_daemon = MHD_start_daemon
- (MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME | MHD_USE_DUAL_STACK,
- (-1 == fh) ? (uint16_t) port : 0,
- NULL, NULL,
- &create_response, NULL,
- MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
- MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
- MHD_OPTION_URI_LOG_CALLBACK, &mhd_log_callback, NULL,
- MHD_OPTION_LISTEN_SOCKET, fh,
- MHD_OPTION_END);
-
- if (NULL == mhd_daemon)
+ ret = TALER_MHD_listen_bind (c,
+ "paivana",
+ &start_daemon,
+ NULL);
+ switch (ret)
{
- GNUNET_break (0);
+ case GNUNET_SYSERR:
+ global_ret = EXIT_NOTCONFIGURED;
GNUNET_SCHEDULER_shutdown ();
return;
+ case GNUNET_NO:
+ if (! have_daemons)
+ {
+ global_ret = EXIT_NOTCONFIGURED;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Could not open all configured listen sockets\n");
+ break;
+ case GNUNET_OK:
+ break;
}
- GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
- NULL);
- run_mhd_now ();
}
@@ -2047,15 +1754,21 @@ main (int argc,
&no_check),
GNUNET_GETOPT_OPTION_END
};
-
- return GNUNET_PROGRAM_run (PAIVANA_project_data (),
- argc,
- argv,
- "paivana-httpd",
- "reverse proxy requesting Taler payment",
- options,
- &run,
- NULL);
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = GNUNET_PROGRAM_run (
+ PAIVANA_project_data (),
+ argc,
+ argv,
+ "paivana-httpd",
+ "reverse proxy requesting Taler payment",
+ options,
+ &run, NULL);
+ if (GNUNET_SYSERR == ret)
+ return EXIT_INVALIDARGUMENT;
+ if (GNUNET_NO == ret)
+ return EXIT_SUCCESS;
+ return global_ret;
}