]> git.ipfire.org Git - fireperf.git/commitdiff
ctx: Move context initialization
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 08:38:54 +0000 (08:38 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 19 Sep 2024 08:38:54 +0000 (08:38 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/constants.h
src/ctx.c
src/ctx.h
src/main.c

index f6b3e429518ea3f815cbd925b6a6551f0857e305..3f3adab06ac706468b25348ddfa50a469008fe1a 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef FIREPERF_CONSTANTS_H
 #define FIREPERF_CONSTANTS_H
 
+#include <syslog.h>
+
 #define DEFAULT_KEEPALIVE_COUNT                        3
 #define DEFAULT_KEEPALIVE_INTERVAL                    10
 #define DEFAULT_LOG_LEVEL                       LOG_INFO
index ebf0b049ef9f2772ca11a0ad7480941e4269cfac..8f3277b2ebd01ee396f9322d8304b53f95aece2d 100644 (file)
--- a/src/ctx.c
+++ b/src/ctx.c
 #                                                                             #
 #############################################################################*/
 
+#include <arpa/inet.h>
+#include <errno.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
 #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 <https://gnu.org/licenses/gpl.html>\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);
+}
index c772b35b2e94ee71d93bae42cbbaa23be4bbc222..a069f9ff3b4cf9e68a16375dc0d5de776edf8e63 100644 (file)
--- 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 */
index afe2c762c20ba8c54e25e70354fda0ccfbda3e65..35a1f509aef62f8da2e1b10e8d9691eea4493e77 100644 (file)
 #                                                                             #
 #############################################################################*/
 
-#include <arpa/inet.h>
 #include <errno.h>
-#include <getopt.h>
-#include <netinet/in.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #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 <https://gnu.org/licenses/gpl.html>\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;
 }