summaryrefslogtreecommitdiff
path: root/src/tools/oping
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/oping')
-rw-r--r--src/tools/oping/oping.c179
-rw-r--r--src/tools/oping/oping_client.c67
-rw-r--r--src/tools/oping/oping_server.c42
3 files changed, 207 insertions, 81 deletions
diff --git a/src/tools/oping/oping.c b/src/tools/oping/oping.c
index 3c1d4fe9..ed3529e5 100644
--- a/src/tools/oping/oping.c
+++ b/src/tools/oping/oping.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2018
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -42,9 +42,11 @@
#include <ouroboros/dev.h>
#include <ouroboros/fccntl.h>
#include <ouroboros/fqueue.h>
+#include <ouroboros/qos.h>
#include "time_utils.h"
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
@@ -58,22 +60,43 @@
#include <errno.h>
#include <float.h>
-#define OPING_BUF_SIZE 1500
-
-#define ECHO_REQUEST 0
-#define ECHO_REPLY 1
-
+#define OPING_BUF_SIZE 1500
+#define ECHO_REQUEST 0
+#define ECHO_REPLY 1
#define OPING_MAX_FLOWS 256
-struct c {
- char * s_apn;
- int interval;
- uint32_t count;
- int size;
+#define USAGE_STRING \
+"Usage: oping [OPTION]...\n" \
+"\n" \
+"Checks liveness between a client and a server\n" \
+"and reports the Round Trip Time (RTT)\n" \
+"\n" \
+" -l, --listen Run in server mode\n" \
+"\n" \
+" -c, --count Number of packets\n" \
+" -d, --duration Duration of the test (default 1s)\n" \
+" -i, --interval Interval (default 1000ms)\n" \
+" -n, --server-name Name of the oping server\n" \
+" -q, --qos QoS (raw, raw_crypt, best, video, voice, data)\n" \
+" -s, --size Payload size (B, default 64)\n" \
+" -Q, --quiet Only print final statistics\n" \
+" -D, --timeofday Print time of day before each line\n" \
+"\n" \
+" --help Display this help text and exit\n" \
+
+struct {
+ char * s_apn;
+ int interval;
+ uint32_t count;
+ int size;
+ bool timestamp;
+ qosspec_t qs;
/* stats */
uint32_t sent;
uint32_t rcvd;
+ size_t ooo;
+ bool quiet;
double rtt_min;
double rtt_max;
@@ -84,12 +107,14 @@ struct c {
pthread_t writer_pt;
} client;
-struct s {
+struct {
struct timespec times[OPING_MAX_FLOWS];
fset_t * flows;
fqueue_t * fq;
pthread_mutex_t lock;
+ bool quiet;
+
pthread_t cleaner_pt;
pthread_t accept_pt;
pthread_t server_pt;
@@ -108,67 +133,130 @@ struct oping_msg {
static void usage(void)
{
- printf("Usage: oping [OPTION]...\n"
- "Checks liveness between a client and a server\n"
- "and reports the Round Trip Time (RTT)\n\n"
- " -l, --listen Run in server mode\n"
- "\n"
- " -c, --count Number of packets (default 1000)\n"
- " -i, --interval Interval (ms, default 1000)\n"
- " -n, --server-apn Name of the oping server\n"
- " -s, --size Payload size (B, default 64)\n"
- " --help Display this help text and exit\n");
+ printf(USAGE_STRING);
+}
+
+/* Times are in ms. */
+static int time_mul(const char * rem)
+{
+ if (strcmp(rem, "ms") == 0 || strcmp(rem, "") == 0)
+ return 1;
+ else if(strcmp(rem, "s") == 0)
+ return 1000;
+ else if (strcmp(rem, "m") == 0)
+ return 60 * 1000;
+ else if (strcmp(rem, "h") == 0)
+ return 60 * 60 * 1000;
+ else if (strcmp(rem, "d") == 0)
+ return 60 * 60 * 24 * 1000;
+
+ printf("Unknown time unit: %s.\n", rem);
+
+ exit(EXIT_FAILURE);
}
-int main(int argc, char ** argv)
+int main(int argc,
+ char ** argv)
{
- int ret = -1;
- char * rem = NULL;
- bool serv = false;
+ int ret = -1;
+ char * rem = NULL;
+ bool serv = false;
+ long duration = 0;
+ char * qos = NULL;
argc--;
argv++;
- client.s_apn = NULL;
- client.interval = 1000;
- client.size = 64;
- client.count = 1000;
+ client.s_apn = NULL;
+ client.interval = 1000;
+ client.size = 64;
+ client.count = INT_MAX;
+ client.timestamp = false;
+ client.qs = qos_raw;
+ client.quiet = false;
+ server.quiet = false;
while (argc > 0) {
- if (strcmp(*argv, "-i") == 0 ||
- strcmp(*argv, "--interval") == 0) {
+ if ((strcmp(*argv, "-i") == 0 ||
+ strcmp(*argv, "--interval") == 0) &&
+ argc > 1) {
client.interval = strtol(*(++argv), &rem, 10);
+ client.interval *= time_mul(rem);
--argc;
- } else if (strcmp(*argv, "-n") == 0 ||
- strcmp(*argv, "--server_apn") == 0) {
+ } else if ((strcmp(*argv, "-n") == 0 ||
+ strcmp(*argv, "--server-name") == 0) &&
+ argc > 1) {
client.s_apn = *(++argv);
--argc;
- } else if (strcmp(*argv, "-c") == 0 ||
- strcmp(*argv, "--count") == 0) {
+ } else if ((strcmp(*argv, "-c") == 0 ||
+ strcmp(*argv, "--count") == 0) &&
+ argc > 1) {
client.count = strtol(*(++argv), &rem, 10);
--argc;
- } else if (strcmp(*argv, "-s") == 0 ||
- strcmp(*argv, "--size") == 0) {
+ } else if ((strcmp(*argv, "-d") == 0 ||
+ strcmp(*argv, "--duration") == 0) &&
+ argc > 1) {
+ duration = strtol(*(++argv), &rem, 10);
+ duration *= time_mul(rem);
+ --argc;
+ } else if ((strcmp(*argv, "-s") == 0 ||
+ strcmp(*argv, "--size") == 0) &&
+ argc > 1) {
client.size = strtol(*(++argv), &rem, 10);
--argc;
+ } else if ((strcmp(*argv, "-q") == 0 ||
+ strcmp(*argv, "--qos") == 0) &&
+ argc > 1) {
+ qos = *(++argv);
+ --argc;
} else if (strcmp(*argv, "-l") == 0 ||
strcmp(*argv, "--listen") == 0) {
serv = true;
+ } else if (strcmp(*argv, "-D") == 0 ||
+ strcmp(*argv, "--timeofday") == 0) {
+ client.timestamp = true;
+ } else if (strcmp(*argv, "-Q") == 0 ||
+ strcmp(*argv, "--quiet") == 0) {
+ client.quiet = true;
+ server.quiet = true;
} else {
- usage();
- exit(EXIT_SUCCESS);
+ goto fail;
}
argc--;
argv++;
}
+ if (duration > 0) {
+ if (client.interval == 0)
+ client.count = duration * 10;
+ else
+ client.count = duration / client.interval;
+ }
+
+ if (qos != NULL) {
+ if (strcmp(qos, "best") == 0)
+ client.qs = qos_best_effort;
+ else if (strcmp(qos, "raw") == 0)
+ client.qs = qos_raw;
+ else if (strcmp(qos, "video") == 0)
+ client.qs = qos_video;
+ else if (strcmp(qos, "voice") == 0)
+ client.qs = qos_voice;
+ else if (strcmp(qos, "data") == 0)
+ client.qs = qos_data;
+ else if (strcmp(qos, "raw_crypt") == 0)
+ client.qs = qos_raw_crypt;
+ else
+ printf("Unknown QoS cube, defaulting to raw.\n");
+ }
+
if (serv) {
ret = server_main();
} else {
if (client.s_apn == NULL) {
printf("No server specified.\n");
usage();
- exit(EXIT_SUCCESS);
+ exit(EXIT_FAILURE);
}
if (client.interval > 10000) {
printf("Ping interval truncated to 10s.\n");
@@ -179,7 +267,6 @@ int main(int argc, char ** argv)
OPING_BUF_SIZE);
client.size = OPING_BUF_SIZE;
}
-
if (client.size < 64) {
printf("Packet size set to 64 bytes.\n");
client.size = 64;
@@ -192,4 +279,8 @@ int main(int argc, char ** argv)
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
+
+ fail:
+ usage();
+ exit(EXIT_FAILURE);
}
diff --git a/src/tools/oping/oping_client.c b/src/tools/oping/oping_client.c
index 6f874dd9..7b03c83d 100644
--- a/src/tools/oping/oping_client.c
+++ b/src/tools/oping/oping_client.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2018
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -65,10 +65,13 @@ void * reader(void * o)
int msg_len = 0;
double ms = 0;
double d = 0;
+ uint32_t exp_id = 0;
fccntl(fd, FLOWSRCVTIMEO, &timeout);
while (!stop && client.rcvd != client.count) {
+ uint32_t id;
+
msg_len = flow_read(fd, buf, OPING_BUF_SIZE);
if (msg_len == -ETIMEDOUT) {
printf("Server timed out.\n");
@@ -84,7 +87,8 @@ void * reader(void * o)
continue;
}
- if ((uint32_t) ntohl(msg->id) >= client.count) {
+ id = (uint32_t) ntohl(msg->id);
+ if (id >= client.count) {
printf("Invalid id.\n");
continue;
}
@@ -98,11 +102,25 @@ void * reader(void * o)
ms = ts_diff_us(&sent, &now) / 1000.0;
- printf("%d bytes from %s: seq=%d time=%.3f ms\n",
- msg_len,
- client.s_apn,
- ntohl(msg->id),
- ms);
+ if (id < exp_id)
+ ++client.ooo;
+
+ if (!client.quiet) {
+ if (client.timestamp) {
+ struct timespec rtc;
+ clock_gettime(CLOCK_REALTIME, &rtc);
+ printf("[%zd.%06zu] ",
+ (ssize_t) rtc.tv_sec,
+ (size_t) rtc.tv_nsec / 1000);
+ }
+
+ printf("%d bytes from %s: seq=%d time=%.3f ms%s\n",
+ msg_len,
+ client.s_apn,
+ ntohl(msg->id),
+ ms,
+ id < exp_id ? " [out-of-order]" : "");
+ }
if (ms < client.rtt_min)
client.rtt_min = ms;
@@ -112,6 +130,9 @@ void * reader(void * o)
d = (ms - client.rtt_avg);
client.rtt_avg += d / client.rcvd;
client.rtt_m2 += d * (ms - client.rtt_avg);
+
+ if (id >= exp_id)
+ exp_id = id + 1;
}
return (void *) 0;
@@ -129,17 +150,20 @@ void * writer(void * o)
if (buf == NULL)
return (void *) -ENOMEM;
- if (fdp == NULL)
+ if (fdp == NULL) {
+ free(buf);
return (void *) -EINVAL;
+ }
memset(buf, 0, client.size);
msg = (struct oping_msg *) buf;
- printf("Pinging %s with %d bytes of data:\n\n",
- client.s_apn, client.size);
+ if (!client.quiet)
+ printf("Pinging %s with %d bytes of data (%u packets):\n\n",
+ client.s_apn, client.size, client.count);
- pthread_cleanup_push((void (*) (void *)) free, buf);
+ pthread_cleanup_push(free, buf);
while (!stop && client.sent < client.count) {
nanosleep(&wait, NULL);
@@ -151,11 +175,9 @@ void * writer(void * o)
msg->tv_sec = now.tv_sec;
msg->tv_nsec = now.tv_nsec;
- if (flow_write(*fdp, buf, client.size) == -1) {
- printf("Failed to send SDU.\n");
- flow_dealloc(*fdp);
- free(buf);
- return (void *) -1;
+ if (flow_write(*fdp, buf, client.size) < 0) {
+ printf("Failed to send packet.\n");
+ stop = true;
}
}
@@ -208,13 +230,15 @@ static int client_main(void)
return -1;
}
- fd = flow_alloc(client.s_apn, NULL, NULL);
+ fd = flow_alloc(client.s_apn, &client.qs, NULL);
if (fd < 0) {
- printf("Failed to allocate flow.\n");
+ printf("Failed to allocate flow: %d.\n", fd);
client_fini();
return -1;
}
+ fccntl(fd, FLOWSFLAGS, FLOWFRDWR | FLOWFRNOPART);
+
clock_gettime(CLOCK_REALTIME, &tic);
pthread_create(&client.reader_pt, NULL, reader, &fd);
@@ -227,8 +251,9 @@ static int client_main(void)
printf("\n");
printf("--- %s ping statistics ---\n", client.s_apn);
- printf("%d SDUs transmitted, ", client.sent);
+ printf("%d packets transmitted, ", client.sent);
printf("%d received, ", client.rcvd);
+ printf("%zd out-of-order, ", client.ooo);
printf("%.0lf%% packet loss, ", client.sent == 0 ? 0 :
ceil(100 - (100 * (client.rcvd / (float) client.sent))));
printf("time: %.3f ms\n", ts_diff_us(&tic, &toc) / 1000.0);
diff --git a/src/tools/oping/oping_server.c b/src/tools/oping/oping_server.c
index 391da197..6f76869c 100644
--- a/src/tools/oping/oping_server.c
+++ b/src/tools/oping/oping_server.c
@@ -1,10 +1,10 @@
/*
- * Ouroboros - Copyright (C) 2016 - 2018
+ * Ouroboros - Copyright (C) 2016 - 2024
*
* Ouroboros ping application
*
- * Dimitri Staessens <dimitri.staessens@ugent.be>
- * Sander Vrijders <sander.vrijders@ugent.be>
+ * Dimitri Staessens <dimitri@ouroboros.rocks>
+ * Sander Vrijders <sander@ouroboros.rocks>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -61,16 +61,21 @@ void * cleaner_thread(void * o)
while (true) {
clock_gettime(CLOCK_REALTIME, &now);
- pthread_mutex_lock(&server.lock);
+
for (i = 0; i < OPING_MAX_FLOWS; ++i)
- if (fset_has(server.flows, i) &&
- ts_diff_ms(&server.times[i], &now) > deadline_ms) {
- printf("Flow %d timed out.\n", i);
- fset_del(server.flows, i);
- flow_dealloc(i);
+ if (fset_has(server.flows, i)) {
+ time_t diff;
+
+ pthread_mutex_lock(&server.lock);
+ diff = ts_diff_ms(&server.times[i], &now);
+ pthread_mutex_unlock(&server.lock);
+
+ if (diff > deadline_ms) {
+ printf("Flow %d timed out.\n", i);
+ fset_del(server.flows, i);
+ flow_dealloc(i);
+ }
}
-
- pthread_mutex_unlock(&server.lock);
sleep(1);
}
}
@@ -96,10 +101,13 @@ void * server_thread(void *o)
continue;
if (ntohl(msg->type) != ECHO_REQUEST) {
- printf("Invalid message on fd %d.", fd);
+ printf("Invalid message on fd %d.\n", fd);
continue;
}
+ if (!server.quiet)
+ printf("Received %d bytes on fd %d.\n", msg_len, fd);
+
clock_gettime(CLOCK_REALTIME, &now);
pthread_mutex_lock(&server.lock);
@@ -118,9 +126,9 @@ void * server_thread(void *o)
void * accept_thread(void * o)
{
- int fd;
+ int fd;
struct timespec now;
- qosspec_t qs;
+ qosspec_t qs;
(void) o;
@@ -137,12 +145,14 @@ void * accept_thread(void * o)
clock_gettime(CLOCK_REALTIME, &now);
- pthread_mutex_lock(&server.lock);
fset_add(server.flows, fd);
+
+ pthread_mutex_lock(&server.lock);
server.times[fd] = now;
pthread_mutex_unlock(&server.lock);
- fccntl(fd, FLOWSFLAGS, FLOWFRNOBLOCK | FLOWFRDWR);
+ fccntl(fd, FLOWSFLAGS,
+ FLOWFRNOBLOCK | FLOWFRDWR | FLOWFRNOPART);
}
return (void *) 0;