summaryrefslogtreecommitdiff
path: root/src/tools/ocbr
diff options
context:
space:
mode:
authorDimitri Staessens <dimitri.staessens@ugent.be>2018-02-14 13:55:00 +0100
committerSander Vrijders <sander.vrijders@ugent.be>2018-02-14 17:58:51 +0100
commit91012d9af758a48c4c57fc940dfcc8a581fa46ac (patch)
tree96495c10b615ddafa94ebcfa1a0977109ec0ffe8 /src/tools/ocbr
parente095d0ade3035c714768266755c9c61acfc2ad0f (diff)
downloadouroboros-91012d9af758a48c4c57fc940dfcc8a581fa46ac.tar.gz
ouroboros-91012d9af758a48c4c57fc940dfcc8a581fa46ac.zip
build: Allow out-of-tree build of tools
This removes the dependencies for the tools on some ouroboros internal headers (endian.h and time_utils.h) so they can be built out-of-tree. The echo-app tool has been renamed oecho and the cbr tool has been renamed ocbr. Signed-off-by: Dimitri Staessens <dimitri.staessens@ugent.be> Signed-off-by: Sander Vrijders <sander.vrijders@ugent.be>
Diffstat (limited to 'src/tools/ocbr')
-rw-r--r--src/tools/ocbr/CMakeLists.txt16
-rw-r--r--src/tools/ocbr/ocbr.c159
-rw-r--r--src/tools/ocbr/ocbr_client.c164
-rw-r--r--src/tools/ocbr/ocbr_server.c260
4 files changed, 599 insertions, 0 deletions
diff --git a/src/tools/ocbr/CMakeLists.txt b/src/tools/ocbr/CMakeLists.txt
new file mode 100644
index 00000000..5dac3e63
--- /dev/null
+++ b/src/tools/ocbr/CMakeLists.txt
@@ -0,0 +1,16 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+set(SOURCE_FILES
+ # Add source files here
+ ocbr.c
+ )
+
+add_executable(ocbr ${SOURCE_FILES})
+
+target_link_libraries(ocbr LINK_PUBLIC ouroboros-dev)
+
+install(TARGETS ocbr RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/tools/ocbr/ocbr.c b/src/tools/ocbr/ocbr.c
new file mode 100644
index 00000000..2c22cc3c
--- /dev/null
+++ b/src/tools/ocbr/ocbr.c
@@ -0,0 +1,159 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2018
+ *
+ * CBR traffic generator
+ *
+ * Dimitri Staessens <dimitri.staessens@ugent.be>
+ * Sander Vrijders <sander.vrijders@ugent.be>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _POSIX_C_SOURCE 199506L
+#define __XSI_VISIBLE 500
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <time.h>
+#include <stdbool.h>
+
+#define BUF_SIZE 1500
+
+#include "ocbr_client.c"
+
+struct s {
+ long interval;
+ long timeout;
+} server_settings;
+
+#include "ocbr_server.c"
+
+static void usage(void)
+{
+ printf("Usage: cbr [OPTION]...\n"
+ "Sends SDUs from client to server at a constant bit rate.\n\n"
+ " -l, --listen Run in server mode\n"
+ "\n"
+ "Server options:\n"
+ " -i, --interval Server report interval (s)\n"
+ " -t, --timeout Server timeout interval (s)\n"
+ "\n"
+ "Client options:\n"
+ " -n, --server_apn Specify the name of the server.\n"
+ " -d, --duration Duration for sending (s)\n"
+ " -f, --flood Send SDUs as fast as possible\n"
+ " -s, --size SDU size (B)\n"
+ " -r, --rate Rate (b/s)\n"
+ " --sleep Sleep in between sending SDUs\n"
+ "\n\n"
+ " --help Display this help text and exit\n");
+}
+
+int main(int argc, char ** argv)
+{
+ int duration = 60; /* One minute test */
+ int size = 1000; /* 1000 byte SDUs */
+ long rate = 1000000; /* 1 Mb/s */
+ bool flood = false;
+ bool sleep = false;
+ int ret = 0;
+ char * rem = NULL;
+ char * s_apn = NULL;
+
+ bool server = false;
+
+ server_settings.interval = 1; /* One second reporting interval */
+ server_settings.timeout = 1;
+
+ argc--;
+ argv++;
+ while (argc > 0) {
+ if (strcmp(*argv, "-i") == 0 ||
+ strcmp(*argv, "--interval") == 0) {
+ server_settings.interval = strtol(*(++argv), &rem, 10);
+ --argc;
+ } else if (strcmp(*argv, "-t") == 0 ||
+ strcmp(*argv, "--timeout") == 0) {
+ server_settings.timeout = strtol(*(++argv), &rem, 10);
+ --argc;
+ } else if (strcmp(*argv, "-n") == 0 ||
+ strcmp(*argv, "--server_apn") == 0) {
+ s_apn = *(++argv);
+ --argc;
+ } else if (strcmp(*argv, "-d") == 0 ||
+ strcmp(*argv, "--duration") == 0) {
+ duration = strtol(*(++argv), &rem, 10);
+ --argc;
+ } else if (strcmp(*argv, "-s") == 0 ||
+ strcmp(*argv, "--size") == 0) {
+ size = strtol(*(++argv), &rem, 10);
+ --argc;
+ } else if (strcmp(*argv, "-r") == 0 ||
+ strcmp(*argv, "--rate") == 0) {
+ rate = strtol(*(++argv), &rem, 10);
+ if (*rem == 'k')
+ rate *= 1000;
+ if (*rem == 'M')
+ rate *= MILLION;
+ if (*rem == 'G')
+ rate *= BILLION;
+ --argc;
+ } else if (strcmp(*argv, "-l") == 0 ||
+ strcmp(*argv, "--listen") == 0) {
+ server = true;
+ } else if (strcmp(*argv, "-f") == 0 ||
+ strcmp(*argv, "--flood") == 0) {
+ flood = true;
+ } else if (strcmp(*argv, "--sleep") == 0) {
+ sleep = true;
+ } else {
+ usage();
+ return 0;
+ }
+ argc--;
+ argv++;
+ }
+
+ if (server) {
+ ret = server_main();
+ } else {
+ if (s_apn == NULL) {
+ printf("No server specified.\n");
+ usage();
+ return 0;
+ }
+
+ ret = client_main(s_apn, duration, size, rate, flood, sleep);
+ }
+
+ return ret;
+}
diff --git a/src/tools/ocbr/ocbr_client.c b/src/tools/ocbr/ocbr_client.c
new file mode 100644
index 00000000..bf527317
--- /dev/null
+++ b/src/tools/ocbr/ocbr_client.c
@@ -0,0 +1,164 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2018
+ *
+ * A simple CBR generator
+ *
+ * Dimitri Staessens <dimitri.staessens@ugent.be>
+ * Sander Vrijders <sander.vrijders@ugent.be>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/dev.h>
+#include <ouroboros/time_utils.h>
+
+#include <signal.h>
+
+volatile bool stop;
+
+static void shutdown_client(int signo, siginfo_t * info, void * c)
+{
+ (void) info;
+ (void) c;
+
+ switch(signo) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ stop = true;
+ default:
+ return;
+ }
+}
+
+static void busy_wait_until(const struct timespec * deadline)
+{
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ while (now.tv_sec < deadline->tv_sec)
+ clock_gettime(CLOCK_REALTIME, &now);
+ while (now.tv_sec == deadline->tv_sec
+ && now.tv_nsec < deadline->tv_nsec)
+ clock_gettime(CLOCK_REALTIME, &now);
+}
+
+int client_main(char * server,
+ int duration,
+ int size,
+ long rate,
+ bool flood,
+ bool sleep)
+{
+ struct sigaction sig_act;
+
+ int fd = 0;
+ char buf[size];
+ long seqnr = 0;
+ long gap = size * 8.0 * (BILLION / (double) rate);
+
+ struct timespec start;
+ struct timespec end;
+ struct timespec intv = {(gap / BILLION), gap % BILLION};
+ int ms;
+
+ stop = false;
+
+ memset(&sig_act, 0, sizeof sig_act);
+ sig_act.sa_sigaction = &shutdown_client;
+ sig_act.sa_flags = 0;
+
+ if (sigaction(SIGINT, &sig_act, NULL) ||
+ sigaction(SIGTERM, &sig_act, NULL) ||
+ sigaction(SIGHUP, &sig_act, NULL) ||
+ sigaction(SIGPIPE, &sig_act, NULL)) {
+ printf("Failed to install sighandler.\n");
+ return -1;
+ }
+
+ printf("Client started, duration %d, rate %lu b/s, size %d B.\n",
+ duration, rate, size);
+
+ fd = flow_alloc(server, NULL, NULL);
+ if (fd < 0) {
+ printf("Failed to allocate flow.\n");
+ return -1;
+ }
+
+ clock_gettime(CLOCK_REALTIME, &start);
+ if (!flood) {
+ while (!stop) {
+ clock_gettime(CLOCK_REALTIME, &end);
+ ts_add(&end, &intv, &end);
+ memcpy(buf, &seqnr, sizeof(seqnr));
+
+ if (flow_write(fd, buf, size) < 0) {
+ stop = true;
+ continue;
+ }
+
+ if (sleep)
+ nanosleep(&intv, NULL);
+ else
+ busy_wait_until(&end);
+
+ ++seqnr;
+
+ if (ts_diff_us(&start, &end) / MILLION >= duration)
+ stop = true;
+ }
+ } else { /* flood */
+ while (!stop) {
+ clock_gettime(CLOCK_REALTIME, &end);
+ if (flow_write(fd, buf, (size_t) size) < 0) {
+ stop = true;
+ continue;
+ }
+
+ ++seqnr;
+
+ if (ts_diff_us(&start, &end) / MILLION
+ >= (long) duration)
+ stop = true;
+ }
+
+ }
+
+ clock_gettime(CLOCK_REALTIME, &end);
+
+ ms = ts_diff_ms(&start, &end);
+
+ printf("sent statistics: "
+ "%9ld SDUs, %12ld bytes in %9d ms, %4.4f Mb/s\n",
+ seqnr, seqnr * size, ms, (seqnr / (ms * 1000.0)) * size * 8.0);
+
+ flow_dealloc(fd);
+
+ return 0;
+}
diff --git a/src/tools/ocbr/ocbr_server.c b/src/tools/ocbr/ocbr_server.c
new file mode 100644
index 00000000..874155ed
--- /dev/null
+++ b/src/tools/ocbr/ocbr_server.c
@@ -0,0 +1,260 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2018
+ *
+ * A simple CBR generator
+ *
+ * Dimitri Staessens <dimitri.staessens@ugent.be>
+ * Sander Vrijders <sander.vrijders@ugent.be>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <ouroboros/dev.h>
+#include <ouroboros/time_utils.h>
+#include <ouroboros/fccntl.h>
+
+#include <stdbool.h>
+
+#ifdef __FreeBSD__
+#define __XSI_VISIBLE 500
+#endif
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define THREADS_SIZE 10
+
+pthread_t listen_thread;
+pthread_t threads[THREADS_SIZE];
+int fds[THREADS_SIZE];
+int fds_count = 0;
+int fds_index = 0;
+pthread_mutex_t fds_lock;
+pthread_cond_t fds_signal;
+
+static void shutdown_server(int signo, siginfo_t * info, void * c)
+{
+ (void) info;
+ (void) c;
+
+ switch(signo) {
+ case SIGINT:
+ case SIGTERM:
+ case SIGHUP:
+ pthread_cancel(listen_thread);
+ default:
+ return;
+ }
+}
+
+static void handle_flow(int fd)
+{
+ int count = 0;
+ char buf[BUF_SIZE];
+
+ struct timespec now;
+ struct timespec alive;
+ struct timespec intv = {server_settings.interval, 0};
+
+ struct timespec iv_start;
+ struct timespec iv_end;
+
+ bool stop = false;
+
+ long sdus = 0;
+ long sdus_intv = 0;
+ long bytes_read = 0;
+ long bytes_read_intv = 0;
+
+
+ clock_gettime(CLOCK_REALTIME, &iv_start);
+ alive = iv_start;
+ ts_add(&iv_start, &intv, &iv_end);
+
+ fccntl(fd, FLOWSFLAGS, FLOWFNONBLOCK);
+
+ while (!stop) {
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ count = flow_read(fd, buf, BUF_SIZE);
+
+ if (count > 0) {
+ clock_gettime(CLOCK_REALTIME, &alive);
+ sdus++;
+ bytes_read += count;
+ }
+
+ if (ts_diff_us(&alive, &now)
+ > server_settings.timeout * MILLION) {
+ printf("Test on flow %d timed out\n", fd);
+ stop = true;
+ }
+
+ if (stop || ts_diff_ms(&now, &iv_end) < 0) {
+ long us = ts_diff_us(&iv_start, &now);
+ printf("Flow %4d: %9ld SDUs (%12ld bytes) in %9ld ms"
+ " => %9.4f p/s, %9.4f Mb/s\n",
+ fd,
+ sdus - sdus_intv,
+ bytes_read - bytes_read_intv,
+ us / 1000,
+ ((sdus - sdus_intv) / (double) us) * MILLION,
+ 8 * ((bytes_read - bytes_read_intv)
+ / (double)(us)));
+ iv_start = iv_end;
+ sdus_intv = sdus;
+ bytes_read_intv = bytes_read;
+ ts_add(&iv_start, &intv, &iv_end);
+ }
+ }
+
+ flow_dealloc(fd);
+}
+
+static void * worker(void * o)
+{
+ int cli_fd;
+
+ (void) o;
+
+ while (true) {
+ pthread_mutex_lock(&fds_lock);
+ pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
+ (void *) &fds_lock);
+ while (fds[fds_index] == -1)
+ pthread_cond_wait(&fds_signal, &fds_lock);
+
+ cli_fd = fds[fds_index];
+ fds[fds_index] = -1;
+
+ pthread_cleanup_pop(true);
+
+ handle_flow(cli_fd);
+
+ pthread_mutex_lock(&fds_lock);
+ fds_count--;
+
+ pthread_cond_signal(&fds_signal);
+ pthread_mutex_unlock(&fds_lock);
+ }
+
+ return 0;
+}
+
+static void * listener(void * o)
+{
+ int fd = 0;
+ qosspec_t qs;
+
+ (void) o;
+
+ printf("Server started, interval is %ld s, timeout is %ld s.\n",
+ server_settings.interval, server_settings.timeout);
+
+ while (true) {
+ pthread_mutex_lock(&fds_lock);
+ pthread_cleanup_push((void(*)(void *)) pthread_mutex_unlock,
+ (void *) &fds_lock);
+
+ while (fds_count == THREADS_SIZE) {
+ printf("Can't accept any more flows, waiting.\n");
+ pthread_cond_wait(&fds_signal, &fds_lock);
+ }
+
+ pthread_cleanup_pop(true);
+
+ fd = flow_accept(&qs, NULL);
+ if (fd < 0) {
+ printf("Failed to accept flow.\n");
+ break;
+ }
+
+ printf("New flow.\n");
+
+ pthread_mutex_lock(&fds_lock);
+
+ fds_count++;
+ fds_index = (fds_index + 1) % THREADS_SIZE;
+ fds[fds_index] = fd;
+
+ pthread_cond_signal(&fds_signal);
+ pthread_mutex_unlock(&fds_lock);
+ }
+
+ return 0;
+}
+
+int server_main(void)
+{
+ struct sigaction sig_act;
+ int i;
+
+ memset(&sig_act, 0, sizeof sig_act);
+ sig_act.sa_sigaction = &shutdown_server;
+ sig_act.sa_flags = 0;
+
+ for (i = 0; i < THREADS_SIZE; i++)
+ fds[i] = -1;
+
+ if (sigaction(SIGINT, &sig_act, NULL) ||
+ sigaction(SIGTERM, &sig_act, NULL) ||
+ sigaction(SIGHUP, &sig_act, NULL) ||
+ sigaction(SIGPIPE, &sig_act, NULL)) {
+ printf("Failed to install sighandler.\n");
+ return -1;
+ }
+
+ if (pthread_mutex_init(&fds_lock, NULL)) {
+ printf("Failed to init mutex.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (pthread_cond_init(&fds_signal, NULL)) {
+ printf("Failed to init cond.\n");
+ return -1;
+ }
+
+ for (i = 0; i < THREADS_SIZE; i++)
+ pthread_create(&threads[i], NULL, worker, NULL);
+
+ pthread_create(&listen_thread, NULL, listener, NULL);
+
+ pthread_join(listen_thread, NULL);
+
+ for (i = 0; i < THREADS_SIZE; i++)
+ pthread_cancel(threads[i]);
+
+ for (i = 0; i < THREADS_SIZE; i++)
+ pthread_join(threads[i], NULL);
+
+ return 0;
+}