From 3c09e1ee43e323bdfdc8b935aa3e5e208e90e2f5 Mon Sep 17 00:00:00 2001 From: Laurent MAZET Date: Fri, 26 Sep 2025 19:30:01 +0200 Subject: [PATCH] work to redo --- todo/instantiation_thread.c | 75 ++ todo/mq_receiver.c | 84 +++ todo/mq_sender.c | 49 ++ todo/prio-inversion.c | 174 +++++ todo/sem_start_finish.c | 123 ++++ todo/udptest/Makefile | 14 + todo/udptest/README | 28 + todo/udptest/clock.c | 129 ++++ todo/udptest/cmdline.c | 1288 ++++++++++++++++++++++++++++++++++ todo/udptest/cmdline.h | 207 ++++++ todo/udptest/com.c | 109 +++ todo/udptest/common.h | 56 ++ todo/udptest/ftrace.c | 64 ++ todo/udptest/launch.c | 15 + todo/udptest/timer.c | 49 ++ todo/udptest/udptest.c | 188 +++++ todo/udptest/udptestserver.c | 87 +++ 17 files changed, 2739 insertions(+) create mode 100644 todo/instantiation_thread.c create mode 100644 todo/mq_receiver.c create mode 100644 todo/mq_sender.c create mode 100644 todo/prio-inversion.c create mode 100644 todo/sem_start_finish.c create mode 100644 todo/udptest/Makefile create mode 100644 todo/udptest/README create mode 100644 todo/udptest/clock.c create mode 100644 todo/udptest/cmdline.c create mode 100644 todo/udptest/cmdline.h create mode 100644 todo/udptest/com.c create mode 100644 todo/udptest/common.h create mode 100644 todo/udptest/ftrace.c create mode 100644 todo/udptest/launch.c create mode 100644 todo/udptest/timer.c create mode 100644 todo/udptest/udptest.c create mode 100644 todo/udptest/udptestserver.c diff --git a/todo/instantiation_thread.c b/todo/instantiation_thread.c new file mode 100644 index 0000000..e72fe22 --- /dev/null +++ b/todo/instantiation_thread.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include + +#define NUM_MEASUREMENTS 10000 + +double deltas_us[NUM_MEASUREMENTS]; + +void* dummy_thread(void *arg) { + (void)arg; + return NULL; +} + +double timespec_diff_us(struct timespec *start, struct timespec *end) { + return (end->tv_sec - start->tv_sec) * 1e6 + + (end->tv_nsec - start->tv_nsec) / 1e3; +} + +int main(void) { + pthread_t posix_t; + pthread_attr_t attr; + struct sched_param param; + + pthread_attr_init(&attr); + pthread_attr_setschedpolicy(&attr, SCHED_FIFO); + param.sched_priority = sched_get_priority_max(SCHED_FIFO); + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + + struct timespec t_start, t_end; + int count = 0; + + while (count < NUM_MEASUREMENTS) { + clock_gettime(CLOCK_MONOTONIC, &t_start); + + pthread_create(&posix_t, &attr, dummy_thread, NULL); + pthread_join(posix_t, NULL); + + clock_gettime(CLOCK_MONOTONIC, &t_end); + + deltas_us[count] = timespec_diff_us(&t_start, &t_end); + count++; + } + + pthread_attr_destroy(&attr); + + // Calcul des statistiques + double sum = 0.0, min = deltas_us[0], max = deltas_us[0]; + for (int i = 0; i < NUM_MEASUREMENTS; i++) { + double d = deltas_us[i]; + sum += d; + if (d < min) min = d; + if (d > max) max = d; + } + + double avg = sum / NUM_MEASUREMENTS; + + double stddev_sum = 0.0; + for (int i = 0; i < NUM_MEASUREMENTS; i++) { + stddev_sum += (deltas_us[i] - avg) * (deltas_us[i] - avg); + } + double stddev = sqrt(stddev_sum / NUM_MEASUREMENTS); + + printf("\n==== Timing Statistics (%d measurements) ====\n", NUM_MEASUREMENTS); + printf("Moyenne : %.3f µs\n", avg); + printf("Minimum : %.3f µs\n", min); + printf("Maximum : %.3f µs\n", max); + printf("Ecart-type : %.3f µs\n", stddev); + printf("============================================\n"); + + return 0; +} diff --git a/todo/mq_receiver.c b/todo/mq_receiver.c new file mode 100644 index 0000000..686ca1b --- /dev/null +++ b/todo/mq_receiver.c @@ -0,0 +1,84 @@ +// +// Receive a string from POSIX mq +// + +#include +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include +#include +#include +#include + +mqd_t mq; +long ts1, ts2; + +// SysTimestamp() emulation +int64_t timespec_as_microseconds(struct timespec ts) +{ + long rv = ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + return rv; +} + +long timespec_as_nanoseconds(struct timespec ts) +{ + long rv = ts.tv_sec * 1000000000 + ts.tv_nsec ; + return rv; +} + +int64_t sysTimestamp() +{ + struct timespec ts; + + clock_gettime (CLOCK_REALTIME, &ts); + + return timespec_as_microseconds(ts); +} + +void got_sigint (int sig) +{ + mq_close(mq); + printf ("Got SIGINT, exiting!\n"); + exit (0); +} + +int main() +{ + int m; + char buff[8096]; + struct mq_attr attr; + long ts = 0, ts_old = 0; + + signal (SIGINT, got_sigint); + + attr.mq_flags = 0; + attr.mq_maxmsg = 10; + attr.mq_msgsize = 8096; + attr.mq_curmsgs = 0; + + mq = mq_open("/test_queue", O_CREAT | O_RDWR, 0644, &attr); + if (mq == -1) { + perror("mq_open"); + return -1; + } + + printf ("Waiting for data...\n"); + + while (1) { + ts_old = ts; + ts = sysTimestamp(); + + m = mq_receive(mq, buff, sizeof(buff), NULL); + if (m == -1) { + perror("mq_receive\n"); + return -1; + } + + printf("%s (%d bytes) %ld\n", buff, m, ts-ts_old); + } + + // mq_close(mq); + + return 0; +} diff --git a/todo/mq_sender.c b/todo/mq_sender.c new file mode 100644 index 0000000..7699c51 --- /dev/null +++ b/todo/mq_sender.c @@ -0,0 +1,49 @@ +// +// Send strings with POSIX mq +// + +#include +#include /* For O_* constants */ +#include /* For mode constants */ +#include +#include +#include +#include +#include + +mqd_t mq; + +void got_sigint (int sig) +{ + mq_close(mq); + printf ("Got SIGINT, exiting!\n"); + exit (0); +} + +int main() +{ + int m; + long i = 0; + char buf[30]; + + signal(SIGINT, got_sigint); + + mq = mq_open("/test_queue", O_WRONLY|O_CREAT,0,0); + if (mq == -1) { + perror("mq_open"); + return -1; + } + + while (1) { + sprintf(buf, "hello world %ld", i++); + m = mq_send(mq, buf, strlen(buf), 0); + if (m == -1) { + perror("mq_send"); + return -1; + } + + // usleep (100000); + } + + return 0; +} diff --git a/todo/prio-inversion.c b/todo/prio-inversion.c new file mode 100644 index 0000000..4628581 --- /dev/null +++ b/todo/prio-inversion.c @@ -0,0 +1,174 @@ +/* + * Priority inversion and inheritance (POSIX) + * + * Based on https://www.blaess.fr/christophe/2011/07/29/eviter-les-inversions-de-priorite-causees-par-des-mutex/ + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define T1_PRIO 5 +#define T2_PRIO 15 +#define T3_PRIO 45 + +static void * T1 (void * unused); +static void * T2 (void * unused); +static void * T3 (void * unused); + +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static int use_inherit = 0; + +void usage (char *s) +{ + fprintf (stderr, "Usage: %s [-i]\n", s); + exit (1); +} + +int main(int ac, char **av) +{ +#ifndef __vxworks + cpu_set_t cpu_set; +#endif + pthread_t t1, t2, t3; + pthread_mutexattr_t attr; + char *cp, *progname = (char*)basename(av[0]); + + while (--ac) { + if ((cp = *++av) == NULL) + break; + if (*cp == '-' && *++cp) { + switch(*cp) { + case 'i' : + use_inherit = 1; break; + + default: + usage(progname); + break; + } + } + else + break; + } + + // Priority inheritance + if (use_inherit) { + printf ("Activating PTHREAD_PRIO_INHERIT\n"); + pthread_mutexattr_init(& attr); + pthread_mutexattr_setprotocol(& attr, PTHREAD_PRIO_INHERIT); + pthread_mutex_init(& mutex, & attr); + } + + // Run the program on 1 CPU +#ifndef __vxworks + CPU_ZERO(& cpu_set); + CPU_SET(0, & cpu_set); // CPU 0 + if (sched_setaffinity(0, sizeof(cpu_set), & cpu_set) != 0) { + perror("sched_setaffinity"); + exit(EXIT_FAILURE); + } +#endif + + // Create the tasks + if ((pthread_create(& t1, NULL, T1, NULL) != 0) + || (pthread_create(& t2, NULL, T2, NULL) != 0) + || (pthread_create(& t3, NULL, T3, NULL) != 0)) { + fprintf(stderr, "Can't create the tasks !"); + exit(EXIT_FAILURE); + } + + pthread_exit(NULL); +} + +#define BOUCLE_1 20000 +#define BOUCLE_2 100000 + +static void * T1 (void * unused) +{ + int i, j; + struct sched_param param; + + printf("%s: starting with priority %d\n", __FUNCTION__, T1_PRIO); + + param.sched_priority = T1_PRIO; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) { + perror("pthread_setschedparam"); + exit(EXIT_FAILURE); + } + + printf("%s: asking for the mutex\n", __FUNCTION__); + pthread_mutex_lock(& mutex); + + printf("%s: got the mutex, working\n", __FUNCTION__); + for (i = 0; i < BOUCLE_1; i ++) + for (j = 0; j < BOUCLE_2; j ++) + ; + printf("%s: stop working\n", __FUNCTION__); + + printf("%s: releasing the mutex\n", __FUNCTION__); + pthread_mutex_unlock(& mutex); + + return NULL; +} + +static void * T2 (void * unused) +{ + int i, j; + struct sched_param param; + + printf("%s: starting with priority %d (sleeping 2s)\n", __FUNCTION__, T2_PRIO); + + param.sched_priority = T2_PRIO; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) { + perror("pthread_setschedparam"); + exit(EXIT_FAILURE); + } + + sleep(2); + + printf("%s: working\n", __FUNCTION__); + for (i = 0; i < BOUCLE_1; i ++) + for (j = 0; j < BOUCLE_2; j ++) + ; + + printf("%s: stop working\n", __FUNCTION__); + + return NULL; +} + + + +static void * T3 (void * unused) +{ + int i, j; + struct sched_param param; + + printf("%s: starting with priority %d (sleeping 1s)\n", __FUNCTION__, T3_PRIO); + + param.sched_priority = T3_PRIO; + if (pthread_setschedparam(pthread_self(), SCHED_FIFO, & param) != 0) { + perror("pthread_setschedparam"); + exit(EXIT_FAILURE); + } + + sleep(1); + + printf("%s: asking for the mutex\n", __FUNCTION__); + pthread_mutex_lock(& mutex); + + printf("%s: got the mutex, working\n", __FUNCTION__); + for (i = 0; i < BOUCLE_1; i ++) + for (j = 0; j < BOUCLE_2; j ++) + ; + printf("%s: stop working\n", __FUNCTION__); + + printf("%s: releasing the mutex\n", __FUNCTION__); + pthread_mutex_unlock(&mutex); + + return NULL; +} + diff --git a/todo/sem_start_finish.c b/todo/sem_start_finish.c new file mode 100644 index 0000000..d422bc1 --- /dev/null +++ b/todo/sem_start_finish.c @@ -0,0 +1,123 @@ +// +// Pthread synchronization with POSIX semaphore +// + + +#include +#include +#include +#include +#include +#include +#include + +#define NT 2 + +static long *measure_tab; + +pthread_t tid[NT]; +int counter, i_loop; +sem_t sem; +long ts1, ts2; + +// SysTimestamp() emulation +int64_t timespec_as_microseconds(struct timespec ts) +{ + long rv = ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + return rv; +} + +long timespec_as_nanoseconds(struct timespec ts) +{ + long rv = ts.tv_sec * 1000000000 + ts.tv_nsec ; + return rv; +} + +int64_t sysTimestamp() +{ + struct timespec ts; + + clock_gettime (CLOCK_REALTIME, &ts); + + return timespec_as_microseconds(ts); +} + +void* trythis(void* arg) +{ + sem_wait(&sem); + + counter += 1; + + // thread 1 took the lock -> timestamp 1 + if (counter % 2 != 0) { + ts1 = sysTimestamp(); + } + + // thread 2 took the lock -> timestamp 2 + else { + ts2 = sysTimestamp(); + // printf ("%ld\n", ts2-ts1); + measure_tab[i_loop++] = ts2 - ts1; + } + + sem_post(&sem); + + return NULL; +} + +void usage (char *s) +{ + fprintf (stderr, "Usage: %s [-n ]\n", s); + exit (1); +} + +int main(int ac, char **av) +{ + register int i, nloop = 10; + char *cp, *progname = (char*)basename(av[0]); + + while (--ac) { + if ((cp = *++av) == NULL) + break; + if (*cp == '-' && *++cp) { + switch(*cp) { + case 'n' : + nloop = atoi(*++av); + break; + + default: + usage(progname); + break; + } + } + else + break; + } + + // Allocate the tab + measure_tab = (long *)calloc (nloop, sizeof(long)); + if (measure_tab == NULL) { + perror ("calloc"); + exit (1); + } + + sem_init (&sem, 0, 1); + + for (i = 0 ; i < nloop ; i++) { + for (int i = 0; i < NT; i++) + pthread_create(&tid[i], NULL, trythis, NULL); + + for (int i = 0; i < NT; i++) + pthread_join(tid[i], NULL); + } + + sem_destroy(&sem); + + // Display the result + for (i = 0 ; i < i_loop ; i++) + printf ("%ld\n", measure_tab[i]); + + free (measure_tab); + + return 0; +} diff --git a/todo/udptest/Makefile b/todo/udptest/Makefile new file mode 100644 index 0000000..8075711 --- /dev/null +++ b/todo/udptest/Makefile @@ -0,0 +1,14 @@ +CC?=gcc +COMMON=com.c timer.c clock.c ftrace.c cmdline.c + +all: udptest udptestserver + +udptest: udptest.c common.h $(COMMON) + $(CC) -o udptest udptest.c $(COMMON) + +udptestserver: udptestserver.c common.h $(COMMON) + $(CC) -o udptestserver udptestserver.c $(COMMON) + +clean: + rm -rf udptest udptestserver *~ *.o + diff --git a/todo/udptest/README b/todo/udptest/README new file mode 100644 index 0000000..23dcdc6 --- /dev/null +++ b/todo/udptest/README @@ -0,0 +1,28 @@ +# UDP test program +# ----------------------------------------------------------------------------- +# Developped to test UDP latencies in RT environment and debug sporadic high +# latencies using ftrace. +# +# /!\ Note that enabling ftrace increase measured latencies depending on how +# many tracepoint are logged. So for low impact, make sure to configure +# some function filtering before. +# +# This project is composed of two programs : +# * One test program performing UDP packet sending and receiving +# * One remote program which only respond as fast as possible the same +# packet (like a echo server) +# +# The test program is able to : +# * Compute statistics on packet round trip time (min,max,avg) +# * Drop first iteration to wait for a right ARP table and routing +# * Network configuration is configurable +# * Message size and number are configurable +# * Each iteration can be periodic with a configurable period (using timerfd) +# or as fast as possible (period=0) +# * If a configurable maximum is detected, ftrace can be used to capture this +# latency context (trace is reset at each iteration). Requires root rights +# * Remote server can wait some time before sending back the response (using +# clock_nanosleep) +# * Remote server count input packet and wait to receive all packet before +# sending them back so packet drop will be detected. +# diff --git a/todo/udptest/clock.c b/todo/udptest/clock.c new file mode 100644 index 0000000..15a9974 --- /dev/null +++ b/todo/udptest/clock.c @@ -0,0 +1,129 @@ +#include +#include +#include "common.h" + + +#ifdef __vxworks +#include +#include +#else +#include +#endif + +#ifdef __vxworks +void clock_current(uint64_t* now) +{ + *now = sysTimestamp(); +} +#else +void clock_current(clock_s* now) +{ + clock_gettime(CLOCK_MONOTONIC_RAW, now); +} +#endif + +#ifdef __vxworks +int clock_diff_us(uint64_t t1, uint64_t t2) +{ + uint64_t diff = t2 - t1; + uint64_t freq = sysTimestampFreq(); + if (freq == 0) return -1; + return (int)((diff * 1000000ULL) / freq); +} +#else +int clock_diff_us(clock_s c1, clock_s c2) +{ + int diff_us = (c2.tv_sec - c1.tv_sec) * 1000000; + diff_us += (c2.tv_nsec - c1.tv_nsec) / 1000; + return diff_us; +} +#endif + +void clock_latency_init(struct latency_s* latency) +{ + latency->iter_number = 0; + latency->cumul_us = 0; + latency->max_us = 0; + latency->min_us = -1; +} + +#ifdef __vxworks +void clock_latency_update(uint64_t t1, uint64_t t2, struct latency_s* latency, const char* name, int verbose) +{ + int diff = clock_diff_us(t1, t2); + + latency->iter_number++; + latency->cumul_us += diff; + + if (diff > latency->max_us) { + latency->max_us = diff; + if (verbose) { + printf("New max latency for %s: %d us at tick=%llu\n", name, diff, (unsigned long long)t2); + } + } + if (diff < latency->min_us || latency->min_us == -1) { + latency->min_us = diff; + } +} +#else +void clock_latency_update(clock_s t1, clock_s t2, struct latency_s* latency, const char* name, int verbose) +{ + int diff = clock_diff_us(t1, t2); + + latency->iter_number++; + latency->cumul_us += diff; + + if (diff > latency->max_us) { + latency->max_us = diff; + if (verbose) { + printf("New max latency for %s: %d us at %ld.%09ld\n", name, diff, t2.tv_sec, t2.tv_nsec); + } + } + if (diff < latency->min_us || latency->min_us == -1) { + latency->min_us = diff; + } +} +#endif + +void clock_latency_reset_avg(struct latency_s* latency) +{ + latency->iter_number = 0; + latency->cumul_us = 0; +} + +#ifdef __vxworks +void clock_latency_print(struct latency_s* latency, const char* name) +{ + uint64_t now; + double avg; + + clock_current(&now); + + printf("[%s] tick=%llu : min=%d us, max=%d us, ", + name, (unsigned long long)now, latency->min_us, latency->max_us); + + if (latency->iter_number > 0) { + avg = (double)latency->cumul_us / latency->iter_number; + printf("avg: %.2f us\n", avg); + } else { + printf("[no new values]\n"); + } +} +#else +void clock_latency_print(struct latency_s* latency, const char* name) +{ + clock_s now; + double avg; + + clock_current(&now); + + if (latency->iter_number > 0) { + avg = (double)latency->cumul_us / latency->iter_number; + printf("[%s] %ld.%09ld : min=%d us, max=%d us, avg=%.2f us\n", + name, now.tv_sec, now.tv_nsec, latency->min_us, latency->max_us, avg); + } else { + printf("[%s] %ld.%09ld : min=%d us, max=%d us, [no new values]\n", + name, now.tv_sec, now.tv_nsec, latency->min_us, latency->max_us); + } +} +#endif diff --git a/todo/udptest/cmdline.c b/todo/udptest/cmdline.c new file mode 100644 index 0000000..a6de143 --- /dev/null +++ b/todo/udptest/cmdline.c @@ -0,0 +1,1288 @@ +/* + File autogenerated by gengetopt version 2.22.6 + generated with the following command: + gengetopt --input=udptest.cmdline --include-getopt + + The developers of gengetopt consider the fixed text that goes in all + gengetopt output files to be in the public domain: + we make no copyright claims on it. +*/ + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifndef FIX_UNUSED +#define FIX_UNUSED(X) (void) (X) /* avoid warnings for unused params */ +#endif + + +#include "cmdline.h" + +const char *gengetopt_args_info_purpose = "Compute latencies on UDP packets round trip."; + +const char *gengetopt_args_info_usage = "Usage: udptest [OPTIONS]..."; + +const char *gengetopt_args_info_versiontext = ""; + +const char *gengetopt_args_info_description = ""; + +const char *gengetopt_args_info_help[] = { + " -h, --help Print help and exit", + " -V, --version Print version and exit", + " -r, --remote-ip=STRING Remote IP Address (default=`127.0.0.1')", + " -p, --port=INT UDP Port Number (default=`15001')", + " -s, --packet-size=INT Packet size in byte (default=`10')", + " -n, --packet-number=INT Number of packet for each iteration (default=`100')", + " -i, --interval=INT Period time in microseconds. If 0, iteration are\n running as fast as possible (default=`0')", + " -m, --max-rtt=INT Maximum time of one period. If 0, the interval value\n is used and if interval is 0, this check is\n disabled. (default=`0')", + " -w, --wait=INT For server side only. This value define how much the\n server wait before sending back packets.\n (default=`0')", + " -v, --verbose Increase program verbosity (default=off)", + " -t, --ftrace Enable ftrace and reset trace on each iteration. Use\n with max-rtt option. Requires root rights.\n (default=off)", + 0 +}; + +typedef enum {ARG_NO + , ARG_FLAG + , ARG_STRING + , ARG_INT +} cmdline_parser_arg_type; + +static +void clear_given (struct gengetopt_args_info *args_info); +static +void clear_args (struct gengetopt_args_info *args_info); + +static int +cmdline_parser_internal (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error); + + +static char * +gengetopt_strdup (const char *s); + +static +void clear_given (struct gengetopt_args_info *args_info) +{ + args_info->help_given = 0 ; + args_info->version_given = 0 ; + args_info->remote_ip_given = 0 ; + args_info->port_given = 0 ; + args_info->packet_size_given = 0 ; + args_info->packet_number_given = 0 ; + args_info->interval_given = 0 ; + args_info->max_rtt_given = 0 ; + args_info->wait_given = 0 ; + args_info->verbose_given = 0 ; + args_info->ftrace_given = 0 ; +} + +static +void clear_args (struct gengetopt_args_info *args_info) +{ + FIX_UNUSED (args_info); + args_info->remote_ip_arg = gengetopt_strdup ("127.0.0.1"); + args_info->remote_ip_orig = NULL; + args_info->port_arg = 15001; + args_info->port_orig = NULL; + args_info->packet_size_arg = 10; + args_info->packet_size_orig = NULL; + args_info->packet_number_arg = 100; + args_info->packet_number_orig = NULL; + args_info->interval_arg = 0; + args_info->interval_orig = NULL; + args_info->max_rtt_arg = 0; + args_info->max_rtt_orig = NULL; + args_info->wait_arg = 0; + args_info->wait_orig = NULL; + args_info->verbose_flag = 0; + args_info->ftrace_flag = 0; + +} + +static +void init_args_info(struct gengetopt_args_info *args_info) +{ + + + args_info->help_help = gengetopt_args_info_help[0] ; + args_info->version_help = gengetopt_args_info_help[1] ; + args_info->remote_ip_help = gengetopt_args_info_help[2] ; + args_info->port_help = gengetopt_args_info_help[3] ; + args_info->packet_size_help = gengetopt_args_info_help[4] ; + args_info->packet_number_help = gengetopt_args_info_help[5] ; + args_info->interval_help = gengetopt_args_info_help[6] ; + args_info->max_rtt_help = gengetopt_args_info_help[7] ; + args_info->wait_help = gengetopt_args_info_help[8] ; + args_info->verbose_help = gengetopt_args_info_help[9] ; + args_info->ftrace_help = gengetopt_args_info_help[10] ; + +} + +void +cmdline_parser_print_version (void) +{ + printf ("%s %s\n", + (strlen(CMDLINE_PARSER_PACKAGE_NAME) ? CMDLINE_PARSER_PACKAGE_NAME : CMDLINE_PARSER_PACKAGE), + CMDLINE_PARSER_VERSION); + + if (strlen(gengetopt_args_info_versiontext) > 0) + printf("\n%s\n", gengetopt_args_info_versiontext); +} + +static void print_help_common(void) { + cmdline_parser_print_version (); + + if (strlen(gengetopt_args_info_purpose) > 0) + printf("\n%s\n", gengetopt_args_info_purpose); + + if (strlen(gengetopt_args_info_usage) > 0) + printf("\n%s\n", gengetopt_args_info_usage); + + printf("\n"); + + if (strlen(gengetopt_args_info_description) > 0) + printf("%s\n\n", gengetopt_args_info_description); +} + +void +cmdline_parser_print_help (void) +{ + int i = 0; + print_help_common(); + while (gengetopt_args_info_help[i]) + printf("%s\n", gengetopt_args_info_help[i++]); +} + +void +cmdline_parser_init (struct gengetopt_args_info *args_info) +{ + clear_given (args_info); + clear_args (args_info); + init_args_info (args_info); +} + +void +cmdline_parser_params_init(struct cmdline_parser_params *params) +{ + if (params) + { + params->override = 0; + params->initialize = 1; + params->check_required = 1; + params->check_ambiguity = 0; + params->print_errors = 1; + } +} + +struct cmdline_parser_params * +cmdline_parser_params_create(void) +{ + struct cmdline_parser_params *params = + (struct cmdline_parser_params *)malloc(sizeof(struct cmdline_parser_params)); + cmdline_parser_params_init(params); + return params; +} + +static void +free_string_field (char **s) +{ + if (*s) + { + free (*s); + *s = 0; + } +} + + +static void +cmdline_parser_release (struct gengetopt_args_info *args_info) +{ + + free_string_field (&(args_info->remote_ip_arg)); + free_string_field (&(args_info->remote_ip_orig)); + free_string_field (&(args_info->port_orig)); + free_string_field (&(args_info->packet_size_orig)); + free_string_field (&(args_info->packet_number_orig)); + free_string_field (&(args_info->interval_orig)); + free_string_field (&(args_info->max_rtt_orig)); + free_string_field (&(args_info->wait_orig)); + + + + clear_given (args_info); +} + + +static void +write_into_file(FILE *outfile, const char *opt, const char *arg, const char *values[]) +{ + FIX_UNUSED (values); + if (arg) { + fprintf(outfile, "%s=\"%s\"\n", opt, arg); + } else { + fprintf(outfile, "%s\n", opt); + } +} + + +int +cmdline_parser_dump(FILE *outfile, struct gengetopt_args_info *args_info) +{ + int i = 0; + + if (!outfile) + { + fprintf (stderr, "%s: cannot dump options to stream\n", CMDLINE_PARSER_PACKAGE); + return EXIT_FAILURE; + } + + if (args_info->help_given) + write_into_file(outfile, "help", 0, 0 ); + if (args_info->version_given) + write_into_file(outfile, "version", 0, 0 ); + if (args_info->remote_ip_given) + write_into_file(outfile, "remote-ip", args_info->remote_ip_orig, 0); + if (args_info->port_given) + write_into_file(outfile, "port", args_info->port_orig, 0); + if (args_info->packet_size_given) + write_into_file(outfile, "packet-size", args_info->packet_size_orig, 0); + if (args_info->packet_number_given) + write_into_file(outfile, "packet-number", args_info->packet_number_orig, 0); + if (args_info->interval_given) + write_into_file(outfile, "interval", args_info->interval_orig, 0); + if (args_info->max_rtt_given) + write_into_file(outfile, "max-rtt", args_info->max_rtt_orig, 0); + if (args_info->wait_given) + write_into_file(outfile, "wait", args_info->wait_orig, 0); + if (args_info->verbose_given) + write_into_file(outfile, "verbose", 0, 0 ); + if (args_info->ftrace_given) + write_into_file(outfile, "ftrace", 0, 0 ); + + + i = EXIT_SUCCESS; + return i; +} + +int +cmdline_parser_file_save(const char *filename, struct gengetopt_args_info *args_info) +{ + FILE *outfile; + int i = 0; + + outfile = fopen(filename, "w"); + + if (!outfile) + { + fprintf (stderr, "%s: cannot open file for writing: %s\n", CMDLINE_PARSER_PACKAGE, filename); + return EXIT_FAILURE; + } + + i = cmdline_parser_dump(outfile, args_info); + fclose (outfile); + + return i; +} + +void +cmdline_parser_free (struct gengetopt_args_info *args_info) +{ + cmdline_parser_release (args_info); +} + +/** @brief replacement of strdup, which is not standard */ +char * +gengetopt_strdup (const char *s) +{ + char *result = 0; + if (!s) + return result; + + result = (char*)malloc(strlen(s) + 1); + if (result == (char*)0) + return (char*)0; + strcpy(result, s); + return result; +} + +int +cmdline_parser (int argc, char **argv, struct gengetopt_args_info *args_info) +{ + return cmdline_parser2 (argc, argv, args_info, 0, 1, 1); +} + +int +cmdline_parser_ext (int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params) +{ + int result; + result = cmdline_parser_internal (argc, argv, args_info, params, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser2 (int argc, char **argv, struct gengetopt_args_info *args_info, int override, int initialize, int check_required) +{ + int result; + struct cmdline_parser_params params; + + params.override = override; + params.initialize = initialize; + params.check_required = check_required; + params.check_ambiguity = 0; + params.print_errors = 1; + + result = cmdline_parser_internal (argc, argv, args_info, ¶ms, 0); + + if (result == EXIT_FAILURE) + { + cmdline_parser_free (args_info); + exit (EXIT_FAILURE); + } + + return result; +} + +int +cmdline_parser_required (struct gengetopt_args_info *args_info, const char *prog_name) +{ + FIX_UNUSED (args_info); + FIX_UNUSED (prog_name); + return EXIT_SUCCESS; +} + +/* + * Extracted from the glibc source tree, version 2.3.6 + * + * Licensed under the GPL as per the whole glibc source tree. + * + * This file was modified so that getopt_long can be called + * many times without risking previous memory to be spoiled. + * + * Modified by Andre Noll and Lorenzo Bettini for use in + * GNU gengetopt generated files. + * + */ + +/* + * we must include anything we need since this file is not thought to be + * inserted in a file already using getopt.h + * + * Lorenzo + */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. +*/ +/* + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `custom_optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +/* Names for the values of the `has_arg' field of `struct option'. */ +#ifndef no_argument +#define no_argument 0 +#endif + +#ifndef required_argument +#define required_argument 1 +#endif + +#ifndef optional_argument +#define optional_argument 2 +#endif + +struct custom_getopt_data { + /* + * These have exactly the same meaning as the corresponding global variables, + * except that they are used for the reentrant versions of getopt. + */ + int custom_optind; + int custom_opterr; + int custom_optopt; + char *custom_optarg; + + /* True if the internal members have been initialized. */ + int initialized; + + /* + * The next char to be scanned in the option-element in which the last option + * character we returned was found. This allows us to pick up the scan where + * we left off. If this is zero, or a null string, it means resume the scan by + * advancing to the next ARGV-element. + */ + char *nextchar; + + /* + * Describe the part of ARGV that contains non-options that have been skipped. + * `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is + * the index after the last of them. + */ + int first_nonopt; + int last_nonopt; +}; + +/* + * the variables optarg, optind, opterr and optopt are renamed with + * the custom_ prefix so that they don't interfere with getopt ones. + * + * Moreover they're static so they are visible only from within the + * file where this very file will be included. + */ + +/* + * For communication from `custom_getopt' to the caller. When `custom_getopt' finds an + * option that takes an argument, the argument value is returned here. + */ +static char *custom_optarg; + +/* + * Index in ARGV of the next element to be scanned. This is used for + * communication to and from the caller and for communication between + * successive calls to `custom_getopt'. + * + * On entry to `custom_getopt', 1 means this is the first call; initialize. + * + * When `custom_getopt' returns -1, this is the index of the first of the non-option + * elements that the caller should itself scan. + * + * Otherwise, `custom_optind' communicates from one call to the next how much of ARGV + * has been scanned so far. + * + * 1003.2 says this must be 1 before any call. + */ +static int custom_optind = 1; + +/* + * Callers store zero here to inhibit the error message for unrecognized + * options. + */ +static int custom_opterr = 1; + +/* + * Set to an option character which was unrecognized. This must be initialized + * on some systems to avoid linking in the system's own getopt implementation. + */ +static int custom_optopt = '?'; + +/* + * Exchange two adjacent subsequences of ARGV. One subsequence is elements + * [first_nonopt,last_nonopt) which contains all the non-options that have been + * skipped so far. The other is elements [last_nonopt,custom_optind), which contains + * all the options processed since those non-options were skipped. + * `first_nonopt' and `last_nonopt' are relocated so that they describe the new + * indices of the non-options in ARGV after they are moved. + */ +static void exchange(char **argv, struct custom_getopt_data *d) +{ + int bottom = d->first_nonopt; + int middle = d->last_nonopt; + int top = d->custom_optind; + char *tem; + + /* + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. It leaves the + * longer segment in the right place overall, but it consists of two + * parts that need to be swapped next. + */ + while (top > middle && middle > bottom) { + if (top - middle > middle - bottom) { + /* Bottom segment is the short one. */ + int len = middle - bottom; + int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = + argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } else { + /* Top segment is the short one. */ + int len = top - middle; + int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + /* Update records for the slots the non-options now occupy. */ + d->first_nonopt += (d->custom_optind - d->last_nonopt); + d->last_nonopt = d->custom_optind; +} + +/* Initialize the internal data when the first call is made. */ +static void custom_getopt_initialize(struct custom_getopt_data *d) +{ + /* + * Start processing options with ARGV-element 1 (since ARGV-element 0 + * is the program name); the sequence of previously skipped non-option + * ARGV-elements is empty. + */ + d->first_nonopt = d->last_nonopt = d->custom_optind; + d->nextchar = NULL; + d->initialized = 1; +} + +#define NONOPTION_P (argv[d->custom_optind][0] != '-' || argv[d->custom_optind][1] == '\0') + +/* return: zero: continue, nonzero: return given value to user */ +static int shuffle_argv(int argc, char *const *argv,const struct option *longopts, + struct custom_getopt_data *d) +{ + /* + * Give FIRST_NONOPT & LAST_NONOPT rational values if CUSTOM_OPTIND has been + * moved back by the user (who may also have changed the arguments). + */ + if (d->last_nonopt > d->custom_optind) + d->last_nonopt = d->custom_optind; + if (d->first_nonopt > d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * If we have just processed some options following some + * non-options, exchange them so that the options come first. + */ + if (d->first_nonopt != d->last_nonopt && + d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->last_nonopt != d->custom_optind) + d->first_nonopt = d->custom_optind; + /* + * Skip any additional non-options and extend the range of + * non-options previously skipped. + */ + while (d->custom_optind < argc && NONOPTION_P) + d->custom_optind++; + d->last_nonopt = d->custom_optind; + /* + * The special ARGV-element `--' means premature end of options. Skip + * it like a null option, then exchange with previous non-options as if + * it were an option, then skip everything else like a non-option. + */ + if (d->custom_optind != argc && !strcmp(argv[d->custom_optind], "--")) { + d->custom_optind++; + if (d->first_nonopt != d->last_nonopt + && d->last_nonopt != d->custom_optind) + exchange((char **) argv, d); + else if (d->first_nonopt == d->last_nonopt) + d->first_nonopt = d->custom_optind; + d->last_nonopt = argc; + d->custom_optind = argc; + } + /* + * If we have done all the ARGV-elements, stop the scan and back over + * any non-options that we skipped and permuted. + */ + if (d->custom_optind == argc) { + /* + * Set the next-arg-index to point at the non-options that we + * previously skipped, so the caller will digest them. + */ + if (d->first_nonopt != d->last_nonopt) + d->custom_optind = d->first_nonopt; + return -1; + } + /* + * If we have come to a non-option and did not permute it, either stop + * the scan or describe it to the caller and pass it by. + */ + if (NONOPTION_P) { + d->custom_optarg = argv[d->custom_optind++]; + return 1; + } + /* + * We have found another option-ARGV-element. Skip the initial + * punctuation. + */ + d->nextchar = (argv[d->custom_optind] + 1 + (longopts != NULL && argv[d->custom_optind][1] == '-')); + return 0; +} + +/* + * Check whether the ARGV-element is a long option. + * + * If there's a long option "fubar" and the ARGV-element is "-fu", consider + * that an abbreviation of the long option, just like "--fu", and not "-f" with + * arg "u". + * + * This distinction seems to be the most useful approach. + * + */ +static int check_long_opt(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + int print_errors, struct custom_getopt_data *d) +{ + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = -1; + int option_index; + + for (nameend = d->nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match or abbreviated matches */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->nextchar, nameend - d->nextchar)) { + if ((unsigned int) (nameend - d->nextchar) + == (unsigned int) strlen(p->name)) { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } else if (pfound == NULL) { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } else if (pfound->has_arg != p->has_arg + || pfound->flag != p->flag + || pfound->val != p->val) + /* Second or later nonexact match found. */ + ambig = 1; + } + if (ambig && !exact) { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' is ambiguous\n", + argv[0], argv[d->custom_optind]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optind++; + d->custom_optopt = 0; + return '?'; + } + if (pfound) { + option_index = indfound; + d->custom_optind++; + if (*nameend) { + if (pfound->has_arg != no_argument) + d->custom_optarg = nameend + 1; + else { + if (print_errors) { + if (argv[d->custom_optind - 1][1] == '-') { + /* --option */ + fprintf(stderr, "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + } else { + /* +option or -option */ + fprintf(stderr, "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[d->custom_optind - 1][0], pfound->name); + } + + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return '?'; + } + } else if (pfound->has_arg == required_argument) { + if (d->custom_optind < argc) + d->custom_optarg = argv[d->custom_optind++]; + else { + if (print_errors) { + fprintf(stderr, + "%s: option `%s' requires an argument\n", + argv[0], + argv[d->custom_optind - 1]); + } + d->nextchar += strlen(d->nextchar); + d->custom_optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->nextchar += strlen(d->nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + /* + * Can't find it as a long option. If this is not getopt_long_only, or + * the option starts with '--' or is not a valid short option, then + * it's an error. Otherwise interpret it as a short option. + */ + if (print_errors) { + if (argv[d->custom_optind][1] == '-') { + /* --option */ + fprintf(stderr, + "%s: unrecognized option `--%s'\n", + argv[0], d->nextchar); + } else { + /* +option or -option */ + fprintf(stderr, + "%s: unrecognized option `%c%s'\n", + argv[0], argv[d->custom_optind][0], + d->nextchar); + } + } + d->nextchar = (char *) ""; + d->custom_optind++; + d->custom_optopt = 0; + return '?'; +} + +static int check_short_opt(int argc, char *const *argv, const char *optstring, + int print_errors, struct custom_getopt_data *d) +{ + char c = *d->nextchar++; + const char *temp = strchr(optstring, c); + + /* Increment `custom_optind' when we start to process its last character. */ + if (*d->nextchar == '\0') + ++d->custom_optind; + if (!temp || c == ':') { + if (print_errors) + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + + d->custom_optopt = c; + return '?'; + } + if (temp[1] == ':') { + if (temp[2] == ':') { + /* This is an option that accepts an argument optionally. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + d->custom_optind++; + } else + d->custom_optarg = NULL; + d->nextchar = NULL; + } else { + /* This is an option that requires an argument. */ + if (*d->nextchar != '\0') { + d->custom_optarg = d->nextchar; + /* + * If we end this ARGV-element by taking the + * rest as an arg, we must advance to the next + * element now. + */ + d->custom_optind++; + } else if (d->custom_optind == argc) { + if (print_errors) { + fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], c); + } + d->custom_optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } else + /* + * We already incremented `custom_optind' once; + * increment it again when taking next ARGV-elt + * as argument. + */ + d->custom_optarg = argv[d->custom_optind++]; + d->nextchar = NULL; + } + } + return c; +} + +/* + * Scan elements of ARGV for option characters given in OPTSTRING. + * + * If an element of ARGV starts with '-', and is not exactly "-" or "--", + * then it is an option element. The characters of this element + * (aside from the initial '-') are option characters. If `getopt' + * is called repeatedly, it returns successively each of the option characters + * from each of the option elements. + * + * If `getopt' finds another option character, it returns that character, + * updating `custom_optind' and `nextchar' so that the next call to `getopt' can + * resume the scan with the following option character or ARGV-element. + * + * If there are no more option characters, `getopt' returns -1. + * Then `custom_optind' is the index in ARGV of the first ARGV-element + * that is not an option. (The ARGV-elements have been permuted + * so that those that are not options now come last.) + * + * OPTSTRING is a string containing the legitimate option characters. + * If an option character is seen that is not listed in OPTSTRING, + * return '?' after printing an error message. If you set `custom_opterr' to + * zero, the error message is suppressed but we still return '?'. + * + * If a char in OPTSTRING is followed by a colon, that means it wants an arg, + * so the following text in the same ARGV-element, or the text of the following + * ARGV-element, is returned in `custom_optarg'. Two colons mean an option that + * wants an optional arg; if there is text in the current ARGV-element, + * it is returned in `custom_optarg', otherwise `custom_optarg' is set to zero. + * + * If OPTSTRING starts with `-' or `+', it requests different methods of + * handling the non-option ARGV-elements. + * See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + * + * Long-named options begin with `--' instead of `-'. + * Their names may be abbreviated as long as the abbreviation is unique + * or is an exact match for some defined option. If they have an + * argument, it follows the option name in the same ARGV-element, separated + * from the option name by a `=', or else the in next ARGV-element. + * When `getopt' finds a long-named option, it returns 0 if that option's + * `flag' field is nonzero, the value of the option's `val' field + * if the `flag' field is zero. + * + * The elements of ARGV aren't really const, because we permute them. + * But we pretend they're const in the prototype to be compatible + * with other systems. + * + * LONGOPTS is a vector of `struct option' terminated by an + * element containing a name which is zero. + * + * LONGIND returns the index in LONGOPT of the long-named option found. + * It is only valid when a long-named option has been found by the most + * recent call. + * + * Return the option character from OPTS just read. Return -1 when there are + * no more options. For unrecognized options, or options missing arguments, + * `custom_optopt' is set to the option letter, and '?' is returned. + * + * The OPTS string is a list of characters which are recognized option letters, + * optionally followed by colons, specifying that that letter takes an + * argument, to be placed in `custom_optarg'. + * + * If a letter in OPTS is followed by two colons, its argument is optional. + * This behavior is specific to the GNU `getopt'. + * + * The argument `--' causes premature termination of argument scanning, + * explicitly telling `getopt' that there are no more options. If OPTS begins + * with `--', then non-option arguments are treated as arguments to the option + * '\0'. This behavior is specific to the GNU `getopt'. + */ + +static int getopt_internal_r(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, + struct custom_getopt_data *d) +{ + int ret, print_errors = d->custom_opterr; + + if (optstring[0] == ':') + print_errors = 0; + if (argc < 1) + return -1; + d->custom_optarg = NULL; + + /* + * This is a big difference with GNU getopt, since optind == 0 + * means initialization while here 1 means first call. + */ + if (d->custom_optind == 0 || !d->initialized) { + if (d->custom_optind == 0) + d->custom_optind = 1; /* Don't scan ARGV[0], the program name. */ + custom_getopt_initialize(d); + } + if (d->nextchar == NULL || *d->nextchar == '\0') { + ret = shuffle_argv(argc, argv, longopts, d); + if (ret) + return ret; + } + if (longopts && (argv[d->custom_optind][1] == '-' )) + return check_long_opt(argc, argv, optstring, longopts, + longind, print_errors, d); + return check_short_opt(argc, argv, optstring, print_errors, d); +} + +static int custom_getopt_internal(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind) +{ + int result; + /* Keep a global copy of all internal members of d */ + static struct custom_getopt_data d; + + d.custom_optind = custom_optind; + d.custom_opterr = custom_opterr; + result = getopt_internal_r(argc, argv, optstring, longopts, + longind, &d); + custom_optind = d.custom_optind; + custom_optarg = d.custom_optarg; + custom_optopt = d.custom_optopt; + return result; +} + +static int custom_getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) +{ + return custom_getopt_internal(argc, argv, options, long_options, + opt_index); +} + + +static char *package_name = 0; + +/** + * @brief updates an option + * @param field the generic pointer to the field to update + * @param orig_field the pointer to the orig field + * @param field_given the pointer to the number of occurrence of this option + * @param prev_given the pointer to the number of occurrence already seen + * @param value the argument for this option (if null no arg was specified) + * @param possible_values the possible values for this option (if specified) + * @param default_value the default value (in case the option only accepts fixed values) + * @param arg_type the type of this option + * @param check_ambiguity @see cmdline_parser_params.check_ambiguity + * @param override @see cmdline_parser_params.override + * @param no_free whether to free a possible previous value + * @param multiple_option whether this is a multiple option + * @param long_opt the corresponding long option + * @param short_opt the corresponding short option (or '-' if none) + * @param additional_error possible further error specification + */ +static +int update_arg(void *field, char **orig_field, + unsigned int *field_given, unsigned int *prev_given, + char *value, const char *possible_values[], + const char *default_value, + cmdline_parser_arg_type arg_type, + int check_ambiguity, int override, + int no_free, int multiple_option, + const char *long_opt, char short_opt, + const char *additional_error) +{ + char *stop_char = 0; + const char *val = value; + int found; + char **string_field; + FIX_UNUSED (field); + + stop_char = 0; + found = 0; + + if (!multiple_option && prev_given && (*prev_given || (check_ambiguity && *field_given))) + { + if (short_opt != '-') + fprintf (stderr, "%s: `--%s' (`-%c') option given more than once%s\n", + package_name, long_opt, short_opt, + (additional_error ? additional_error : "")); + else + fprintf (stderr, "%s: `--%s' option given more than once%s\n", + package_name, long_opt, + (additional_error ? additional_error : "")); + return 1; /* failure */ + } + + FIX_UNUSED (default_value); + + if (field_given && *field_given && ! override) + return 0; + if (prev_given) + (*prev_given)++; + if (field_given) + (*field_given)++; + if (possible_values) + val = possible_values[found]; + + switch(arg_type) { + case ARG_FLAG: + *((int *)field) = !*((int *)field); + break; + case ARG_INT: + if (val) *((int *)field) = strtol (val, &stop_char, 0); + break; + case ARG_STRING: + if (val) { + string_field = (char **)field; + if (!no_free && *string_field) + free (*string_field); /* free previous string */ + *string_field = gengetopt_strdup (val); + } + break; + default: + break; + }; + + /* check numeric conversion */ + switch(arg_type) { + case ARG_INT: + if (val && !(stop_char && *stop_char == '\0')) { + fprintf(stderr, "%s: invalid numeric value: %s\n", package_name, val); + return 1; /* failure */ + } + break; + default: + ; + }; + + /* store the original value */ + switch(arg_type) { + case ARG_NO: + case ARG_FLAG: + break; + default: + if (value && orig_field) { + if (no_free) { + *orig_field = value; + } else { + if (*orig_field) + free (*orig_field); /* free previous string */ + *orig_field = gengetopt_strdup (value); + } + } + }; + + return 0; /* OK */ +} + + +int +cmdline_parser_internal ( + int argc, char **argv, struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params, const char *additional_error) +{ + int c; /* Character of the parsed option. */ + + int error_occurred = 0; + struct gengetopt_args_info local_args_info; + + int override; + int initialize; + int check_required; + int check_ambiguity; + + char *optarg; + int optind; + int opterr; + int optopt; + + package_name = argv[0]; + + override = params->override; + initialize = params->initialize; + check_required = params->check_required; + check_ambiguity = params->check_ambiguity; + + if (initialize) + cmdline_parser_init (args_info); + + cmdline_parser_init (&local_args_info); + + optarg = 0; + optind = 0; + opterr = params->print_errors; + optopt = '?'; + + while (1) + { + int option_index = 0; + + static struct option long_options[] = { + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "remote-ip", 1, NULL, 'r' }, + { "port", 1, NULL, 'p' }, + { "packet-size", 1, NULL, 's' }, + { "packet-number", 1, NULL, 'n' }, + { "interval", 1, NULL, 'i' }, + { "max-rtt", 1, NULL, 'm' }, + { "wait", 1, NULL, 'w' }, + { "verbose", 0, NULL, 'v' }, + { "ftrace", 0, NULL, 't' }, + { 0, 0, 0, 0 } + }; + + custom_optarg = optarg; + custom_optind = optind; + custom_opterr = opterr; + custom_optopt = optopt; + + c = custom_getopt_long (argc, argv, "hVr:p:s:n:i:m:w:vt", long_options, &option_index); + + optarg = custom_optarg; + optind = custom_optind; + opterr = custom_opterr; + optopt = custom_optopt; + + if (c == -1) break; /* Exit from `while (1)' loop. */ + + switch (c) + { + case 'h': /* Print help and exit. */ + cmdline_parser_print_help (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'V': /* Print version and exit. */ + cmdline_parser_print_version (); + cmdline_parser_free (&local_args_info); + exit (EXIT_SUCCESS); + + case 'r': /* Remote IP Address. */ + + + if (update_arg( (void *)&(args_info->remote_ip_arg), + &(args_info->remote_ip_orig), &(args_info->remote_ip_given), + &(local_args_info.remote_ip_given), optarg, 0, "127.0.0.1", ARG_STRING, + check_ambiguity, override, 0, 0, + "remote-ip", 'r', + additional_error)) + goto failure; + + break; + case 'p': /* UDP Port Number. */ + + + if (update_arg( (void *)&(args_info->port_arg), + &(args_info->port_orig), &(args_info->port_given), + &(local_args_info.port_given), optarg, 0, "15001", ARG_INT, + check_ambiguity, override, 0, 0, + "port", 'p', + additional_error)) + goto failure; + + break; + case 's': /* Packet size in byte. */ + + + if (update_arg( (void *)&(args_info->packet_size_arg), + &(args_info->packet_size_orig), &(args_info->packet_size_given), + &(local_args_info.packet_size_given), optarg, 0, "10", ARG_INT, + check_ambiguity, override, 0, 0, + "packet-size", 's', + additional_error)) + goto failure; + + break; + case 'n': /* Number of packet for each iteration. */ + + + if (update_arg( (void *)&(args_info->packet_number_arg), + &(args_info->packet_number_orig), &(args_info->packet_number_given), + &(local_args_info.packet_number_given), optarg, 0, "100", ARG_INT, + check_ambiguity, override, 0, 0, + "packet-number", 'n', + additional_error)) + goto failure; + + break; + case 'i': /* Period time in microseconds. If 0, iteration are running as fast as possible. */ + + + if (update_arg( (void *)&(args_info->interval_arg), + &(args_info->interval_orig), &(args_info->interval_given), + &(local_args_info.interval_given), optarg, 0, "0", ARG_INT, + check_ambiguity, override, 0, 0, + "interval", 'i', + additional_error)) + goto failure; + + break; + case 'm': /* Maximum time of one period. If 0, the interval value is used and if interval is 0, this check is disabled.. */ + + + if (update_arg( (void *)&(args_info->max_rtt_arg), + &(args_info->max_rtt_orig), &(args_info->max_rtt_given), + &(local_args_info.max_rtt_given), optarg, 0, "0", ARG_INT, + check_ambiguity, override, 0, 0, + "max-rtt", 'm', + additional_error)) + goto failure; + + break; + case 'w': /* For server side only. This value define how much the server wait before sending back packets.. */ + + + if (update_arg( (void *)&(args_info->wait_arg), + &(args_info->wait_orig), &(args_info->wait_given), + &(local_args_info.wait_given), optarg, 0, "0", ARG_INT, + check_ambiguity, override, 0, 0, + "wait", 'w', + additional_error)) + goto failure; + + break; + case 'v': /* Increase program verbosity. */ + + + if (update_arg((void *)&(args_info->verbose_flag), 0, &(args_info->verbose_given), + &(local_args_info.verbose_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "verbose", 'v', + additional_error)) + goto failure; + + break; + case 't': /* Enable ftrace and reset trace on each iteration. Use with max-rtt option. Requires root rights.. */ + + + if (update_arg((void *)&(args_info->ftrace_flag), 0, &(args_info->ftrace_given), + &(local_args_info.ftrace_given), optarg, 0, 0, ARG_FLAG, + check_ambiguity, override, 1, 0, "ftrace", 't', + additional_error)) + goto failure; + + break; + + case 0: /* Long option with no short option */ + case '?': /* Invalid option. */ + /* `getopt_long' already printed an error message. */ + goto failure; + + default: /* bug: option not considered. */ + fprintf (stderr, "%s: option unknown: %c%s\n", CMDLINE_PARSER_PACKAGE, c, (additional_error ? additional_error : "")); + abort (); + } /* switch */ + } /* while */ + + + + + cmdline_parser_release (&local_args_info); + + if ( error_occurred ) + return (EXIT_FAILURE); + + return 0; + +failure: + + cmdline_parser_release (&local_args_info); + return (EXIT_FAILURE); +} diff --git a/todo/udptest/cmdline.h b/todo/udptest/cmdline.h new file mode 100644 index 0000000..65d3080 --- /dev/null +++ b/todo/udptest/cmdline.h @@ -0,0 +1,207 @@ +/** @file cmdline.h + * @brief The header file for the command line option parser + * generated by GNU Gengetopt version 2.22.6 + * http://www.gnu.org/software/gengetopt. + * DO NOT modify this file, since it can be overwritten + * @author GNU Gengetopt by Lorenzo Bettini */ + +#ifndef CMDLINE_H +#define CMDLINE_H + +/* If we use autoconf. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include /* for FILE */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef CMDLINE_PARSER_PACKAGE +/** @brief the program name (used for printing errors) */ +#define CMDLINE_PARSER_PACKAGE "udptest" +#endif + +#ifndef CMDLINE_PARSER_PACKAGE_NAME +/** @brief the complete program name (used for help and version) */ +#define CMDLINE_PARSER_PACKAGE_NAME "udptest" +#endif + +#ifndef CMDLINE_PARSER_VERSION +/** @brief the program version */ +#define CMDLINE_PARSER_VERSION "0.1" +#endif + +/** @brief Where the command line options are stored */ +struct gengetopt_args_info +{ + const char *help_help; /**< @brief Print help and exit help description. */ + const char *version_help; /**< @brief Print version and exit help description. */ + char * remote_ip_arg; /**< @brief Remote IP Address (default='127.0.0.1'). */ + char * remote_ip_orig; /**< @brief Remote IP Address original value given at command line. */ + const char *remote_ip_help; /**< @brief Remote IP Address help description. */ + int port_arg; /**< @brief UDP Port Number (default='15001'). */ + char * port_orig; /**< @brief UDP Port Number original value given at command line. */ + const char *port_help; /**< @brief UDP Port Number help description. */ + int packet_size_arg; /**< @brief Packet size in byte (default='10'). */ + char * packet_size_orig; /**< @brief Packet size in byte original value given at command line. */ + const char *packet_size_help; /**< @brief Packet size in byte help description. */ + int packet_number_arg; /**< @brief Number of packet for each iteration (default='100'). */ + char * packet_number_orig; /**< @brief Number of packet for each iteration original value given at command line. */ + const char *packet_number_help; /**< @brief Number of packet for each iteration help description. */ + int interval_arg; /**< @brief Period time in microseconds. If 0, iteration are running as fast as possible (default='0'). */ + char * interval_orig; /**< @brief Period time in microseconds. If 0, iteration are running as fast as possible original value given at command line. */ + const char *interval_help; /**< @brief Period time in microseconds. If 0, iteration are running as fast as possible help description. */ + int max_rtt_arg; /**< @brief Maximum time of one period. If 0, the interval value is used and if interval is 0, this check is disabled. (default='0'). */ + char * max_rtt_orig; /**< @brief Maximum time of one period. If 0, the interval value is used and if interval is 0, this check is disabled. original value given at command line. */ + const char *max_rtt_help; /**< @brief Maximum time of one period. If 0, the interval value is used and if interval is 0, this check is disabled. help description. */ + int wait_arg; /**< @brief For server side only. This value define how much the server wait before sending back packets. (default='0'). */ + char * wait_orig; /**< @brief For server side only. This value define how much the server wait before sending back packets. original value given at command line. */ + const char *wait_help; /**< @brief For server side only. This value define how much the server wait before sending back packets. help description. */ + int verbose_flag; /**< @brief Increase program verbosity (default=off). */ + const char *verbose_help; /**< @brief Increase program verbosity help description. */ + int ftrace_flag; /**< @brief Enable ftrace and reset trace on each iteration. Use with max-rtt option. Requires root rights. (default=off). */ + const char *ftrace_help; /**< @brief Enable ftrace and reset trace on each iteration. Use with max-rtt option. Requires root rights. help description. */ + + unsigned int help_given ; /**< @brief Whether help was given. */ + unsigned int version_given ; /**< @brief Whether version was given. */ + unsigned int remote_ip_given ; /**< @brief Whether remote-ip was given. */ + unsigned int port_given ; /**< @brief Whether port was given. */ + unsigned int packet_size_given ; /**< @brief Whether packet-size was given. */ + unsigned int packet_number_given ; /**< @brief Whether packet-number was given. */ + unsigned int interval_given ; /**< @brief Whether interval was given. */ + unsigned int max_rtt_given ; /**< @brief Whether max-rtt was given. */ + unsigned int wait_given ; /**< @brief Whether wait was given. */ + unsigned int verbose_given ; /**< @brief Whether verbose was given. */ + unsigned int ftrace_given ; /**< @brief Whether ftrace was given. */ + +} ; + +/** @brief The additional parameters to pass to parser functions */ +struct cmdline_parser_params +{ + int override; /**< @brief whether to override possibly already present options (default 0) */ + int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */ + int check_required; /**< @brief whether to check that all required options were provided (default 1) */ + int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */ + int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */ +} ; + +/** @brief the purpose string of the program */ +extern const char *gengetopt_args_info_purpose; +/** @brief the usage string of the program */ +extern const char *gengetopt_args_info_usage; +/** @brief the description string of the program */ +extern const char *gengetopt_args_info_description; +/** @brief all the lines making the help output */ +extern const char *gengetopt_args_info_help[]; + +/** + * The command line parser + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser (int argc, char **argv, + struct gengetopt_args_info *args_info); + +/** + * The command line parser (version with additional parameters - deprecated) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param override whether to override possibly already present options + * @param initialize whether to initialize the option structure my_args_info + * @param check_required whether to check that all required options were provided + * @return 0 if everything went fine, NON 0 if an error took place + * @deprecated use cmdline_parser_ext() instead + */ +int cmdline_parser2 (int argc, char **argv, + struct gengetopt_args_info *args_info, + int override, int initialize, int check_required); + +/** + * The command line parser (version with additional parameters) + * @param argc the number of command line options + * @param argv the command line options + * @param args_info the structure where option information will be stored + * @param params additional parameters for the parser + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_ext (int argc, char **argv, + struct gengetopt_args_info *args_info, + struct cmdline_parser_params *params); + +/** + * Save the contents of the option struct into an already open FILE stream. + * @param outfile the stream where to dump options + * @param args_info the option struct to dump + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_dump(FILE *outfile, + struct gengetopt_args_info *args_info); + +/** + * Save the contents of the option struct into a (text) file. + * This file can be read by the config file parser (if generated by gengetopt) + * @param filename the file where to save + * @param args_info the option struct to save + * @return 0 if everything went fine, NON 0 if an error took place + */ +int cmdline_parser_file_save(const char *filename, + struct gengetopt_args_info *args_info); + +/** + * Print the help + */ +void cmdline_parser_print_help(void); +/** + * Print the version + */ +void cmdline_parser_print_version(void); + +/** + * Initializes all the fields a cmdline_parser_params structure + * to their default values + * @param params the structure to initialize + */ +void cmdline_parser_params_init(struct cmdline_parser_params *params); + +/** + * Allocates dynamically a cmdline_parser_params structure and initializes + * all its fields to their default values + * @return the created and initialized cmdline_parser_params structure + */ +struct cmdline_parser_params *cmdline_parser_params_create(void); + +/** + * Initializes the passed gengetopt_args_info structure's fields + * (also set default values for options that have a default) + * @param args_info the structure to initialize + */ +void cmdline_parser_init (struct gengetopt_args_info *args_info); +/** + * Deallocates the string fields of the gengetopt_args_info structure + * (but does not deallocate the structure itself) + * @param args_info the structure to deallocate + */ +void cmdline_parser_free (struct gengetopt_args_info *args_info); + +/** + * Checks that all the required options were specified + * @param args_info the structure to check + * @param prog_name the name of the program that will be used to print + * possible errors + * @return + */ +int cmdline_parser_required (struct gengetopt_args_info *args_info, + const char *prog_name); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CMDLINE_H */ diff --git a/todo/udptest/com.c b/todo/udptest/com.c new file mode 100644 index 0000000..349ac83 --- /dev/null +++ b/todo/udptest/com.c @@ -0,0 +1,109 @@ +#include "common.h" + +int com_init_server(struct sockaddr_in *sockaddr, socklen_t *socklen, int port) +{ + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/); + if (s < 0) + { + printf("Failed to create socket\n"); + return -1; + } + + /* This will be filled by the first recvfrom() with the peer's addr */ + *socklen = sizeof(struct sockaddr_in); + memset((char *) sockaddr, 0, sizeof(struct sockaddr_in)); + + struct sockaddr_in host; + host.sin_family = AF_INET; + host.sin_port = htons(port); + host.sin_addr.s_addr = htonl(INADDR_ANY); + + if(bind(s, (struct sockaddr*)&host, sizeof(struct sockaddr_in)) == -1) + { + printf("Failed to bind sockaddr\n"); + return -2; + } + + return s; +} + +int com_init_client(struct sockaddr_in *sockaddr, socklen_t *socklen, const char* ipaddr, int port, int timeout_us) +{ + int s; + struct timeval tv; + + s = socket(AF_INET, SOCK_DGRAM, 0 /*IPPROTO_UDP*/); + if (s < 0) + { + printf("Failed to create socket\n"); + return -1; + } + + *socklen = sizeof(struct sockaddr_in); + memset((char *) sockaddr, 0, sizeof(struct sockaddr_in)); + sockaddr->sin_family = AF_INET; + sockaddr->sin_port = htons(port); + + if (inet_aton(ipaddr, &(sockaddr->sin_addr)) == 0) + { + printf("Failed to binarize IP addr\n"); + return -2; + } + + if (timeout_us > 0) { + /* Note : Starting from NH4, this timeout must be greater than 2*Hz + * Assuming HZ=1000, this means the minimum timeout is 2ms. + * This timeout is only here to unblock blocking rcv()/send(), time checking is done in the main loop. + */ + if (timeout_us < 2000) { + timeout_us = 2000; + } + tv.tv_sec = timeout_us / 1000000; + tv.tv_usec = timeout_us % 1000000; + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)); + } + + return s; +} + +int com_send(struct sockaddr_in *sockaddr, socklen_t *socklen, int fd, char *packet_out, int size) +{ + ssize_t sent; + + sent = sendto(fd, packet_out, size, 0 , (struct sockaddr *) sockaddr, *socklen); + + if (sent < 0) + { + printf("Failed to send packet, errno = %d\n", errno); + return -errno; + } + else if (sent != size) + { + printf("Sendto has not sent all the bytes : %ld sent and %d expected.\n", sent, size); + return -1; + } + + return 0; +} + +int com_receive(struct sockaddr_in *sockaddr, socklen_t *socklen, int fd, char *packet_in, int size) +{ + ssize_t rcvd; + + rcvd = recvfrom(fd, packet_in, size, 0, (struct sockaddr *) sockaddr, socklen); + + if (rcvd < 0) + { + printf("Failed to receive packet, errno = %d (%s)\n", errno, strerror(errno)); + return -errno; + } + else if (rcvd != size) + { + printf("Recvfrom has not received all the bytes : %ld received and %d expected.\n", rcvd, size); + return -1; + } + + return 0; +} diff --git a/todo/udptest/common.h b/todo/udptest/common.h new file mode 100644 index 0000000..6cab22c --- /dev/null +++ b/todo/udptest/common.h @@ -0,0 +1,56 @@ +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __vxworks +#include +#endif + +#define clock_s struct timespec + +struct latency_s { + int max_us; + int min_us; + long long cumul_us; + long long iter_number; +}; + +int com_init_server(struct sockaddr_in *sockaddr, socklen_t *socklen, int port); +int com_init_client(struct sockaddr_in *sockaddr, socklen_t *socklen, const char* ipaddr, int port, int timeout_us); +int com_send(struct sockaddr_in *sockaddr, socklen_t *socklen, int fd, char *packet_out, int size); +int com_receive(struct sockaddr_in *sockaddr, socklen_t *socklen, int fd, char *packet_in, int size); + +int timer_init(void); /* Return fd to use */ +int timer_setdelay(int fd, unsigned int delay_us); +int timer_wait(int fd); + +#ifndef __vxworks +void clock_current(clock_s *now); +int clock_diff_us(clock_s c1, clock_s c2); /* Return the difference in milliseconds */ +void clock_latency_update(clock_s prev, clock_s now, struct latency_s *latency, const char* name, int verbose); +#else +void clock_current(uint64_t* now); +int clock_diff_us(uint64_t t1, uint64_t t2); +void clock_latency_update(uint64_t t1, uint64_t t2, struct latency_s* latency, const char* name, int verbose); +#endif +void clock_latency_print(struct latency_s* latency, const char* name); +void clock_latency_reset_avg(struct latency_s* latency); +void clock_latency_init(struct latency_s* latency); + +int start_ftrace(); /* Return fd to use with stop_ftrace() */ +void stop_ftrace(); +void reset_ftrace(); +void init_trace_marker(); +void trace_write(const char *fmt, ...); + + +#endif diff --git a/todo/udptest/ftrace.c b/todo/udptest/ftrace.c new file mode 100644 index 0000000..fb75cb4 --- /dev/null +++ b/todo/udptest/ftrace.c @@ -0,0 +1,64 @@ +#include +#include +#include +#include +#include "common.h" + +int start_ftrace() +{ + int fd; + char one = '1'; + + fd = open("/sys/kernel/debug/tracing/tracing_on", O_WRONLY); + write(fd, &one, 1); + close(fd); + + return fd; +} + +void stop_ftrace() +{ + int fd; + char zero = '0'; + + fd = open("/sys/kernel/debug/tracing/tracing_on", O_WRONLY); + write(fd, &zero, 1); + close(fd); +} + +void reset_ftrace() +{ + int fd; + char zero = '0'; + + fd = open("/sys/kernel/debug/tracing/trace", O_WRONLY); + write(fd, &zero, 1); + close(fd); +} + +static int trace_marker_fd = -1; +void init_trace_marker() +{ + trace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY); + if(trace_marker_fd < 0) { + fprintf(stderr, "Warning can't open ftrace marker (errno=%d) (it will be ignored)\n", errno); + } + +} + +void trace_write(const char *fmt, ...) +{ + va_list ap; + char buf[256]; + int n; + + if (trace_marker_fd < 0) + return; + + va_start(ap, fmt); + n = vsnprintf(buf, 256, fmt, ap); + va_end(ap); + + write(trace_marker_fd, buf, n); +} + diff --git a/todo/udptest/launch.c b/todo/udptest/launch.c new file mode 100644 index 0000000..d118962 --- /dev/null +++ b/todo/udptest/launch.c @@ -0,0 +1,15 @@ +#include +#include +#include + +extern int main(int argc, char **argv); + +int launch_udptest(char *ip_addr) { + + printf ("IP= <%s>\n", ip_addr); + + char *argv[] = { "udptest", "-n", "1", "-r", ip_addr}; + int argc = sizeof(argv) / sizeof(argv[0]); + + return main(argc, argv); +} diff --git a/todo/udptest/timer.c b/todo/udptest/timer.c new file mode 100644 index 0000000..55fb675 --- /dev/null +++ b/todo/udptest/timer.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include "common.h" + +/* Use timerfd using the libc */ +int timer_init(void) +{ + int timerfd = -1; + + /* Create FD */ + timerfd = timerfd_create(CLOCK_REALTIME, 0); + + return timerfd; +} + +int timer_setdelay(int fd, unsigned int delay_us) +{ + struct itimerspec ts; + + memset(&ts, sizeof(ts), 0); + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_sec = delay_us / 1000000; + ts.it_value.tv_nsec = (delay_us * 1000) % 1000000000; + + int res = timerfd_settime(fd, 0, &ts, 0); + if(res < 0){ + printf("Failed to configure timer\n"); + return -1; + } + + return 0; +} + +int timer_wait(int fd) +{ + fd_set set; + int ret; + + FD_ZERO(&set); + FD_SET(fd, &set); + + ret = select(FD_SETSIZE, &set, NULL, NULL,NULL); + + return ret; +} + + diff --git a/todo/udptest/udptest.c b/todo/udptest/udptest.c new file mode 100644 index 0000000..9f1e346 --- /dev/null +++ b/todo/udptest/udptest.c @@ -0,0 +1,188 @@ +#include "common.h" +#include "cmdline.h" + +int main(int argc, char** argv) +{ + + struct gengetopt_args_info opt; + char* packets; + struct sockaddr_in sockaddr; + struct latency_s lat_rtt; + #ifndef __vxworks + clock_s time_begin_of_iter, time_end_of_iter; + clock_s time_last_print; + #else + uint64_t time_begin_of_iter, time_end_of_iter; + uint64_t time_last_print; + #endif + socklen_t socklen; + int fd_udp, fd_timer, i, timeout_socket_us = 0, loop_iter = 0, rc; + int duration_iter, since_last_print; + uint32_t seq_start = 0; /* Sequence counter to check for packet ordering and synchro */ + uint32_t *seq; + int warmup = 1; /* Drop only first iteration */ + int leaving = 0; + + if (cmdline_parser(argc, argv, &opt) != 0) { + return -1; + } + + if (opt.packet_size_arg < 4) { + printf("Error: Packet size must be at least 4 bytes as we store a sequence counter in it.\n"); + return -1; + } + +#ifndef __vxworks + init_trace_marker(); +#endif + + printf("Starting UDPtest.\n"); + printf("Send %d packets of %d bytes and receive them every %d us.\n", opt.packet_number_arg, opt.packet_size_arg, opt.interval_arg); + + if (opt.interval_arg > 0) { + timeout_socket_us = opt.interval_arg; + } else if (opt.max_rtt_arg > 0) { + timeout_socket_us = opt.max_rtt_arg; + } else { + timeout_socket_us = 1000000; /* One second timeout */ + } + + fd_udp = com_init_client(&sockaddr, &socklen, opt.remote_ip_arg, opt.port_arg, timeout_socket_us); + if (fd_udp < 0) { + printf("Failed to open socket for UDP communication. Check ip address and port number availability.\n"); + return -1; + } else if (opt.verbose_flag) { + printf("Fd for UDP communication is %d.\n", fd_udp); + } + printf("Sending to %s on port %d\n", opt.remote_ip_arg, opt.port_arg); + + /* Buffer allocation */ + packets = malloc(opt.packet_size_arg * opt.packet_number_arg); + memset(packets, 0xaa, opt.packet_size_arg * opt.packet_number_arg); /* Will trigger allocation on write for overcommit system */ + + /* TimerFD initialization */ +#ifndef __vxworks + fd_timer = timer_init(); +#endif + + /* Latency statistics initialization */ + clock_latency_init(&lat_rtt); + clock_current(&time_last_print); + + /* Ftrace initialization */ + if (opt.ftrace_flag) { + //TODO configure? + //TODO check if possible or fail (ie.root rights) +#ifndef __vxworks + start_ftrace(); +#endif + } + + while (!leaving) { + loop_iter++; + + if (opt.ftrace_flag) { +#ifndef __vxworks + reset_ftrace(); +#endif + } + +#ifndef __vxworks + timer_setdelay(fd_timer, opt.interval_arg); +#endif + + /* Init time */ + clock_current(&time_begin_of_iter); + + /* Init sequence counter */ + seq_start = (loop_iter * opt.packet_number_arg) % UINT_MAX; + + for (i=0; i 1000000) { /* Print statistics each second */ + time_last_print = time_end_of_iter; + clock_latency_print(&lat_rtt, "lat_rtt"); + clock_latency_reset_avg(&lat_rtt); + } + } + + /* Check that one iteration is less than the period */ + duration_iter = clock_diff_us(time_begin_of_iter, time_end_of_iter); + // trace_write("udptest : %dus lat", duration_iter); + if (opt.interval_arg > 0 && duration_iter > opt.interval_arg && !warmup) { + if (opt.ftrace_flag) { + // stop_ftrace(); + } + clock_latency_print(&lat_rtt, "lat_rtt"); + printf("Loop period exceeded. Exit.\n"); + leaving = 1; + } + /* Check that RTT is less than the one asked */ + if (opt.max_rtt_arg > 0 && duration_iter > opt.max_rtt_arg && !warmup) { + if (opt.ftrace_flag) { + // stop_ftrace(); + } + clock_latency_print(&lat_rtt, "lat_rtt"); + printf("UDP packets RTT exceeded. Exit.\n"); + leaving = 1; + } + + if (warmup > 0) { + warmup--; + } + + if (opt.verbose_flag) { + printf("End of loop %d.\n", loop_iter); + } + + if (!leaving && opt.interval_arg > 0) { +#ifndef __vxworks + timer_wait(fd_timer); +#endif + } + } + + close(fd_udp); + + return 0; +} diff --git a/todo/udptest/udptestserver.c b/todo/udptest/udptestserver.c new file mode 100644 index 0000000..b00aa76 --- /dev/null +++ b/todo/udptest/udptestserver.c @@ -0,0 +1,87 @@ +#include "common.h" +#include "cmdline.h" + +int main(int argc, char** argv) +{ + struct gengetopt_args_info opt; + struct sockaddr_in sockaddr; + socklen_t socklen; + char* packets; + int fd_udp, i; + int loop_iter = 0; + struct timespec wait; + uint32_t seq_start = 0; /* Sequence counter to check for packet ordering and synchro */ + uint32_t *seq; + + if (cmdline_parser(argc, argv, &opt) != 0) { + return -1; + } + + if (opt.packet_size_arg < 4) { + printf("Error: Packet size must be at least 4 bytes as we store a sequence counter in it.\n"); + return -1; + } + + printf("Starting UDPtest server side.\n"); + printf("Receive %d packets of %d bytes and send them back after %d us.\n", opt.packet_number_arg, opt.packet_size_arg, opt.wait_arg); + + fd_udp = com_init_server(&sockaddr, &socklen, opt.port_arg); + if (fd_udp < 0) { + printf("Failed to open socket for UDP communication. Check port number availability %d.\n", opt.port_arg); + return -1; + } else if (opt.verbose_flag) { + printf("Fd for UDP communication is %d.\n", fd_udp); + } + printf("Listening on port %d\n", opt.port_arg); + + /* Buffer allocation */ + packets = malloc(opt.packet_size_arg * opt.packet_number_arg); + memset(packets, 0xaa, opt.packet_size_arg * opt.packet_number_arg); /* Will trigger allocation on write for overcommit system */ + + /* Wait timeval initialization */ + if (opt.wait_arg > 0) { + wait.tv_sec = opt.wait_arg / 1000000; + wait.tv_nsec = (opt.wait_arg * 1000) % 1000000; + } + + while (1) { + loop_iter++; + + /* Init sequence counter (same init as udptest program) */ + seq_start = (loop_iter * opt.packet_number_arg) % UINT_MAX; + + for (i=0; i 0) { + clock_nanosleep(CLOCK_MONOTONIC, 0, &wait, NULL); + } + + if (opt.verbose_flag) { + printf("Send back the packets\n"); + } + + for (i=0; i