1a951c980SBrian Tierney 2a951c980SBrian Tierney /* 3a951c980SBrian Tierney * Copyright (c) 2009, The Regents of the University of California, through 4a951c980SBrian Tierney * Lawrence Berkeley National Laboratory (subject to receipt of any required 5a951c980SBrian Tierney * approvals from the U.S. Dept. of Energy). All rights reserved. 6a951c980SBrian Tierney */ 7a951c980SBrian Tierney 8a951c980SBrian Tierney /* iperf_udp.c: UDP specific routines for iperf 9a951c980SBrian Tierney * 10a951c980SBrian Tierney * NOTE: not yet finished / working 11a951c980SBrian Tierney */ 12a951c980SBrian Tierney 13*8a0b5a5dSsethdelliott // XXX: Do we really need all these headers? 14a951c980SBrian Tierney #include <stdio.h> 15a951c980SBrian Tierney #include <stdlib.h> 16a951c980SBrian Tierney #include <string.h> 17a951c980SBrian Tierney #include <getopt.h> 18a951c980SBrian Tierney #include <errno.h> 19a951c980SBrian Tierney #include <signal.h> 20a951c980SBrian Tierney #include <unistd.h> 21a951c980SBrian Tierney #include <assert.h> 22a951c980SBrian Tierney #include <fcntl.h> 23a951c980SBrian Tierney #include <sys/socket.h> 24a951c980SBrian Tierney #include <sys/types.h> 25a951c980SBrian Tierney #include <netinet/in.h> 26a951c980SBrian Tierney #include <arpa/inet.h> 27a951c980SBrian Tierney #include <netdb.h> 28a951c980SBrian Tierney #include <pthread.h> 29a951c980SBrian Tierney #include <stdint.h> 30a951c980SBrian Tierney #include <netinet/tcp.h> 31a951c980SBrian Tierney #include <sys/time.h> 32a951c980SBrian Tierney #include <sys/resource.h> 33a951c980SBrian Tierney #include <sched.h> 34a951c980SBrian Tierney #include <signal.h> 35a951c980SBrian Tierney #include <setjmp.h> 36a951c980SBrian Tierney 37a951c980SBrian Tierney #include "iperf.h" 38a951c980SBrian Tierney #include "iperf_api.h" 39a951c980SBrian Tierney #include "iperf_udp.h" 40b60a49ddSsethdelliott #include "iperf_error.h" 41a951c980SBrian Tierney #include "timer.h" 42a951c980SBrian Tierney #include "net.h" 43a951c980SBrian Tierney #include "locale.h" 44a951c980SBrian Tierney 45a951c980SBrian Tierney 46*8a0b5a5dSsethdelliott /* iperf_udp_recv 47a951c980SBrian Tierney * 48*8a0b5a5dSsethdelliott * receives the data for UDP 49a951c980SBrian Tierney */ 50a951c980SBrian Tierney int 51a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp) 52a951c980SBrian Tierney { 538556db5dSsethdelliott int result; 54a951c980SBrian Tierney int size = sp->settings->blksize; 558556db5dSsethdelliott int sec, usec, pcount; 56a951c980SBrian Tierney double transit = 0, d = 0; 578556db5dSsethdelliott struct timeval sent_time, arrival_time; 58a951c980SBrian Tierney 59a951c980SBrian Tierney result = Nread(sp->socket, sp->buffer, size, Pudp); 60a951c980SBrian Tierney 618556db5dSsethdelliott if (result < 0) { 628556db5dSsethdelliott return (-1); 63a951c980SBrian Tierney } 64*8a0b5a5dSsethdelliott 65a951c980SBrian Tierney sp->result->bytes_received += result; 668556db5dSsethdelliott sp->result->bytes_received_this_interval += result; 678556db5dSsethdelliott 688556db5dSsethdelliott memcpy(&sec, sp->buffer, sizeof(sec)); 698556db5dSsethdelliott memcpy(&usec, sp->buffer+4, sizeof(usec)); 708556db5dSsethdelliott memcpy(&pcount, sp->buffer+8, sizeof(pcount)); 718556db5dSsethdelliott sec = ntohl(sec); 728556db5dSsethdelliott usec = ntohl(usec); 738556db5dSsethdelliott pcount = ntohl(pcount); 748556db5dSsethdelliott sent_time.tv_sec = sec; 758556db5dSsethdelliott sent_time.tv_usec = usec; 768556db5dSsethdelliott 778556db5dSsethdelliott /* Out of order packets */ 788556db5dSsethdelliott if (pcount >= sp->packet_count + 1) { 798556db5dSsethdelliott if (pcount > sp->packet_count + 1) { 808556db5dSsethdelliott sp->cnt_error += (pcount - 1) - sp->packet_count; 818556db5dSsethdelliott } 828556db5dSsethdelliott sp->packet_count = pcount; 838556db5dSsethdelliott } else { 848556db5dSsethdelliott sp->outoforder_packets++; 858556db5dSsethdelliott printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket); 868556db5dSsethdelliott } 87a951c980SBrian Tierney 88a951c980SBrian Tierney /* jitter measurement */ 89b60a49ddSsethdelliott gettimeofday(&arrival_time, NULL); 90b60a49ddSsethdelliott 918556db5dSsethdelliott transit = timeval_diff(&sent_time, &arrival_time); 92a951c980SBrian Tierney d = transit - sp->prev_transit; 93a951c980SBrian Tierney if (d < 0) 94a951c980SBrian Tierney d = -d; 95a951c980SBrian Tierney sp->prev_transit = transit; 968556db5dSsethdelliott // XXX: This is NOT the way to calculate jitter 978556db5dSsethdelliott // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] 98a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 99a951c980SBrian Tierney 100*8a0b5a5dSsethdelliott return (result); 101a951c980SBrian Tierney } 102a951c980SBrian Tierney 103a951c980SBrian Tierney 104*8a0b5a5dSsethdelliott /* iperf_udp_send 105*8a0b5a5dSsethdelliott * 106*8a0b5a5dSsethdelliott * sends the data for UDP 107*8a0b5a5dSsethdelliott */ 108a951c980SBrian Tierney int 109a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp) 110a951c980SBrian Tierney { 1118556db5dSsethdelliott ssize_t result = 0; 112a951c980SBrian Tierney int64_t dtargus; 113a951c980SBrian Tierney int64_t adjustus = 0; 1148556db5dSsethdelliott uint64_t sec, usec, pcount; 1158556db5dSsethdelliott int size = sp->settings->blksize; 1168556db5dSsethdelliott struct timeval before, after; 117a951c980SBrian Tierney 118aa89cda2Ssethdelliott if (timer_expired(sp->send_timer)) { 119a951c980SBrian Tierney 120a951c980SBrian Tierney dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; 121a951c980SBrian Tierney dtargus /= sp->settings->rate; 122a951c980SBrian Tierney 123a951c980SBrian Tierney assert(dtargus != 0); 124aa89cda2Ssethdelliott 125b60a49ddSsethdelliott gettimeofday(&before, 0); 126b60a49ddSsethdelliott 1278556db5dSsethdelliott ++sp->packet_count; 1288556db5dSsethdelliott sec = htonl(before.tv_sec); 1298556db5dSsethdelliott usec = htonl(before.tv_usec); 1308556db5dSsethdelliott pcount = htonl(sp->packet_count); 131a951c980SBrian Tierney 1328556db5dSsethdelliott memcpy(sp->buffer, &sec, sizeof(sec)); 1338556db5dSsethdelliott memcpy(sp->buffer+4, &usec, sizeof(usec)); 1348556db5dSsethdelliott memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 135a951c980SBrian Tierney 136a951c980SBrian Tierney result = Nwrite(sp->socket, sp->buffer, size, Pudp); 137a951c980SBrian Tierney 1388556db5dSsethdelliott if (result < 0) 139b60a49ddSsethdelliott return (-1); 1408556db5dSsethdelliott 1418556db5dSsethdelliott sp->result->bytes_sent += result; 1428556db5dSsethdelliott sp->result->bytes_sent_this_interval += result; 143aa89cda2Ssethdelliott 144b60a49ddSsethdelliott gettimeofday(&after, 0); 145a951c980SBrian Tierney 146a951c980SBrian Tierney adjustus = dtargus; 147a951c980SBrian Tierney adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; 148a951c980SBrian Tierney adjustus += (before.tv_usec - after.tv_usec); 149a951c980SBrian Tierney 1508556db5dSsethdelliott if (adjustus > 0) { 151a951c980SBrian Tierney dtargus = adjustus; 152a951c980SBrian Tierney } 153aa89cda2Ssethdelliott 154b60a49ddSsethdelliott if (update_timer(sp->send_timer, 0, dtargus) < 0) 155b60a49ddSsethdelliott return (-1); 156aa89cda2Ssethdelliott } 157aa89cda2Ssethdelliott 158*8a0b5a5dSsethdelliott return (result); 159a951c980SBrian Tierney } 160a951c980SBrian Tierney 161a951c980SBrian Tierney /**************************************************************************/ 162*8a0b5a5dSsethdelliott // XXX: This function is deprecated 163a951c980SBrian Tierney struct iperf_stream * 164a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp) 165a951c980SBrian Tierney { 166a951c980SBrian Tierney struct iperf_stream *sp; 167a951c980SBrian Tierney 168a951c980SBrian Tierney sp = (struct iperf_stream *) iperf_new_stream(testp); 1698556db5dSsethdelliott if (!sp) { 170a951c980SBrian Tierney return (NULL); 171a951c980SBrian Tierney } 172a951c980SBrian Tierney sp->rcv = iperf_udp_recv; 173a951c980SBrian Tierney sp->snd = iperf_udp_send; 174a951c980SBrian Tierney 175a951c980SBrian Tierney return sp; 176a951c980SBrian Tierney } 177a951c980SBrian Tierney 178a951c980SBrian Tierney /**************************************************************************/ 179a951c980SBrian Tierney 180*8a0b5a5dSsethdelliott /* iperf_udp_accept 181a951c980SBrian Tierney * 182*8a0b5a5dSsethdelliott * accepts a new UDP connection 183a951c980SBrian Tierney */ 184a951c980SBrian Tierney int 185a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test) 186a951c980SBrian Tierney { 187a951c980SBrian Tierney struct iperf_stream *sp; 188a951c980SBrian Tierney struct sockaddr_in sa_peer; 1898556db5dSsethdelliott int buf; 190a951c980SBrian Tierney socklen_t len; 1918556db5dSsethdelliott int sz, s; 192a951c980SBrian Tierney 193*8a0b5a5dSsethdelliott s = test->prot_listener; 194a951c980SBrian Tierney 195a951c980SBrian Tierney len = sizeof sa_peer; 196*8a0b5a5dSsethdelliott if ((sz = recvfrom(test->prot_listener, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { 197b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 1988556db5dSsethdelliott return (-1); 1998556db5dSsethdelliott } 200a951c980SBrian Tierney 2018556db5dSsethdelliott if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { 202b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 203b60a49ddSsethdelliott return (-1); 204a951c980SBrian Tierney } 205*8a0b5a5dSsethdelliott /* 206a951c980SBrian Tierney sp = test->new_stream(test); 2078556db5dSsethdelliott if (!sp) 2088556db5dSsethdelliott return (-1); 2098556db5dSsethdelliott sp->socket = s; 210b60a49ddSsethdelliott if (iperf_init_stream(sp, test) < 0) 211b60a49ddSsethdelliott return (-1); 212a951c980SBrian Tierney iperf_add_stream(test, sp); 2138556db5dSsethdelliott FD_SET(s, &test->read_set); 2148556db5dSsethdelliott FD_SET(s, &test->write_set); 2158556db5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 216*8a0b5a5dSsethdelliott */ 217a951c980SBrian Tierney 218*8a0b5a5dSsethdelliott test->prot_listener = netannounce(Pudp, NULL, test->server_port); 219*8a0b5a5dSsethdelliott if (test->prot_listener < 0) { 220*8a0b5a5dSsethdelliott i_errno = IESTREAMLISTEN; 221b60a49ddSsethdelliott return (-1); 222b60a49ddSsethdelliott } 223a951c980SBrian Tierney 224*8a0b5a5dSsethdelliott FD_SET(test->prot_listener, &test->read_set); 225*8a0b5a5dSsethdelliott test->max_fd = (test->max_fd < test->prot_listener) ? test->prot_listener : test->max_fd; 226a951c980SBrian Tierney 2278556db5dSsethdelliott /* Let the client know we're ready "accept" another UDP "stream" */ 228*8a0b5a5dSsethdelliott if (write(s, &buf, sizeof(buf)) < 0) { 229b60a49ddSsethdelliott i_errno = IESTREAMWRITE; 230b60a49ddSsethdelliott return (-1); 231a951c980SBrian Tierney } 232a951c980SBrian Tierney 233*8a0b5a5dSsethdelliott return (s); 234*8a0b5a5dSsethdelliott } 235*8a0b5a5dSsethdelliott 236*8a0b5a5dSsethdelliott 237*8a0b5a5dSsethdelliott /* iperf_udp_listen 238*8a0b5a5dSsethdelliott * 239*8a0b5a5dSsethdelliott * start up a listener for UDP stream connections 240*8a0b5a5dSsethdelliott */ 241*8a0b5a5dSsethdelliott int 242*8a0b5a5dSsethdelliott iperf_udp_listen(struct iperf_test *test) 243*8a0b5a5dSsethdelliott { 244*8a0b5a5dSsethdelliott int s; 245*8a0b5a5dSsethdelliott 246*8a0b5a5dSsethdelliott if ((s = netannounce(Pudp, NULL, test->server_port)) < 0) { 247*8a0b5a5dSsethdelliott i_errno = IESTREAMLISTEN; 248*8a0b5a5dSsethdelliott return (-1); 249*8a0b5a5dSsethdelliott } 250*8a0b5a5dSsethdelliott 251*8a0b5a5dSsethdelliott return (s); 252*8a0b5a5dSsethdelliott } 253*8a0b5a5dSsethdelliott 254*8a0b5a5dSsethdelliott 255*8a0b5a5dSsethdelliott /* iperf_udp_connect 256*8a0b5a5dSsethdelliott * 257*8a0b5a5dSsethdelliott * connect to a TCP stream listener 258*8a0b5a5dSsethdelliott */ 259*8a0b5a5dSsethdelliott int 260*8a0b5a5dSsethdelliott iperf_udp_connect(struct iperf_test *test) 261*8a0b5a5dSsethdelliott { 262*8a0b5a5dSsethdelliott int s, buf; 263*8a0b5a5dSsethdelliott 264*8a0b5a5dSsethdelliott if ((s = netdial(Pudp, test->server_hostname, test->server_port)) < 0) { 265*8a0b5a5dSsethdelliott i_errno = IESTREAMCONNECT; 266*8a0b5a5dSsethdelliott return (-1); 267*8a0b5a5dSsethdelliott } 268*8a0b5a5dSsethdelliott 269*8a0b5a5dSsethdelliott /* Write to the UDP stream to give the server this stream's credentials */ 270*8a0b5a5dSsethdelliott if (write(s, &buf, sizeof(buf)) < 0) { 271*8a0b5a5dSsethdelliott // XXX: Should this be changed to IESTREAMCONNECT? 272*8a0b5a5dSsethdelliott i_errno = IESTREAMWRITE; 273*8a0b5a5dSsethdelliott return (-1); 274*8a0b5a5dSsethdelliott } 275*8a0b5a5dSsethdelliott /* Wait until the server confirms the client UDP write */ 276*8a0b5a5dSsethdelliott // XXX: Should this read be TCP instead? 277*8a0b5a5dSsethdelliott if (read(s, &buf, sizeof(buf)) < 0) { 278*8a0b5a5dSsethdelliott i_errno = IESTREAMREAD; 279*8a0b5a5dSsethdelliott return (-1); 280*8a0b5a5dSsethdelliott } 281*8a0b5a5dSsethdelliott 282*8a0b5a5dSsethdelliott return (s); 283*8a0b5a5dSsethdelliott } 284*8a0b5a5dSsethdelliott 285*8a0b5a5dSsethdelliott 286*8a0b5a5dSsethdelliott /* iperf_udp_init 287*8a0b5a5dSsethdelliott * 288*8a0b5a5dSsethdelliott * initializer for UDP streams in TEST_START 289*8a0b5a5dSsethdelliott */ 290*8a0b5a5dSsethdelliott int 291*8a0b5a5dSsethdelliott iperf_udp_init(struct iperf_test *test) 292*8a0b5a5dSsethdelliott { 293*8a0b5a5dSsethdelliott int64_t dtargus; 294*8a0b5a5dSsethdelliott struct iperf_stream *sp; 295*8a0b5a5dSsethdelliott 296*8a0b5a5dSsethdelliott /* Calculate the send delay needed to hit target bandwidth (-b) */ 297*8a0b5a5dSsethdelliott dtargus = (int64_t) test->default_settings->blksize * SEC_TO_US * 8; 298*8a0b5a5dSsethdelliott dtargus /= test->default_settings->rate; 299*8a0b5a5dSsethdelliott 300*8a0b5a5dSsethdelliott assert(dtargus != 0); 301*8a0b5a5dSsethdelliott 302*8a0b5a5dSsethdelliott for (sp = test->streams; sp; sp = sp->next) { 303*8a0b5a5dSsethdelliott sp->send_timer = new_timer(dtargus / SEC_TO_US, dtargus % SEC_TO_US); 304*8a0b5a5dSsethdelliott if (sp->send_timer == NULL) 305*8a0b5a5dSsethdelliott return (-1); 306*8a0b5a5dSsethdelliott } 307a951c980SBrian Tierney 308b60a49ddSsethdelliott return (0); 309a951c980SBrian Tierney } 310