From: Michael Tremer Date: Thu, 19 Sep 2024 08:38:54 +0000 (+0000) Subject: ctx: Move context initialization X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=a9835f6a26a393e328635b348111671f6b313e35;p=fireperf.git ctx: Move context initialization Signed-off-by: Michael Tremer --- diff --git a/src/constants.h b/src/constants.h index f6b3e42..3f3adab 100644 --- a/src/constants.h +++ b/src/constants.h @@ -21,6 +21,8 @@ #ifndef FIREPERF_CONSTANTS_H #define FIREPERF_CONSTANTS_H +#include + #define DEFAULT_KEEPALIVE_COUNT 3 #define DEFAULT_KEEPALIVE_INTERVAL 10 #define DEFAULT_LOG_LEVEL LOG_INFO diff --git a/src/ctx.c b/src/ctx.c index ebf0b04..8f3277b 100644 --- a/src/ctx.c +++ b/src/ctx.c @@ -18,4 +18,273 @@ # # #############################################################################*/ +#include +#include +#include +#include +#include +#include +#include +#include + #include "ctx.h" +#include "logging.h" +#include "random.h" + +static int parse_address(const char* string, struct in6_addr* address6) { + struct in_addr address4; + + // Try parsing this address + int r = inet_pton(AF_INET6, string, address6); + + // Success! + if (r == 1) + return 0; + + // Try parsing this as an IPv4 address + r = inet_pton(AF_INET, string, &address4); + if (r == 1) { + // Convert to IPv6-mapped address + address6->s6_addr32[0] = htonl(0x0000); + address6->s6_addr32[1] = htonl(0x0000); + address6->s6_addr32[2] = htonl(0xffff); + address6->s6_addr32[3] = address4.s_addr; + + return 0; + } + + // Could not parse this + return 1; +} + +static int check_port(int port) { + if (port <= 0 || port >= 65536) { + fprintf(stderr, "Invalid port number: %u\n", port); + + return 2; + } + + return 0; +} + +static int parse_port_range(struct fireperf_ctx* ctx, const char* optarg) { + int first_port, last_port; + + int r = sscanf(optarg, "%d:%d", &first_port, &last_port); + if (r != 2) + return 1; + + // Check if both ports are in range + r = check_port(first_port); + if (r) + return r; + + r = check_port(last_port); + if (r) + return r; + + if (first_port > last_port) { + fprintf(stderr, "Invalid port range: %s\n", optarg); + return 2; + } + + ctx->port = first_port; + ctx->listening_sockets = (last_port - first_port) + 1; + + return 0; +} + +static int parse_port(struct fireperf_ctx* ctx, const char* optarg) { + ctx->port = atoi(optarg); + ctx->listening_sockets = 1; + + return check_port(ctx->port); +} + +static int parse_argv(struct fireperf_ctx* ctx, int argc, char* argv[]) { + static struct option long_options[] = { + {"client", required_argument, 0, 'c'}, + {"close", no_argument, 0, 'x'}, + {"debug", no_argument, 0, 'd'}, + {"duplex", no_argument, 0, 'D'}, + {"keepalive", no_argument, 0, 'k'}, + {"parallel", required_argument, 0, 'P'}, + {"port", required_argument, 0, 'p'}, + {"server", no_argument, 0, 's'}, + {"timeout", required_argument, 0, 't'}, + {"version", no_argument, 0, 'V'}, + {"zero", no_argument, 0, 'z'}, + {0, 0, 0, 0}, + }; + + int option_index = 0; + int done = 0; + + while (!done) { + int c = getopt_long(argc, argv, "c:dkp:st:xzDP:V", long_options, &option_index); + + // End + if (c == -1) + break; + + switch (c) { + case 0: + if (long_options[option_index].flag != 0) + break; + + printf("option %s", long_options[option_index].name); + + if (optarg) + printf(" with arg: %s", optarg); + + printf("\n"); + break; + + case '?': + // getopt_long already printed the error message + return 1; + + case 'V': + printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); + printf("Copyright (C) 2021 The IPFire Project (https://www.ipfire.org/)\n"); + printf("License GPLv3+: GNU GPL version 3 or later \n"); + printf("This is free software: you are free to change and redistribute it\n"); + printf("There is NO WARRANTY, to the extent permitted by law.\n\n"); + printf("Written by Michael Tremer\n"); + + exit(0); + break; + + case 'c': + ctx->mode = FIREPERF_MODE_CLIENT; + + // Parse the given IP address + int r = parse_address(optarg, &ctx->address); + if (r) { + fprintf(stderr, "Could not parse IP address %s\n", optarg); + return 2; + } + break; + + case 'D': + ctx->duplex = 1; + break; + + case 'd': + ctx->loglevel = LOG_DEBUG; + break; + + case 'k': + ctx->keepalive_only = 1; + break; + + case 'P': + ctx->parallel = strtoul(optarg, NULL, 10); + + if (ctx->parallel > MAX_PARALLEL) { + fprintf(stderr, "Number of parallel connections is too high: %lu\n", + ctx->parallel); + return 2; + } + break; + + case 'p': + // Try parsing the port range first. + // If this fails, we try parsing a single port + r = parse_port_range(ctx, optarg); + if (r == 1) + r = parse_port(ctx, optarg); + if (r) + return r; + + break; + + case 's': + ctx->mode = FIREPERF_MODE_SERVER; + break; + + case 't': + ctx->timeout = strtoul(optarg, NULL, 10); + break; + + case 'x': + ctx->close = 1; + break; + + case 'z': + ctx->zero = 1; + break; + + default: + done = 1; + break; + } + } + + return 0; +} + +int fireperf_ctx_create(struct fireperf_ctx** ctx, int argc, char* argv[]) { + struct fireperf_ctx* c = NULL; + int r; + + // Allocate a new context + c = calloc(1, sizeof(*c)); + if (!c) + return -errno; + + // Configure keepalive + c->keepalive_count = DEFAULT_KEEPALIVE_COUNT; + c->keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL; + + // Configure listening sockets + c->listening_sockets = DEFAULT_LISTENING_SOCKETS; + + // Configure logging + c->loglevel = DEFAULT_LOG_LEVEL; + + // Configure mode + c->mode = FIREPERF_MODE_NONE; + + // Configure port + c->port = DEFAULT_PORT; + + // Configure parallelism + c->parallel = DEFAULT_PARALLEL; + + // Fetch how many workers we would launch + c->max_workers = sysconf(_SC_NPROCESSORS_ONLN); + + // Parse the command line + r = parse_argv(c, argc, argv); + if (r) + goto ERROR; + + // Initialize random pool + if (!c->zero) { + c->pool = fireperf_random_pool_create(c, DEFAULT_RANDOM_POOL_SIZE); + if (!c->pool) { + ERROR(c, "Could not allocate random data\n"); + r = 1; + goto ERROR; + } + } + + // Return the context + *ctx = c; + + return 0; + +ERROR: + if (c) + fireperf_ctx_free(c); + + return r; +} + +void fireperf_ctx_free(struct fireperf_ctx* ctx) { + if (ctx->pool) + fireperf_random_pool_free(ctx->pool); + + free(ctx); +} diff --git a/src/ctx.h b/src/ctx.h index c772b35..a069f9f 100644 --- a/src/ctx.h +++ b/src/ctx.h @@ -56,4 +56,7 @@ struct fireperf_ctx { unsigned int max_workers; }; +int fireperf_ctx_create(struct fireperf_ctx** ctx, int argc, char* argv[]); +void fireperf_ctx_free(struct fireperf_ctx* ctx); + #endif /* FIREPERF_CTX_H */ diff --git a/src/main.c b/src/main.c index afe2c76..35a1f50 100644 --- a/src/main.c +++ b/src/main.c @@ -18,10 +18,7 @@ # # #############################################################################*/ -#include #include -#include -#include #include #include #include @@ -39,74 +36,6 @@ #include "server.h" #include "util.h" -static int parse_address(const char* string, struct in6_addr* address6) { - // Try parsing this address - int r = inet_pton(AF_INET6, string, address6); - - // Success! - if (r == 1) - return 0; - - // Try parsing this as an IPv4 address - struct in_addr address4; - r = inet_pton(AF_INET, string, &address4); - if (r == 1) { - // Convert to IPv6-mapped address - address6->s6_addr32[0] = htonl(0x0000); - address6->s6_addr32[1] = htonl(0x0000); - address6->s6_addr32[2] = htonl(0xffff); - address6->s6_addr32[3] = address4.s_addr; - - return 0; - } - - // Could not parse this - return 1; -} - -static int check_port(int port) { - if (port <= 0 || port >= 65536) { - fprintf(stderr, "Invalid port number: %u\n", port); - return 2; - } - - return 0; -} - -static int parse_port_range(struct fireperf_ctx* ctx, const char* optarg) { - int first_port, last_port; - - int r = sscanf(optarg, "%d:%d", &first_port, &last_port); - if (r != 2) - return 1; - - // Check if both ports are in range - r = check_port(first_port); - if (r) - return r; - - r = check_port(last_port); - if (r) - return r; - - if (first_port > last_port) { - fprintf(stderr, "Invalid port range: %s\n", optarg); - return 2; - } - - ctx->port = first_port; - ctx->listening_sockets = (last_port - first_port) + 1; - - return 0; -} - -static int parse_port(struct fireperf_ctx* ctx, const char* optarg) { - ctx->port = atoi(optarg); - ctx->listening_sockets = 1; - - return check_port(ctx->port); -} - static int set_limits(struct fireperf_ctx* ctx) { struct rlimit limit; @@ -132,174 +61,27 @@ static int set_limits(struct fireperf_ctx* ctx) { return 0; } -static int parse_argv(int argc, char* argv[], struct fireperf_ctx* ctx) { - static struct option long_options[] = { - {"client", required_argument, 0, 'c'}, - {"close", no_argument, 0, 'x'}, - {"debug", no_argument, 0, 'd'}, - {"duplex", no_argument, 0, 'D'}, - {"keepalive", no_argument, 0, 'k'}, - {"parallel", required_argument, 0, 'P'}, - {"port", required_argument, 0, 'p'}, - {"server", no_argument, 0, 's'}, - {"timeout", required_argument, 0, 't'}, - {"version", no_argument, 0, 'V'}, - {"zero", no_argument, 0, 'z'}, - {0, 0, 0, 0}, - }; - - int option_index = 0; - int done = 0; - - while (!done) { - int c = getopt_long(argc, argv, "c:dkp:st:xzDP:V", long_options, &option_index); - - // End - if (c == -1) - break; - - switch (c) { - case 0: - if (long_options[option_index].flag != 0) - break; - - printf("option %s", long_options[option_index].name); - - if (optarg) - printf(" with arg: %s", optarg); - - printf("\n"); - break; - - case '?': - // getopt_long already printed the error message - return 1; - - case 'V': - printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); - printf("Copyright (C) 2021 The IPFire Project (https://www.ipfire.org/)\n"); - printf("License GPLv3+: GNU GPL version 3 or later \n"); - printf("This is free software: you are free to change and redistribute it\n"); - printf("There is NO WARRANTY, to the extent permitted by law.\n\n"); - printf("Written by Michael Tremer\n"); - - exit(0); - break; - - case 'c': - ctx->mode = FIREPERF_MODE_CLIENT; - - // Parse the given IP address - int r = parse_address(optarg, &ctx->address); - if (r) { - fprintf(stderr, "Could not parse IP address %s\n", optarg); - return 2; - } - break; - - case 'D': - ctx->duplex = 1; - break; - - case 'd': - ctx->loglevel = LOG_DEBUG; - break; - - case 'k': - ctx->keepalive_only = 1; - break; - - case 'P': - ctx->parallel = strtoul(optarg, NULL, 10); - - if (ctx->parallel > MAX_PARALLEL) { - fprintf(stderr, "Number of parallel connections is too high: %lu\n", - ctx->parallel); - return 2; - } - break; - - case 'p': - // Try parsing the port range first. - // If this fails, we try parsing a single port - r = parse_port_range(ctx, optarg); - if (r == 1) - r = parse_port(ctx, optarg); - if (r) - return r; - - break; - - case 's': - ctx->mode = FIREPERF_MODE_SERVER; - break; - - case 't': - ctx->timeout = strtoul(optarg, NULL, 10); - break; - - case 'x': - ctx->close = 1; - break; - - case 'z': - ctx->zero = 1; - break; - - default: - done = 1; - break; - } - } - - return 0; -} - int main(int argc, char* argv[]) { - struct fireperf_ctx ctx = { - .keepalive_count = DEFAULT_KEEPALIVE_COUNT, - .keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL, - .listening_sockets = DEFAULT_LISTENING_SOCKETS, - .loglevel = DEFAULT_LOG_LEVEL, - .mode = FIREPERF_MODE_NONE, - .port = DEFAULT_PORT, - .parallel = DEFAULT_PARALLEL, - }; + struct fireperf_ctx* ctx = NULL; struct fireperf_stats stats = { 0 }; int r; int epollfd = -1; int timerfd = -1; - // Parse command line - r = parse_argv(argc, argv, &ctx); + // Create a new context + r = fireperf_ctx_create(&ctx, argc, argv); if (r) return r; - // Initialise random number generator - srandom(time(NULL)); - - // Fetch how many workers we would launch - ctx.max_workers = sysconf(_SC_NPROCESSORS_ONLN); - // Set limits - r = set_limits(&ctx); + r = set_limits(ctx); if (r) return r; - // Initialize random pool - if (!ctx.zero) { - ctx.pool = fireperf_random_pool_create(&ctx, DEFAULT_RANDOM_POOL_SIZE); - if (!ctx.pool) { - ERROR(&ctx, "Could not allocate random data\n"); - r = 1; - goto ERROR; - } - } - // Initialize epoll() epollfd = epoll_create1(0); if (epollfd < 0) { - ERROR(&ctx, "Could not initialize epoll(): %s\n", strerror(errno)); + ERROR(ctx, "Could not initialize epoll(): %s\n", strerror(errno)); r = 1; goto ERROR; } @@ -307,7 +89,7 @@ int main(int argc, char* argv[]) { // Create timerfd() to print statistics timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); if (timerfd < 0) { - ERROR(&ctx, "timerfd_create() failed: %s\n", strerror(errno)); + ERROR(ctx, "timerfd_create() failed: %s\n", strerror(errno)); r = 1; goto ERROR; } @@ -318,7 +100,7 @@ int main(int argc, char* argv[]) { }; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &ev)) { - ERROR(&ctx, "Could not add timerfd to epoll(): %s\n", strerror(errno)); + ERROR(ctx, "Could not add timerfd to epoll(): %s\n", strerror(errno)); r = 1; goto ERROR; } @@ -331,17 +113,17 @@ int main(int argc, char* argv[]) { r = timerfd_settime(timerfd, 0, &timer, NULL); if (r) { - ERROR(&ctx, "Could not set timer: %s\n", strerror(errno)); + ERROR(ctx, "Could not set timer: %s\n", strerror(errno)); r = 1; goto ERROR; } - switch (ctx.mode) { + switch (ctx->mode) { case FIREPERF_MODE_CLIENT: - return fireperf_client(&ctx, &stats, epollfd, timerfd); + return fireperf_client(ctx, &stats, epollfd, timerfd); case FIREPERF_MODE_SERVER: - return fireperf_server(&ctx, epollfd, timerfd); + return fireperf_server(ctx, epollfd, timerfd); case FIREPERF_MODE_NONE: fprintf(stderr, "No mode selected\n"); @@ -356,8 +138,8 @@ ERROR: if (timerfd > 0) close(timerfd); - if (ctx.pool) - fireperf_random_pool_free(ctx.pool); + if (ctx) + fireperf_ctx_free(ctx); return r; }