#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
static int so, srv_so;
static int srv_port = 0;
static struct sockaddr_in laddr, dst_addr;
static struct sockaddr_in srv_addr;
static uint32_t tc = 0;
void ErrorUsage(void);
uint32_t str2svc(const char *str);
void ShowStastics(int64_t *DiffsBuf, int num_frames);
int64_t time_diff(struct timeval *b, struct timeval *a);
void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
void tcpClient(int num_frames, int frame_size,
const char *buf, struct timespec sleep_time);
void udpClient(int num_frames, int frame_size,
const char *buf, struct timespec sleep_time);
int
main(int argc, char *argv[])
{
int num_frames = 0, frame_size = 0, delay_ms = 0, rc = 0;
char *buf = NULL, ch, *type = NULL, *mode = NULL, *ip_addr = NULL;
int64_t *DiffsBuf;
struct timespec sleep_time;
while ((ch = getopt(argc, argv, "m:p:f:n:t:d:i:k:")) != -1) {
switch (ch) {
case 'm': {
mode = optarg;
break;
}
case 'p': {
srv_port = atoi(optarg);
break;
}
case 'f' : {
frame_size = atoi(optarg);
break;
}
case 'n' : {
num_frames = atoi(optarg);
break;
}
case 'i': {
ip_addr = optarg;
bzero(&srv_addr, sizeof(srv_addr));
rc = inet_aton(optarg, &srv_addr.sin_addr);
if (rc == 0) {
perror("inet_ntoa failed");
exit(1);
}
}
case 'd': {
delay_ms = atoi(optarg);
break;
}
case 't' : {
type = optarg;
break;
}
case 'k': {
tc = str2svc(optarg);
break;
}
default: {
printf("Invalid option: %c\n", ch);
ErrorUsage();
}
}
}
if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) {
ErrorUsage();
}
if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) {
ErrorUsage();
}
buf = calloc(1, frame_size);
if (buf == NULL) {
printf("malloc failed\n");
exit(1);
}
if ( strcmp(mode, "server") == 0 ) {
printf("<LOG> : Start %s server on port %d with expected frame size of %d\n",
type, srv_port, frame_size);
DiffsBuf = (int64_t *)calloc(num_frames, sizeof(int64_t));
if (DiffsBuf == NULL) {
printf("malloc failed\n");
exit(1);
}
if( strcmp(type, "tcp") == 0) {
tcpServer(frame_size, num_frames, buf, DiffsBuf);
} else {
udpServer(frame_size, num_frames, buf, DiffsBuf);
}
}
else if ( strcmp(mode, "client") == 0 ){
if ( !ip_addr || (tc > 0 && (tc < SO_TC_BK_SYS || tc > SO_TC_CTL)) ){
ErrorUsage();
}
printf("<LOG> : Start sending %d %s frames to %s:%d with a frame size of %d\n",
num_frames, type, ip_addr, srv_port, frame_size);
bzero(&sleep_time, sizeof(sleep_time));
while (delay_ms >= 1000) {
sleep_time.tv_sec++;
delay_ms -= 1000;
}
sleep_time.tv_nsec = delay_ms * 1000 * 1000;
if( strcmp(type, "tcp") == 0) {
tcpClient(num_frames, frame_size, buf, sleep_time);
} else {
udpClient(num_frames, frame_size, buf, sleep_time);
}
} else {
ErrorUsage();
}
}
void
ErrorUsage(void) {
printf("Correct Usage");
printf("Server : frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>\n");
printf("Client : frame_delay -m client -t <tcp/udp> -i <srv_ipv4_add> -p <srv_port> -n <num_frames> -f <frame_size> -d <delay_ms> -k <traffic_class>\n");
exit(1);
}
uint32_t
str2svc(const char *str)
{
uint32_t svc;
char *endptr;
if (str == NULL || *str == '\0')
svc = UINT32_MAX;
else if (strcasecmp(str, "BK_SYS") == 0)
return SO_TC_BK_SYS;
else if (strcasecmp(str, "BK") == 0)
return SO_TC_BK;
else if (strcasecmp(str, "BE") == 0)
return SO_TC_BE;
else if (strcasecmp(str, "RD") == 0)
return SO_TC_RD;
else if (strcasecmp(str, "OAM") == 0)
return SO_TC_OAM;
else if (strcasecmp(str, "AV") == 0)
return SO_TC_AV;
else if (strcasecmp(str, "RV") == 0)
return SO_TC_RV;
else if (strcasecmp(str, "VI") == 0)
return SO_TC_VI;
else if (strcasecmp(str, "VO") == 0)
return SO_TC_VO;
else if (strcasecmp(str, "CTL") == 0)
return SO_TC_CTL;
else {
svc = (uint32_t)strtoul(str, &endptr, 0);
if (*endptr != '\0')
svc = UINT32_MAX;
}
return (svc);
}
void
ShowStastics(int64_t *DiffsBuf, int num_frames) {
int i = 0;
int64_t sum = 0, mean = 0;
while(i < num_frames)
sum += DiffsBuf[i++];
mean = sum / num_frames;
printf("<LOG> : Mean: %.2f usecs\n", sum / (double)num_frames);
i = 0;
sum = 0;
while(i < num_frames) {
sum += (DiffsBuf[i]-mean)*(DiffsBuf[i]-mean);
i++;
}
printf("<LOG> : Popular Standard Deviation: %.2f usecs\n",
sqrt(sum/(double)num_frames));
}
int64_t
time_diff(struct timeval *b, struct timeval *a)
{
int64_t usecs;
usecs = (a->tv_sec - b->tv_sec) * 1000 * 1000;
usecs += (int64_t)(a->tv_usec - b->tv_usec);
return(usecs);
}
void
tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
int rc = 0, i = 0, ignore_count = 0;
uint32_t dst_len = 0;
struct timeval before, after;
ssize_t bytes;
int64_t usecs;
uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
printf("<LOG> : TCP Server\n");
so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (so == -1) {
perror("failed to create socket");
exit(1);
}
bzero(&laddr, sizeof(laddr));
laddr.sin_family = AF_INET;
laddr.sin_port = htons(srv_port);
rc = bind(so, (const struct sockaddr *)&laddr, sizeof(laddr));
if (rc != 0) {
perror("failed to bind");
exit(1);
}
rc = listen(so, 10);
if (rc != 0) {
perror("failed to listen");
exit(1);
}
srv_so = accept(so, (struct sockaddr *)&dst_addr, &dst_len);
if (srv_so == -1) {
perror("failed to accept");
exit(1);
}
while (1) {
if ( i == num_frames ) {
printf("<LOG> : Completed\n");
break;
}
printf("<LOG> : Waiting for receiving\n");
bzero(&before, sizeof(before));
bzero(&after, sizeof(after));
rc = gettimeofday(&before, NULL);
if (rc == -1) {
perror("gettimeofday failed");
exit(1);
}
bytes = recv(srv_so, buf, frame_size, MSG_WAITALL);
if (bytes == -1) {
perror("recv failed");
exit(1);
}
else if (bytes > 0 && bytes != frame_size) {
printf("Client exited\n");
printf("Didn't recv the complete frame, bytes %ld\n",
bytes);
exit(1);
}
else if (bytes == 0) {
break;
}
rc = gettimeofday(&after, NULL);
if (rc == -1) {
perror("gettimeofday failed");
exit(1);
}
cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
if (prev_frame_ts > 0) {
int64_t d_variation = 0;
d_variation = (int64_t)((cur_recv - prev_recv) -
(frame_ts - prev_frame_ts));
if (d_variation > 0) {
if (min_variation == 0)
min_variation = d_variation;
else
min_variation = ((min_variation <= d_variation) ?
min_variation : d_variation);
max_variation = ((max_variation >= d_variation) ?
max_variation : d_variation);
avg_variation += d_variation;
} else {
ignore_count++;
}
}
prev_recv = cur_recv;
prev_frame_ts = frame_ts;
++i;
usecs = time_diff(&before, &after);
DiffsBuf[i] = usecs;
printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
}
if (i != ignore_count)
avg_variation = avg_variation / (i - ignore_count);
else
avg_variation = 0;
printf("<LOG> : Received frames: %u\n", i);
printf("<LOG> : Ignored frames: %u\n", ignore_count);
printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
ShowStastics(DiffsBuf, num_frames);
}
void
udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
int rc = 0, i = 0, ignore_count = 0;
uint32_t dst_len = 0;
ssize_t bytes;
struct timeval before, after;
int64_t usecs;
uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
printf("<LOG> : UDP Server\n");
so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (so == -1) {
perror("failed to create socket");
exit(1);
}
bzero(&laddr,sizeof(laddr));
laddr.sin_family = AF_INET;
laddr.sin_addr.s_addr=htonl(INADDR_ANY);
laddr.sin_port=htons(srv_port);
rc = bind(so, (struct sockaddr *)&laddr,sizeof(laddr));
if (rc != 0) {
perror("failed to bind");
exit(1);
}
while (1) {
if ( i == num_frames ) {
printf("<LOG> : Completed\n");
break;
}
printf("<LOG> : Waiting for receiving\n");
bzero(&before, sizeof(before));
bzero(&after, sizeof(after));
rc = gettimeofday(&before, NULL);
if (rc == -1) {
perror("gettimeofday failed");
exit(1);
}
bytes = recvfrom(so, buf, frame_size, 0, (struct sockaddr *)&dst_addr, &dst_len);
if (bytes == -1) {
perror("recv failed");
exit(1);
}
else if (bytes > 0 && bytes != frame_size) {
printf("Client exited\n");
printf("Didn't recv the complete frame, bytes %ld\n",
bytes);
exit(1);
}
else if (bytes == 0) {
break;
}
rc = gettimeofday(&after, NULL);
if (rc == -1) {
perror("gettimeofday failed");
exit(1);
}
cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
if (prev_frame_ts > 0) {
int64_t d_variation = 0;
d_variation = (int64_t)((cur_recv - prev_recv) -
(frame_ts - prev_frame_ts));
if (d_variation > 0) {
if (min_variation == 0)
min_variation = d_variation;
else
min_variation = ((min_variation <= d_variation) ?
min_variation : d_variation);
max_variation = ((max_variation >= d_variation) ?
max_variation : d_variation);
avg_variation += d_variation;
} else {
ignore_count++;
}
}
prev_recv = cur_recv;
prev_frame_ts = frame_ts;
++i;
usecs = time_diff(&before, &after);
DiffsBuf[i] = usecs;
printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
}
if (i != ignore_count)
avg_variation = avg_variation / (i - ignore_count);
else
avg_variation = 0;
printf("<LOG> : Received frames: %u\n", i);
printf("<LOG> : Ignored frames: %u\n", ignore_count);
printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
ShowStastics(DiffsBuf, num_frames);
}
void
tcpClient(int num_frames, int frame_size,
const char *buf, struct timespec sleep_time){
int rc = 0, i = 0;
ssize_t bytes;
printf("<LOG> : TCP Client\n");
so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (so <= 0) {
perror("creating socket failed");
exit(1);
}
srv_addr.sin_port = htons(srv_port);
srv_addr.sin_len = sizeof(srv_addr);
srv_addr.sin_family = AF_INET;
rc = connect(so, (const struct sockaddr *)&srv_addr,
sizeof(srv_addr));
if (rc != 0) {
perror("connect failed");
exit(1);
}
if (tc > 0) {
rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
sizeof(tc));
if (rc == -1) {
perror("failed to set traffic class");
exit(1);
}
}
for (i = 0; i < num_frames; ++i) {
struct timeval fts;
uint64_t frame_ts;
rc = gettimeofday(&fts, NULL);
if (rc == -1) {
perror("faile to get time of day");
exit(1);
}
frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
bytes = send(so, buf, frame_size, 0);
if (bytes == -1) {
perror("send failed \n");
exit(1);
}
if (bytes != frame_size) {
printf("failed to send all bytes, sent %ld\n", bytes);
exit (1);
}
rc = nanosleep(&sleep_time, NULL);
if (rc == -1) {
perror("sleep failed");
exit(1);
}
printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
}
}
void
udpClient(int num_frames, int frame_size,
const char *buf, struct timespec sleep_time){
int rc = 0, i = 0;
ssize_t bytes;
printf("<LOG> : UDP Client\n");
so = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (so <= 0) {
perror("creating socket failed");
exit(1);
}
srv_addr.sin_port = htons(srv_port);
srv_addr.sin_len = sizeof(srv_addr);
srv_addr.sin_family = AF_INET;
if (tc > 0) {
rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
sizeof(tc));
if (rc == -1) {
perror("failed to set traffic class");
exit(1);
}
}
for (i = 0; i < num_frames; ++i) {
struct timeval fts;
uint64_t frame_ts;
rc = gettimeofday(&fts, NULL);
if (rc == -1) {
perror("faile to get time of day");
exit(1);
}
frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
bytes = sendto(so, buf, frame_size, 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if (bytes == -1) {
perror("send failed \n");
exit(1);
}
if (bytes != frame_size) {
printf("failed to send all bytes, sent %ld\n", bytes);
exit (1);
}
rc = nanosleep(&sleep_time, NULL);
if (rc == -1) {
perror("sleep failed");
exit(1);
}
printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
}
}