diff --git a/project/.gitignore b/project/.gitignore new file mode 100644 index 0000000..2700bb3 --- /dev/null +++ b/project/.gitignore @@ -0,0 +1 @@ +netem diff --git a/project/Makefile b/project/Makefile new file mode 100644 index 0000000..e516727 --- /dev/null +++ b/project/Makefile @@ -0,0 +1,17 @@ +TARGET = netem + +OBJS = main.o probe.o + +CC = gcc +CFLAGS = -g -lrt + +all: $(TARGET) Makefile + +$(TARGET): $(OBJS) + $(CC) -o $@ $^ + +clean: + rm -f $(TARGET) + rm -f *.o *~ + +.PHONY: all clean diff --git a/project/main.c b/project/main.c new file mode 100644 index 0000000..b490486 --- /dev/null +++ b/project/main.c @@ -0,0 +1,98 @@ +#include +#include + +#include +#include + +#include +#include + +#define VERSION "0.1" + +int running = 1; + +void quit(int sig, siginfo_t *si, void *ptr) +{ + printf("Goodbye!\n"); + running = 0; +} + +int main(int argc, char *argv[]) +{ + /* Options */ + int mark; + int interval; + int rate; + + if (argc < 2) { + printf("usage: %s CMD [OPTIONS]\n", argv[0]); + printf(" CMD can be one of:\n"); + printf(" live \n"); + printf(" probe \n"); + printf(" emulate \n"); + + /* + -m --mark N apply emulation only to packet buffers with mark N + -i --interval N update the emulation parameters every N seconds + -r --rate the packet rate used for measurements + */ + + printf("\n"); + printf("netem util %s (built on %s %s)\n", + VERSION, __DATE__, __TIME__); + printf(" Copyright 2015, Steffen Vogel \n"); + + exit(EXIT_FAILURE); + } + + char *cmd = argv[1]; + + /* Setup signals */ + struct sigaction sa_quit = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = quit + }; + + sigemptyset(&sa_quit.sa_mask); + sigaction(SIGTERM, &sa_quit, NULL); + sigaction(SIGINT, &sa_quit, NULL); + + /* Parse Arguments */ + char c, *endptr; + while ((c = getopt (argc-1, argv+1, "h:m:i:")) != -1) { + switch (c) { + case 'm': + mark = strtoul(optarg, &endptr, 10); + goto check; + case 'i': + interval = strtoul(optarg, &endptr, 10); + goto check; + case 'r': + rate = strtoul(optarg, &endptr, 10); + goto check; + + case '?': + if (optopt == 'c') + error(-1, 0, "Option -%c requires an argument.", optopt); + else if (isprint(optopt)) + error(-1, 0, "Unknown option '-%c'.", optopt); + else + error(-1, 0, "Unknown option character '\\x%x'.", optopt); + exit(EXIT_FAILURE); + default: + abort(); + } + + continue; +check: + if (optarg == endptr) + error(-1, 0, "Failed to parse parse option argument '-%c %s'", c, optarg); + } + + if (!strcmp(cmd, "probe")) + return probe(); + else + error(-1, 0, "Unknown command: %s", cmd); + + return 0; +} \ No newline at end of file diff --git a/project/probe.c b/project/probe.c new file mode 100644 index 0000000..e29dd1a --- /dev/null +++ b/project/probe.c @@ -0,0 +1,60 @@ +#include +#include + +#include +#include + +int probe() +{ + int val; + + printf("Start probing\n"); + + /* Create RAW socket */ + int sd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); + + /* Enable kernel / hw timestamping */ + val = SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_SOFTWARE; /* Enable RX timestamps */ + val |= SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_TX_SOFTWARE; /* Enable TX timestamps */ + + val |= SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE; /* Report SW and HW timestamps */ + + val |= SOF_TIMESTAMPING_OPT_TSONLY; /* Only return timestamp in cmsg */ + + if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, (void *) val, &val)) + error(-1, errno, "Failed to set SO_TIMESTAMPING"); + + + return 0; +} + +int probe_read_ts(int sd) +{ + char cmsg[1024]; + struct msghdr msgh = { + .msg_name = NULL, .msg_namelen = 0, + .msg_iov = NULL, .msg_iovlen = 0, + .msg_control = &cmsg, .msg_controllen = sizeof(cmsg) + }; + struct cmsghdr *cmsg; + struct timespec *ts; + + if (recvmsg(sd, &msgh, 0) == -1) + error(-1, errno, "Failed to get control messages"); + + /* Receive auxiliary data in msgh */ + for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_TIMESTAMPING) { + ts = (struct timespec*) CMSG_DATA(cmsg); + break; + } + } + if (cmsg == NULL) + error(-1, 0, "SO_TIMESTAMPING not enabled or small buffer or I/O error."); + + if (ts) { + for (int i = 0; i < 3; i++) { + print_ts(&ts[i]); + } + } +} \ No newline at end of file