diff options
author | 2021-05-09 14:20:58 -0400 | |
---|---|---|
committer | 2021-05-09 14:20:58 -0400 | |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /network_cmds/frame_delay | |
download | apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip |
Import macOS userland
adv_cmds-176
basic_cmds-55
bootstrap_cmds-116.100.1
developer_cmds-66
diskdev_cmds-667.40.1
doc_cmds-53.60.1
file_cmds-321.40.3
mail_cmds-35
misc_cmds-34
network_cmds-606.40.1
patch_cmds-17
remote_cmds-63
shell_cmds-216.60.1
system_cmds-880.60.2
text_cmds-106
Diffstat (limited to 'network_cmds/frame_delay')
-rw-r--r-- | network_cmds/frame_delay/frame_delay.8 | 45 | ||||
-rw-r--r-- | network_cmds/frame_delay/frame_delay.c | 595 |
2 files changed, 640 insertions, 0 deletions
diff --git a/network_cmds/frame_delay/frame_delay.8 b/network_cmds/frame_delay/frame_delay.8 new file mode 100644 index 0000000..0f454d5 --- /dev/null +++ b/network_cmds/frame_delay/frame_delay.8 @@ -0,0 +1,45 @@ +.Dd October 12, 2015 +.Dt FRAME_DELAY 8 +.Os Darwin +.Sh NAME +.Nm frame_delay +.Nd Utility to measure TCP/UDP frame delay + +.Sh DESCRIPTION +.Pp +The +.Nm +utility is designed to measure the effect of latency on +delivery of evenly spaced TCP/UDP frames. This can be latency induced +due to buffering or protocol stack or network drivers. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl m +Server/Client mode. Should be "server" or "client". +.It Fl t +TCP/UDP frame. Should be either "tcp" or "udp". +.It Fl i +(Client Only) Server ip address. +.It Fl p +Port number. +.It Fl n +Number of frames. +.It Fl f +Frame size. +.It Fl d +(Client only) Delay traffic class. Pick one from {BK_SYS, BK, BE, RD, QAM, AV, RV, VI, VO, CTL}. +.El + +.Sh EXAMPLES +.Pp +Setup TCP server: +.Dl "frame_delay -m server -t tcp -p 10010 -n 10 -f 1000" +.Pp +Setup corresponding TCP client: +.Dl "frame_delay -m client -t tcp -i 127.0.0.1 -p 10010 -n 10 -f 1000 -d 2000 -k RD" + +.Sh AUTHORS +.An Padma Bhooma , +.An Kang Sun , +.An Vincent Lubet .
\ No newline at end of file diff --git a/network_cmds/frame_delay/frame_delay.c b/network_cmds/frame_delay/frame_delay.c new file mode 100644 index 0000000..37a58b7 --- /dev/null +++ b/network_cmds/frame_delay/frame_delay.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2009-2015 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +/* + * Usage for frame_delay + * + * Server + * ./frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size> + * + * 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> + */ + +/* + * TODO list : + * 1. UDP fragmentation and reassembly + */ + +#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> + +/* Server Static variable */ +static int so, srv_so; +static int srv_port = 0; +static struct sockaddr_in laddr, dst_addr; +/* Client Static variable */ +static struct sockaddr_in srv_addr; +static uint32_t tc = 0; +/* Usage */ +void ErrorUsage(void); +/* str2svc */ +uint32_t str2svc(const char *str); +/* Show Stastics */ +void ShowStastics(int64_t *DiffsBuf, int num_frames); +/* Returns difference between two timevals in microseconds */ +int64_t time_diff(struct timeval *b, struct timeval *a); +/* tcp server */ +void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf); +/* udp server */ +void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf); +/* tcp server */ +void tcpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time); +/* udp server */ +void udpClient(int num_frames, int frame_size, + const char *buf, struct timespec sleep_time); + +/* Main function */ +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(); + } + } + } + /* General check for both server and client */ + if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) { + ErrorUsage(); + } + if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) { + ErrorUsage(); + } + /* Allocate memory for buf */ + buf = calloc(1, frame_size); + if (buf == NULL) { + printf("malloc failed\n"); + exit(1); + } + if ( strcmp(mode, "server") == 0 ) { + /* Server */ + 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 */ + tcpServer(frame_size, num_frames, buf, DiffsBuf); + } else { + /* updServer */ + 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(); + } + /* Client */ + 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); + /* Resolving sleep time bug : delay_ms should just be calculated once */ + 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) { + /* Call TCP client */ + tcpClient(num_frames, frame_size, buf, sleep_time); + } else { + /* Call UDP client */ + udpClient(num_frames, frame_size, buf, sleep_time); + } + } else { + ErrorUsage(); + } +} + +/* Error usage */ +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); +} + +/* str2svc */ +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); +} + +/* Show Stastics */ +void +ShowStastics(int64_t *DiffsBuf, int num_frames) { + int i = 0; + int64_t sum = 0, mean = 0; + + /* Mean */ + while(i < num_frames) + sum += DiffsBuf[i++]; + mean = sum / num_frames; + printf("<LOG> : Mean: %.2f usecs\n", sum / (double)num_frames); + /* Popular Standard Deviation */ + 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)); +} + +/* Returns difference between two timevals in microseconds */ +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); +} + +/* Server */ + +/* tcp server */ +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; + /* New change from Padama */ + 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)); + /* printf("Frame %u ts %llu d_variation %lld usecs\n", + i, frame_ts, d_variation);*/ + 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; + /* Compute the time differenc */ + 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); +} + +/* udp server */ +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; + /* New change from Padama */ + 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)); + /* printf("Frame %u ts %llu d_variation %lld usecs\n", + i, frame_ts, d_variation);*/ + 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; + /* Compute the time differenc */ + 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); +} + +/* Client */ +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; + /* Add a timestamp to the frame */ + 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; + /* Add a timestamp to the frame */ + 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)); + } +} + + |