twister

HTTP fault injector for testing
Log | Files | Refs | README | LICENSE

commit 3dabe91c4dccd0f8ea8093797d70bec3ae5cf0a4
parent f66eb7244e76523b96c625ce6675b1aba2c48fb7
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date:   Thu,  6 Jun 2019 16:20:31 +0200

Adding serve mode "unix".

Diffstat:
Msrc/test/test_twister.sh | 6++++++
Msrc/twister/taler-twister-service.c | 227++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 220 insertions(+), 13 deletions(-)

diff --git a/src/test/test_twister.sh b/src/test/test_twister.sh @@ -47,6 +47,12 @@ twister_service_pid=$! echo Twister launched. +sleep 1 +if ! ps xo pid | grep ${twister_service_pid}; then + echo Twister did not start correctly + return 77 +fi + # hack the response code. taler-twister -c ./test_twister.conf --responsecode 202 diff --git a/src/twister/taler-twister-service.c b/src/twister/taler-twister-service.c @@ -54,6 +54,7 @@ #endif #define REQUEST_BUFFER_MAX (1024*1024) +#define UNIX_BACKLOG 500 /** * Log curl error. @@ -2107,6 +2108,197 @@ do_shutdown (void *cls) target_server_base_url = NULL; } +/** + * 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 cfg 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. + */ +static int +parse_serving_mean (const struct GNUNET_CONFIGURATION_Handle *cfg, + 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 (cfg, + "twister", + "SERVE", + choices, + &serve)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "twister", + "SERVE"); + return GNUNET_SYSERR; + } + + if (0 == strcmp ("tcp", serve)) + { + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number + (cfg, + "twister", + "HTTP_PORT", + &port_ull)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "twister", + "HTTP_PORT"); + return GNUNET_SYSERR; + } + *port = (uint16_t) port_ull; + return GNUNET_OK; + } + + /* serving via unix */ + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string + (cfg, + "twister", + "SERVE_UNIXPATH", + path)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "twister", + "SERVE_UNIXPATH"); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string + (cfg, + "twister", + "SERVE_UNIXMODE", + &modestring)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "twister", + "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, + "twister", + "SERVE_UNIXMODE", + "must be octal number"); + GNUNET_free (modestring); + return GNUNET_SYSERR; + } + + GNUNET_free (modestring); + + + return GNUNET_OK; +} + /** * Main function that will be run. Main tasks are (1) init. the @@ -2123,7 +2315,11 @@ run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service) { - unsigned long long port; + uint16_t port; + int fh = -1; + + char *serve_unixpath; + mode_t serve_unixmode; (void) cls; (void) service; @@ -2165,31 +2361,36 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (c, - "twister", - "HTTP_PORT", - &port)) + + if (GNUNET_SYSERR == parse_serving_mean (c, + &port, + &serve_unixpath, + &serve_unixmode)) { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "twister", - "HTTP_PORT"); + GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Proxy listens on port %llu\n", - port); + + 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, - (uint16_t) port, + (-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)