]> git.saurik.com Git - apple/network_cmds.git/blame - frame_delay/frame_delay.c
network_cmds-596.tar.gz
[apple/network_cmds.git] / frame_delay / frame_delay.c
CommitLineData
26c66ce9
A
1/*
2 * Copyright (c) 2009-2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * Usage for frame_delay
31 *
32 * Server
33 * ./frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>
34 *
35 * Client
36 * ./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>
37 */
38
39/*
40 * TODO list :
41 * 1. UDP fragmentation and reassembly
42 */
43
44#include <stdio.h>
45#include <stdlib.h>
46#include <math.h>
47#include <string.h>
48#include <unistd.h>
49#include <fcntl.h>
50#include <sys/types.h>
51#include <sys/socket.h>
52#include <netinet/in.h>
53#include <arpa/inet.h>
54#include <sys/time.h>
55
56/* Server Static variable */
57static int so, srv_so;
58static int srv_port = 0;
59static struct sockaddr_in laddr, dst_addr;
60/* Client Static variable */
61static struct sockaddr_in srv_addr;
62static uint32_t tc = 0;
63/* Usage */
64void ErrorUsage(void);
65/* str2svc */
66uint32_t str2svc(const char *str);
67/* Show Stastics */
68void ShowStastics(int64_t *DiffsBuf, int num_frames);
69/* Returns difference between two timevals in microseconds */
70int64_t time_diff(struct timeval *b, struct timeval *a);
71/* tcp server */
72void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
73/* udp server */
74void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
75/* tcp server */
76void tcpClient(int num_frames, int frame_size,
77 const char *buf, struct timespec sleep_time);
78/* udp server */
79void udpClient(int num_frames, int frame_size,
80 const char *buf, struct timespec sleep_time);
81
82/* Main function */
83int
84main(int argc, char *argv[])
85{
86 int num_frames = 0, frame_size = 0, delay_ms = 0, rc = 0;
87 char *buf = NULL, ch, *type = NULL, *mode = NULL, *ip_addr = NULL;
88 int64_t *DiffsBuf;
89 struct timespec sleep_time;
90
91 while ((ch = getopt(argc, argv, "m:p:f:n:t:d:i:k:")) != -1) {
92 switch (ch) {
93 case 'm': {
94 mode = optarg;
95 break;
96 }
97 case 'p': {
98 srv_port = atoi(optarg);
99 break;
100 }
101 case 'f' : {
102 frame_size = atoi(optarg);
103 break;
104 }
105 case 'n' : {
106 num_frames = atoi(optarg);
107 break;
108 }
109 case 'i': {
110 ip_addr = optarg;
111 bzero(&srv_addr, sizeof(srv_addr));
112 rc = inet_aton(optarg, &srv_addr.sin_addr);
113 if (rc == 0) {
114 perror("inet_ntoa failed");
115 exit(1);
116 }
117 }
118 case 'd': {
119 delay_ms = atoi(optarg);
120 break;
121 }
122 case 't' : {
123 type = optarg;
124 break;
125 }
126 case 'k': {
127 tc = str2svc(optarg);
128 break;
129 }
130 default: {
131 printf("Invalid option: %c\n", ch);
132 ErrorUsage();
133 }
134 }
135 }
136 /* General check for both server and client */
137 if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) {
138 ErrorUsage();
139 }
140 if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) {
141 ErrorUsage();
142 }
143 /* Allocate memory for buf */
144 buf = calloc(1, frame_size);
145 if (buf == NULL) {
146 printf("malloc failed\n");
147 exit(1);
148 }
149 if ( strcmp(mode, "server") == 0 ) {
150 /* Server */
151 printf("<LOG> : Start %s server on port %d with expected frame size of %d\n",
152 type, srv_port, frame_size);
153 DiffsBuf = (int64_t *)calloc(num_frames, sizeof(int64_t));
154 if (DiffsBuf == NULL) {
155 printf("malloc failed\n");
156 exit(1);
157 }
158 if( strcmp(type, "tcp") == 0) {
159 /* tcpServer */
160 tcpServer(frame_size, num_frames, buf, DiffsBuf);
161 } else {
162 /* updServer */
163 udpServer(frame_size, num_frames, buf, DiffsBuf);
164 }
165 }
166 else if ( strcmp(mode, "client") == 0 ){
167 if ( !ip_addr || (tc > 0 && (tc < SO_TC_BK_SYS || tc > SO_TC_CTL)) ){
168 ErrorUsage();
169 }
170 /* Client */
171 printf("<LOG> : Start sending %d %s frames to %s:%d with a frame size of %d\n",
172 num_frames, type, ip_addr, srv_port, frame_size);
173 /* Resolving sleep time bug : delay_ms should just be calculated once */
174 bzero(&sleep_time, sizeof(sleep_time));
175 while (delay_ms >= 1000) {
176 sleep_time.tv_sec++;
177 delay_ms -= 1000;
178 }
179 sleep_time.tv_nsec = delay_ms * 1000 * 1000;
180 if( strcmp(type, "tcp") == 0) {
181 /* Call TCP client */
182 tcpClient(num_frames, frame_size, buf, sleep_time);
183 } else {
184 /* Call UDP client */
185 udpClient(num_frames, frame_size, buf, sleep_time);
186 }
187 } else {
188 ErrorUsage();
189 }
190}
191
192/* Error usage */
193void
194ErrorUsage(void) {
195 printf("Correct Usage");
196 printf("Server : frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>\n");
197 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");
198 exit(1);
199}
200
201/* str2svc */
202uint32_t
203str2svc(const char *str)
204{
205 uint32_t svc;
206 char *endptr;
207
208 if (str == NULL || *str == '\0')
209 svc = UINT32_MAX;
210 else if (strcasecmp(str, "BK_SYS") == 0)
211 return SO_TC_BK_SYS;
212 else if (strcasecmp(str, "BK") == 0)
213 return SO_TC_BK;
214 else if (strcasecmp(str, "BE") == 0)
215 return SO_TC_BE;
216 else if (strcasecmp(str, "RD") == 0)
217 return SO_TC_RD;
218 else if (strcasecmp(str, "OAM") == 0)
219 return SO_TC_OAM;
220 else if (strcasecmp(str, "AV") == 0)
221 return SO_TC_AV;
222 else if (strcasecmp(str, "RV") == 0)
223 return SO_TC_RV;
224 else if (strcasecmp(str, "VI") == 0)
225 return SO_TC_VI;
226 else if (strcasecmp(str, "VO") == 0)
227 return SO_TC_VO;
228 else if (strcasecmp(str, "CTL") == 0)
229 return SO_TC_CTL;
230 else {
231 svc = (uint32_t)strtoul(str, &endptr, 0);
232 if (*endptr != '\0')
233 svc = UINT32_MAX;
234 }
235 return (svc);
236}
237
238/* Show Stastics */
239void
240ShowStastics(int64_t *DiffsBuf, int num_frames) {
241 int i = 0;
242 int64_t sum = 0, mean = 0;
243
244 /* Mean */
245 while(i < num_frames)
246 sum += DiffsBuf[i++];
247 mean = sum / num_frames;
248 printf("<LOG> : Mean: %.2f usecs\n", sum / (double)num_frames);
249 /* Popular Standard Deviation */
250 i = 0;
251 sum = 0;
252 while(i < num_frames) {
253 sum += (DiffsBuf[i]-mean)*(DiffsBuf[i]-mean);
254 i++;
255 }
256 printf("<LOG> : Popular Standard Deviation: %.2f usecs\n",
257 sqrt(sum/(double)num_frames));
258}
259
260/* Returns difference between two timevals in microseconds */
261int64_t
262time_diff(struct timeval *b, struct timeval *a)
263{
264 int64_t usecs;
265 usecs = (a->tv_sec - b->tv_sec) * 1000 * 1000;
266 usecs += (int64_t)(a->tv_usec - b->tv_usec);
267 return(usecs);
268}
269
270/* Server */
271
272/* tcp server */
273void
274tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
275 int rc = 0, i = 0, ignore_count = 0;
276 uint32_t dst_len = 0;
277 struct timeval before, after;
278 ssize_t bytes;
279 int64_t usecs;
280 /* New change from Padama */
281 uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
282 uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
283
284 printf("<LOG> : TCP Server\n");
285 so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
286 if (so == -1) {
287 perror("failed to create socket");
288 exit(1);
289 }
290 bzero(&laddr, sizeof(laddr));
291 laddr.sin_family = AF_INET;
292 laddr.sin_port = htons(srv_port);
293 rc = bind(so, (const struct sockaddr *)&laddr, sizeof(laddr));
294 if (rc != 0) {
295 perror("failed to bind");
296 exit(1);
297 }
298 rc = listen(so, 10);
299 if (rc != 0) {
300 perror("failed to listen");
301 exit(1);
302 }
303 srv_so = accept(so, (struct sockaddr *)&dst_addr, &dst_len);
304 if (srv_so == -1) {
305 perror("failed to accept");
306 exit(1);
307 }
308 while (1) {
309 if ( i == num_frames ) {
310 printf("<LOG> : Completed\n");
311 break;
312 }
313 printf("<LOG> : Waiting for receiving\n");
314 bzero(&before, sizeof(before));
315 bzero(&after, sizeof(after));
316 rc = gettimeofday(&before, NULL);
317 if (rc == -1) {
318 perror("gettimeofday failed");
319 exit(1);
320 }
321 bytes = recv(srv_so, buf, frame_size, MSG_WAITALL);
322 if (bytes == -1) {
323 perror("recv failed");
324 exit(1);
325 }
326 else if (bytes > 0 && bytes != frame_size) {
327 printf("Client exited\n");
328 printf("Didn't recv the complete frame, bytes %ld\n",
329 bytes);
330 exit(1);
331 }
332 else if (bytes == 0) {
333 break;
334 }
335 rc = gettimeofday(&after, NULL);
336 if (rc == -1) {
337 perror("gettimeofday failed");
338 exit(1);
339 }
340 cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
341 memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
342 if (prev_frame_ts > 0) {
343 int64_t d_variation = 0;
344 d_variation = (int64_t)((cur_recv - prev_recv) -
345 (frame_ts - prev_frame_ts));
346 /* printf("Frame %u ts %llu d_variation %lld usecs\n",
347 i, frame_ts, d_variation);*/
348 if (d_variation > 0) {
349 if (min_variation == 0)
350 min_variation = d_variation;
351 else
352 min_variation = ((min_variation <= d_variation) ?
353 min_variation : d_variation);
354 max_variation = ((max_variation >= d_variation) ?
355 max_variation : d_variation);
356 avg_variation += d_variation;
357 } else {
358 ignore_count++;
359 }
360 }
361 prev_recv = cur_recv;
362 prev_frame_ts = frame_ts;
363 ++i;
364 /* Compute the time differenc */
365 usecs = time_diff(&before, &after);
366 DiffsBuf[i] = usecs;
367 printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
368 }
369 if (i != ignore_count)
370 avg_variation = avg_variation / (i - ignore_count);
371 else
372 avg_variation = 0;
373
374 printf("<LOG> : Received frames: %u\n", i);
375 printf("<LOG> : Ignored frames: %u\n", ignore_count);
376 printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
377 printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
378 printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
379 ShowStastics(DiffsBuf, num_frames);
380}
381
382/* udp server */
383void
384udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
385 int rc = 0, i = 0, ignore_count = 0;
386 uint32_t dst_len = 0;
387 ssize_t bytes;
388 struct timeval before, after;
389 int64_t usecs;
390 /* New change from Padama */
391 uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
392 uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
393
394 printf("<LOG> : UDP Server\n");
395 so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
396 if (so == -1) {
397 perror("failed to create socket");
398 exit(1);
399 }
400 bzero(&laddr,sizeof(laddr));
401 laddr.sin_family = AF_INET;
402 laddr.sin_addr.s_addr=htonl(INADDR_ANY);
403 laddr.sin_port=htons(srv_port);
404 rc = bind(so, (struct sockaddr *)&laddr,sizeof(laddr));
405 if (rc != 0) {
406 perror("failed to bind");
407 exit(1);
408 }
409 while (1) {
410 if ( i == num_frames ) {
411 printf("<LOG> : Completed\n");
412 break;
413 }
414 printf("<LOG> : Waiting for receiving\n");
415 bzero(&before, sizeof(before));
416 bzero(&after, sizeof(after));
417 rc = gettimeofday(&before, NULL);
418 if (rc == -1) {
419 perror("gettimeofday failed");
420 exit(1);
421 }
422 bytes = recvfrom(so, buf, frame_size, 0, (struct sockaddr *)&dst_addr, &dst_len);
423 if (bytes == -1) {
424 perror("recv failed");
425 exit(1);
426 }
427 else if (bytes > 0 && bytes != frame_size) {
428 printf("Client exited\n");
429 printf("Didn't recv the complete frame, bytes %ld\n",
430 bytes);
431 exit(1);
432 }
433 else if (bytes == 0) {
434 break;
435 }
436 rc = gettimeofday(&after, NULL);
437 if (rc == -1) {
438 perror("gettimeofday failed");
439 exit(1);
440 }
441 cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
442 memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
443 if (prev_frame_ts > 0) {
444 int64_t d_variation = 0;
445
446 d_variation = (int64_t)((cur_recv - prev_recv) -
447 (frame_ts - prev_frame_ts));
448 /* printf("Frame %u ts %llu d_variation %lld usecs\n",
449 i, frame_ts, d_variation);*/
450 if (d_variation > 0) {
451 if (min_variation == 0)
452 min_variation = d_variation;
453 else
454 min_variation = ((min_variation <= d_variation) ?
455 min_variation : d_variation);
456 max_variation = ((max_variation >= d_variation) ?
457 max_variation : d_variation);
458 avg_variation += d_variation;
459 } else {
460 ignore_count++;
461 }
462 }
463 prev_recv = cur_recv;
464 prev_frame_ts = frame_ts;
465 ++i;
466 /* Compute the time differenc */
467 usecs = time_diff(&before, &after);
468 DiffsBuf[i] = usecs;
469 printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
470 }
471 if (i != ignore_count)
472 avg_variation = avg_variation / (i - ignore_count);
473 else
474 avg_variation = 0;
475 printf("<LOG> : Received frames: %u\n", i);
476 printf("<LOG> : Ignored frames: %u\n", ignore_count);
477 printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
478 printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
479 printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
480 ShowStastics(DiffsBuf, num_frames);
481}
482
483/* Client */
484void
485tcpClient(int num_frames, int frame_size,
486 const char *buf, struct timespec sleep_time){
487 int rc = 0, i = 0;
488 ssize_t bytes;
489
490 printf("<LOG> : TCP Client\n");
491 so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
492
493 if (so <= 0) {
494 perror("creating socket failed");
495 exit(1);
496 }
497 srv_addr.sin_port = htons(srv_port);
498 srv_addr.sin_len = sizeof(srv_addr);
499 srv_addr.sin_family = AF_INET;
500 rc = connect(so, (const struct sockaddr *)&srv_addr,
501 sizeof(srv_addr));
502 if (rc != 0) {
503 perror("connect failed");
504 exit(1);
505 }
506 if (tc > 0) {
507 rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
508 sizeof(tc));
509 if (rc == -1) {
510 perror("failed to set traffic class");
511 exit(1);
512 }
513 }
514 for (i = 0; i < num_frames; ++i) {
515 struct timeval fts;
516 uint64_t frame_ts;
517 /* Add a timestamp to the frame */
518 rc = gettimeofday(&fts, NULL);
519 if (rc == -1) {
520 perror("faile to get time of day");
521 exit(1);
522 }
523 frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
524 memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
525 bytes = send(so, buf, frame_size, 0);
526 if (bytes == -1) {
527 perror("send failed \n");
528 exit(1);
529 }
530 if (bytes != frame_size) {
531 printf("failed to send all bytes, sent %ld\n", bytes);
532 exit (1);
533 }
534 rc = nanosleep(&sleep_time, NULL);
535 if (rc == -1) {
536 perror("sleep failed");
537 exit(1);
538 }
539 printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
540 }
541}
542
543void
544udpClient(int num_frames, int frame_size,
545 const char *buf, struct timespec sleep_time){
546 int rc = 0, i = 0;
547 ssize_t bytes;
548
549 printf("<LOG> : UDP Client\n");
550 so = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
551 if (so <= 0) {
552 perror("creating socket failed");
553 exit(1);
554 }
555 srv_addr.sin_port = htons(srv_port);
556 srv_addr.sin_len = sizeof(srv_addr);
557 srv_addr.sin_family = AF_INET;
558 if (tc > 0) {
559 rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
560 sizeof(tc));
561 if (rc == -1) {
562 perror("failed to set traffic class");
563 exit(1);
564 }
565 }
566 for (i = 0; i < num_frames; ++i) {
567 struct timeval fts;
568 uint64_t frame_ts;
569 /* Add a timestamp to the frame */
570 rc = gettimeofday(&fts, NULL);
571 if (rc == -1) {
572 perror("faile to get time of day");
573 exit(1);
574 }
575 frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
576 memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
577 bytes = sendto(so, buf, frame_size, 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
578 if (bytes == -1) {
579 perror("send failed \n");
580 exit(1);
581 }
582 if (bytes != frame_size) {
583 printf("failed to send all bytes, sent %ld\n", bytes);
584 exit (1);
585 }
586 rc = nanosleep(&sleep_time, NULL);
587 if (rc == -1) {
588 perror("sleep failed");
589 exit(1);
590 }
591 printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
592 }
593}
594
595