exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit a69d9259d5ceaeb84ccde37625363d8277900bd9
parent 517ddd674ab12a032c6214500e541542ebdb277f
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Fri, 13 Jun 2025 18:11:39 +0200

add SERVE=systemd option (fixes #10023)

Diffstat:
Msrc/include/taler_mhd_lib.h | 19-------------------
Msrc/mhd/mhd_config.c | 468++++++++++++++++++++++++++++++++++++++-----------------------------------------
2 files changed, 223 insertions(+), 264 deletions(-)

diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h @@ -876,25 +876,6 @@ TALER_MHD_check_content_length_ (struct MHD_Connection *connection, /** - * Parse the configuration to determine on which port - * or UNIX domain path we should run an HTTP service. - * - * @param cfg configuration to parse - * @param section section of the configuration to parse (usually "exchange") - * @param[out] rport set to the port number, or 0 for none - * @param[out] unix_path set to the UNIX path, or NULL for none - * @param[out] unix_mode set to the mode to be used for @a unix_path - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -TALER_MHD_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section, - uint16_t *rport, - char **unix_path, - mode_t *unix_mode); - - -/** * Function called for logging by MHD. * * @param cls closure, NULL diff --git a/src/mhd/mhd_config.c b/src/mhd/mhd_config.c @@ -32,136 +32,6 @@ /** - * Parse the configuration to determine on which port - * or UNIX domain path we should run an HTTP service. - * - * @param cfg configuration to parse - * @param section section of the configuration to parse (usually "exchange") - * @param[out] rport set to the port number, or 0 for none - * @param[out] unix_path set to the UNIX path, or NULL for none - * @param[out] unix_mode set to the mode to be used for @a unix_path - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -TALER_MHD_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg, - const char *section, - uint16_t *rport, - char **unix_path, - mode_t *unix_mode) -{ - const char *choices[] = { - "tcp", - "unix", - NULL - }; - const char *serve_type; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_choice (cfg, - section, - "SERVE", - choices, - &serve_type)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "SERVE", - "serve type (tcp or unix) required"); - return GNUNET_SYSERR; - } - - if (0 == strcasecmp (serve_type, - "tcp")) - { - unsigned long long port; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - section, - "PORT", - &port)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "PORT", - "port number required"); - return GNUNET_SYSERR; - } - - if ( (0 == port) || - (port > UINT16_MAX) ) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "PORT", - "port number not in [1,65535]"); - return GNUNET_SYSERR; - } - *rport = (uint16_t) port; - *unix_path = NULL; - return GNUNET_OK; - } - if (0 == strcmp (serve_type, - "unix")) - { - struct sockaddr_un s_un; - char *modestring; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - section, - "UNIXPATH", - unix_path)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH", - "UNIXPATH value required"); - return GNUNET_SYSERR; - } - if (strlen (*unix_path) >= sizeof (s_un.sun_path)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "unixpath `%s' is too long\n", - *unix_path); - GNUNET_free (*unix_path); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - section, - "UNIXPATH_MODE", - &modestring)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE"); - GNUNET_free (*unix_path); - return GNUNET_SYSERR; - } - errno = 0; - *unix_mode = (mode_t) strtoul (modestring, NULL, 8); - if (0 != errno) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE", - "must be octal number"); - GNUNET_free (modestring); - GNUNET_free (*unix_path); - return GNUNET_SYSERR; - } - GNUNET_free (modestring); - return GNUNET_OK; - } - /* not reached */ - GNUNET_assert (0); - return GNUNET_SYSERR; -} - - -/** * Function called for logging by MHD. * * @param cls closure, NULL @@ -320,10 +190,31 @@ TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, uint16_t *port) { - char *bind_to; - struct GNUNET_NETWORK_Handle *nh; + const char *choices[] = { + "tcp", + "unix", + "systemd", + NULL + }; + const char *serve_type; - /* try systemd passing first */ + *port = 0; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_choice (cfg, + section, + "SERVE", + choices, + &serve_type)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "SERVE", + "serve type (tcp, unix or systemd) required"); + return GNUNET_SYSERR; + } + + + /* try systemd passing always first */ { const char *listen_pid; const char *listen_fds; @@ -332,57 +223,111 @@ TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, listen_pid = getenv ("LISTEN_PID"); listen_fds = getenv ("LISTEN_FDS"); if ( (NULL != listen_pid) && - (NULL != listen_fds) && - (getpid () == strtol (listen_pid, - NULL, - 10)) && - (1 == strtoul (listen_fds, - NULL, - 10)) ) + (NULL != listen_fds) ) { - int fh; - int flags; - - fh = 3; - flags = fcntl (fh, - F_GETFD); - if ( (-1 == flags) && - (EBADF == errno) ) + if (0 != strcmp (serve_type, + "systemd")) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Bad listen socket passed, ignored\n"); - fh = -1; + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Using systemd activation, due to environment variables. You should set SERVE=systemd in your configuration!\n"); } - flags |= FD_CLOEXEC; - if ( (-1 != fh) && - (0 != fcntl (fh, - F_SETFD, - flags)) ) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "fcntl"); - if (-1 != fh) + if ( (getpid () == + strtol (listen_pid, + NULL, + 10)) && + (1 == strtoul (listen_fds, + NULL, + 10)) ) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Successfully obtained listen socket from hypervisor\n"); - return fh; + int fh; + int flags; + + fh = 3; + flags = fcntl (fh, + F_GETFD); + if ( (-1 == flags) && + (EBADF == errno) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Bad listen socket passed, ignored\n"); + fh = -1; + } + flags |= FD_CLOEXEC; + if ( (-1 != fh) && + (0 != fcntl (fh, + F_SETFD, + flags)) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "fcntl"); + if (-1 != fh) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Successfully obtained listen socket from hypervisor\n"); + return fh; + } } } } /* now try configuration file */ - *port = 0; + if (0 == strcmp (serve_type, + "unix")) { char *serve_unixpath; mode_t unixpath_mode; + struct sockaddr_un s_un; + char *modestring; + + *port = 0; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + section, + "UNIXPATH", + &serve_unixpath)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "UNIXPATH", + "UNIXPATH value required"); + return -1; + } + if (strlen (serve_unixpath) >= sizeof (s_un.sun_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "unixpath `%s' is too long\n", + serve_unixpath); + GNUNET_free (serve_unixpath); + return -1; + } if (GNUNET_OK != - TALER_MHD_parse_config (cfg, - section, - port, - &serve_unixpath, - &unixpath_mode)) + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "UNIXPATH_MODE", + &modestring)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "UNIXPATH_MODE"); + GNUNET_free (serve_unixpath); + return -1; + } + errno = 0; + unixpath_mode = (mode_t) strtoul (modestring, + NULL, + 8); + if (0 != errno) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "UNIXPATH_MODE", + "must be octal number"); + GNUNET_free (modestring); + GNUNET_free (serve_unixpath); return -1; - if (NULL != serve_unixpath) + } + GNUNET_free (modestring); + { int ret; @@ -392,102 +337,135 @@ TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, return ret; } } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - section, - "BIND_TO", - &bind_to)) - return -1; /* only set port */ - /* let's have fun binding... */ + if (0 == strcasecmp (serve_type, + "tcp")) { - char port_str[6]; - struct addrinfo hints; - struct addrinfo *res; - int ec; - - GNUNET_snprintf (port_str, - sizeof (port_str), - "%u", - (unsigned int) *port); - *port = 0; /* do NOT return port in case of errors */ - memset (&hints, - 0, - sizeof (hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE -#ifdef AI_IDN - | AI_IDN -#endif - ; + unsigned long long lport; + struct GNUNET_NETWORK_Handle *nh; + char *bind_to; - if (0 != - (ec = getaddrinfo (bind_to, - port_str, - &hints, - &res))) + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + section, + "PORT", + &lport)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to resolve BIND_TO address `%s': %s\n", - bind_to, - gai_strerror (ec)); - GNUNET_free (bind_to); + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "PORT", + "port number required"); return -1; } - GNUNET_free (bind_to); - if (NULL == (nh = GNUNET_NETWORK_socket_create (res->ai_family, - res->ai_socktype, - res->ai_protocol))) + if ( (0 == lport) || + (lport > UINT16_MAX) ) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "socket"); - freeaddrinfo (res); + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "PORT", + "port number not in [1,65535]"); return -1; } + *port = (uint16_t) lport; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "BIND_TO", + &bind_to)) + bind_to = NULL; + + /* let's have fun binding... */ { - const int on = 1; + char port_str[6]; + struct addrinfo hints; + struct addrinfo *res; + int ec; + + GNUNET_snprintf (port_str, + sizeof (port_str), + "%u", + (unsigned int) *port); + memset (&hints, + 0, + sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE +#ifdef AI_IDN + | AI_IDN +#endif + ; + + if (0 != + (ec = getaddrinfo (bind_to, + port_str, + &hints, + &res))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to resolve BIND_TO address `%s': %s\n", + bind_to, + gai_strerror (ec)); + GNUNET_free (bind_to); + return -1; + } + GNUNET_free (bind_to); + if (NULL == (nh = GNUNET_NETWORK_socket_create (res->ai_family, + res->ai_socktype, + res->ai_protocol))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + freeaddrinfo (res); + return -1; + } + { + const int on = 1; + + if (GNUNET_OK != + GNUNET_NETWORK_socket_setsockopt (nh, + SOL_SOCKET, + SO_REUSEPORT, + &on, + sizeof(on))) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "setsockopt"); + } if (GNUNET_OK != - GNUNET_NETWORK_socket_setsockopt (nh, - SOL_SOCKET, - SO_REUSEPORT, - &on, - sizeof(on))) - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "setsockopt"); + GNUNET_NETWORK_socket_bind (nh, + res->ai_addr, + res->ai_addrlen)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "bind"); + freeaddrinfo (res); + return -1; + } + freeaddrinfo (res); } + if (GNUNET_OK != - GNUNET_NETWORK_socket_bind (nh, - res->ai_addr, - res->ai_addrlen)) + GNUNET_NETWORK_socket_listen (nh, + UNIX_BACKLOG)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "bind"); - freeaddrinfo (res); + "listen"); + GNUNET_SCHEDULER_shutdown (); return -1; } - freeaddrinfo (res); - } - - if (GNUNET_OK != - GNUNET_NETWORK_socket_listen (nh, - UNIX_BACKLOG)) - { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, - "listen"); - GNUNET_SCHEDULER_shutdown (); - return -1; - } - /* extract and return actual socket handle from 'nh' */ - { - int fh; + /* extract and return actual socket handle from 'nh' */ + { + int fh; - fh = GNUNET_NETWORK_get_fd (nh); - GNUNET_NETWORK_socket_free_memory_only_ (nh); - return fh; + fh = GNUNET_NETWORK_get_fd (nh); + GNUNET_NETWORK_socket_free_memory_only_ (nh); + return fh; + } } + return -1; }