1/* 2 * Copyright (c) 2014, University of Washington. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich. 8 * Attn: Systems Group. 9 */ 10 11#include <stdio.h> 12#include <unistd.h> 13#include <stdlib.h> 14#include <string.h> 15#include <netdb.h> 16#include <inttypes.h> 17#include <sys/types.h> 18#include <sys/socket.h> 19#include <netinet/in.h> 20#include <arpa/inet.h> 21#include <sys/time.h> 22#include <strings.h> 23#include <assert.h> 24#include <pthread.h> 25 26#define timersub(a, b, result) \ 27 do { \ 28 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ 29 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ 30 if ((result)->tv_usec < 0) { \ 31 --(result)->tv_sec; \ 32 (result)->tv_usec += 1000000; \ 33 } \ 34 } while (0) 35 36#define BUFSIZE 1024 37#define MAX_ROUNDS 10000000 38 39#ifndef MIN 40#define MIN(a,b) ((a) < (b) ? (a) : (b)) 41#endif 42#ifndef MAX 43#define MAX(a,b) ((a) > (b) ? (a) : (b)) 44#endif 45 46static struct timeval tvs[MAX_ROUNDS], tst[MAX_ROUNDS]; 47 48/* 49 * error - wrapper for perror 50 */ 51static void error(char *msg) { 52 perror(msg); 53 exit(1); 54} 55 56static int sockfd; /* socket */ 57static struct sockaddr_in clientaddr; /* client addr */ 58static socklen_t clientlen; /* byte size of client's address */ 59static int delay = 0; 60static size_t rounds, packets = 0; 61 62static void *receiver_func(void *unused) 63{ 64 char buf[BUFSIZE]; /* message buf */ 65 66 for(int i = 0; i < rounds; i++) { 67 /* 68 * recvfrom: receive a UDP datagram from a client 69 */ 70 int n = recvfrom(sockfd, buf, BUFSIZE, 0, NULL, NULL); 71 if (n < 0) 72 error("ERROR in recvfrom"); 73 74 /* printf("server received %d bytes\n", n); */ 75 assert(n == BUFSIZE); 76 77 /* uint64_t *cnt = (uint64_t *)buf; */ 78 struct timeval *tstamp = (struct timeval *)&buf[8]; 79 gettimeofday(&tst[i], NULL); 80 timersub(&tst[i], tstamp, &tvs[i]); 81 packets++; 82 /* if(*cnt != i) { */ 83 /* printf("Packets reordered? %d != %" PRIu64 "\n", i, *cnt); */ 84 /* exit(1); */ 85 /* } */ 86 } 87 88 return NULL; 89} 90 91int main(int argc, char **argv) { 92 int portno; /* port to listen on */ 93 int optval; /* flag value for setsockopt */ 94 char buf[BUFSIZE]; /* message buf */ 95 96 /* 97 * check command line arguments 98 */ 99 if (argc < 6) { 100 fprintf(stderr, "usage: %s <port> <server IP> <delay us> <rounds> <start_val>\n", argv[0]); 101 exit(1); 102 } 103 portno = atoi(argv[1]); 104 delay = atoi(argv[3]); 105 rounds = atoi(argv[4]); 106 assert(rounds < MAX_ROUNDS); 107 size_t start = atoi(argv[5]); 108 109 /* 110 * socket: create the parent socket 111 */ 112 sockfd = socket(AF_INET, SOCK_DGRAM, 0); 113 if (sockfd < 0) 114 error("ERROR opening socket"); 115 116 /* setsockopt: Handy debugging trick that lets 117 * us rerun the server immediately after we kill it; 118 * otherwise we have to wait about 20 secs. 119 * Eliminates "ERROR on binding: Address already in use" error. 120 */ 121 optval = 1; 122 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 123 (const void *)&optval , sizeof(int)); 124 125 clientlen = sizeof(clientaddr); 126 127 bzero((char *) &clientaddr, sizeof(clientaddr)); 128 clientaddr.sin_family = AF_INET; 129 clientaddr.sin_addr.s_addr = inet_addr(argv[2]); 130 if(clientaddr.sin_addr.s_addr == INADDR_NONE) { 131 printf("Error on inet_addr()\n"); 132 exit(1); 133 } 134 clientaddr.sin_port = htons((unsigned short)portno); 135 136 pthread_t sender; 137 int ret = pthread_create(&sender, NULL, receiver_func, NULL); 138 assert(ret == 0); 139 140 uint64_t *cnt = (uint64_t *)buf; 141 struct timeval *tstamp = (struct timeval *)&buf[8]; 142 143 memset(tstamp, 0, sizeof(struct timeval)); 144 145 for(*cnt = 0; *cnt < rounds; (*cnt)++) { 146 struct timeval oldstamp, diff; 147 148 oldstamp = *tstamp; 149 150 do { 151 gettimeofday(tstamp, NULL); 152 timersub(tstamp, &oldstamp, &diff); 153 /* printf("now = %lu, oldstamp = %lu, diff = %lu, delay = %d\n", */ 154 /* tstamp->tv_sec * 1000000 + tstamp->tv_usec, */ 155 /* oldstamp.tv_sec * 1000000 + oldstamp.tv_usec, */ 156 /* diff.tv_sec * 1000000 + diff.tv_usec, delay); */ 157 } while((uint64_t)(diff.tv_sec * 1000000 + diff.tv_usec) < (uint64_t)delay); 158 159 int n = sendto(sockfd, buf, BUFSIZE, 0, 160 (struct sockaddr *) &clientaddr, clientlen); 161 if (n < 0) 162 error("ERROR in sendto"); 163 } 164 165 ret = pthread_cancel(sender); 166 assert(ret == 0); 167 168 unsigned long sum = 0, min = 99999, max = 0; 169 170 for(int i = 0; i < packets; i++) { 171 unsigned long r = tvs[i].tv_sec * 1000000 + tvs[i].tv_usec; 172 unsigned long t = tst[i].tv_sec * 1000000 + tst[i].tv_usec; 173 if(t != 0) { 174 printf("%zd %lu %lu %lu us\n", i + start, t - r, t, r); 175 sum += r; 176 min = MIN(min, r); 177 max = MAX(max, r); 178 } 179 } 180 181 printf("average %lu us, min %lu us, max %lu us\n", 182 sum / (packets - 1), min, max); 183 184 return 0; 185} 186