commit e8bffc0ea9fdaed07ccc22bc09e2c9352277fb70
parent 8a7f3119157b8d6c2be3425353b8420051ee617e
Author: Florian Dold <florian.dold@gmail.com>
Date: Mon, 25 Apr 2016 21:02:49 +0200
unix-domain socket support
Diffstat:
2 files changed, 169 insertions(+), 21 deletions(-)
diff --git a/src/backend/merchant.conf b/src/backend/merchant.conf
@@ -5,9 +5,14 @@
# General settings for the backend.
[merchant]
+SERVE = tcp
+
# Which HTTP port does the backend listen on?
PORT = 9966
+UNIXPATH = ${TALER_RUNTIME_DIR}/merchant.http
+UNIXPATH_MODE = 660
+
# Where does the backend store the merchant's private key?
KEYFILE = ${TALER_DATA_HOME}/merchant/merchant.priv
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
@@ -19,6 +19,7 @@
* communication with the exchange
* @author Marcello Stanisci
* @author Christian Grothoff
+ * @author Florian Dold
*/
#include "platform.h"
#include <microhttpd.h>
@@ -40,6 +41,12 @@
/**
+ * Backlog for listen operation on unix-domain sockets.
+ */
+#define UNIX_BACKLOG 500
+
+
+/**
* Our wire format details in JSON format (with salt).
*/
struct json_t *j_wire;
@@ -110,6 +117,17 @@ struct TALER_MERCHANTDB_Plugin *db;
*/
static struct MHD_Daemon *mhd;
+/**
+ * Path for the unix domain-socket
+ * to run the daemon on.
+ */
+static char *serve_unixpath;
+
+/**
+ * File mode for unix-domain socket.
+ */
+static mode_t unixpath_mode;
+
/**
* A client has requested the given url using the given method
@@ -490,18 +508,6 @@ run (void *cls,
return;
}
if (GNUNET_SYSERR ==
- GNUNET_CONFIGURATION_get_value_number (config,
- "merchant",
- "PORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "merchant",
- "PORT");
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- if (GNUNET_SYSERR ==
GNUNET_CONFIGURATION_get_value_string (config,
"taler",
"currency",
@@ -583,15 +589,152 @@ run (void *cls,
return;
}
- mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME,
- port,
- NULL, NULL,
- &url_handler, NULL,
- MHD_OPTION_NOTIFY_COMPLETED,
- &handle_mhd_completion_callback, NULL,
- MHD_OPTION_CONNECTION_TIMEOUT,
- (unsigned int) 10 /* 10s */,
- MHD_OPTION_END);
+
+ {
+ const char *choices[] = {"tcp", "unix"};
+ const char *serve_type;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_choice (config,
+ "merchant",
+ "serve",
+ choices,
+ &serve_type))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "merchant",
+ "serve",
+ "serve type required");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ // FIXME: refactor two calls to MHD_start_daemon
+ // into one, using an options array instead of varags
+
+ if (0 == strcmp (serve_type, "tcp"))
+ {
+
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_number (config,
+ "merchant",
+ "PORT",
+ &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "merchant",
+ "PORT");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME,
+ port,
+ NULL, NULL,
+ &url_handler, NULL,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &handle_mhd_completion_callback, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ (unsigned int) 10 /* 10s */,
+ MHD_OPTION_END);
+ }
+ else if (0 == strcmp (serve_type, "unix"))
+ {
+ struct sockaddr_un *un;
+ unsigned long long mode;
+ struct GNUNET_NETWORK_Handle *nh;
+ int fh;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (config,
+ "merchant",
+ "unixpath",
+ &serve_unixpath))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "merchant",
+ "unixpath",
+ "unixpath required");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (strlen (serve_unixpath) >= sizeof (un->sun_path))
+ {
+ fprintf (stderr,
+ "Invalid configuration: unix path too long\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (config,
+ "merchant",
+ "unixpath_mode",
+ &mode))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "merchant",
+ "unixpath_mode",
+ "unixpath_mode required");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ unixpath_mode = (mode_t) mode;
+
+ un = GNUNET_new (struct sockaddr_un);
+ un->sun_family = AF_UNIX;
+ strncpy (un->sun_path, serve_unixpath, 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_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_OK != GNUNET_NETWORK_socket_bind (nh, (void *) un, sizeof (struct sockaddr_un)))
+ {
+ fprintf (stderr, "bind failed for AF_UNIX\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_OK != GNUNET_NETWORK_socket_listen (nh, UNIX_BACKLOG))
+ {
+ fprintf (stderr, "listen failed for AF_UNIX\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ fh = GNUNET_NETWORK_get_fd (nh);
+
+ if (0 != fchmod (fh, unixpath_mode))
+ {
+ fprintf (stderr, "chmod failed: %s\n", strerror (errno));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME,
+ 0,
+ NULL, NULL,
+ &url_handler, NULL,
+ MHD_OPTION_LISTEN_SOCKET, fh,
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &handle_mhd_completion_callback, NULL,
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ (unsigned int) 10 /* 10s */,
+ MHD_OPTION_END);
+ GNUNET_NETWORK_socket_free_memory_only_ (nh);
+ }
+ else
+ {
+ // not reached
+ GNUNET_assert (0);
+ }
+ }
+
if (NULL == mhd)
{
GNUNET_break (0);