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 13a951c980SBrian Tierney #include <stdio.h> 14a951c980SBrian Tierney #include <stdlib.h> 15a951c980SBrian Tierney #include <string.h> 16a951c980SBrian Tierney #include <getopt.h> 17a951c980SBrian Tierney #include <errno.h> 18a951c980SBrian Tierney #include <signal.h> 19a951c980SBrian Tierney #include <unistd.h> 20a951c980SBrian Tierney #include <assert.h> 21a951c980SBrian Tierney #include <fcntl.h> 22a951c980SBrian Tierney #include <sys/socket.h> 23a951c980SBrian Tierney #include <sys/types.h> 24a951c980SBrian Tierney #include <netinet/in.h> 25a951c980SBrian Tierney #include <arpa/inet.h> 26a951c980SBrian Tierney #include <netdb.h> 27a951c980SBrian Tierney #include <pthread.h> 28a951c980SBrian Tierney #include <stdint.h> 29a951c980SBrian Tierney #include <netinet/tcp.h> 30a951c980SBrian Tierney #include <sys/time.h> 31a951c980SBrian Tierney #include <sys/resource.h> 32a951c980SBrian Tierney #include <sched.h> 33a951c980SBrian Tierney #include <signal.h> 34a951c980SBrian Tierney #include <setjmp.h> 35a951c980SBrian Tierney 36a951c980SBrian Tierney #include "iperf.h" 37a951c980SBrian Tierney #include "iperf_api.h" 38a951c980SBrian Tierney #include "iperf_udp.h" 39a951c980SBrian Tierney #include "timer.h" 40a951c980SBrian Tierney #include "net.h" 41a951c980SBrian Tierney #include "locale.h" 42a951c980SBrian Tierney 43a951c980SBrian Tierney 44a951c980SBrian Tierney /**************************************************************************/ 45a951c980SBrian Tierney 46a951c980SBrian Tierney /** 47a951c980SBrian Tierney * iperf_udp_recv -- receives the client data for UDP 48a951c980SBrian Tierney * 49a951c980SBrian Tierney *returns state of packet received 50a951c980SBrian Tierney * 51a951c980SBrian Tierney */ 52a951c980SBrian Tierney 53a951c980SBrian Tierney int 54a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp) 55a951c980SBrian Tierney { 568556db5dSsethdelliott int result; 57a951c980SBrian Tierney int size = sp->settings->blksize; 588556db5dSsethdelliott int sec, usec, pcount; 59a951c980SBrian Tierney double transit = 0, d = 0; 608556db5dSsethdelliott struct timeval sent_time, arrival_time; 61a951c980SBrian Tierney 62a951c980SBrian Tierney #ifdef USE_SEND 638556db5dSsethdelliott do { 64a951c980SBrian Tierney result = recv(sp->socket, sp->buffer, size, 0); 65a951c980SBrian Tierney } while (result == -1 && errno == EINTR); 66a951c980SBrian Tierney #else 67a951c980SBrian Tierney result = Nread(sp->socket, sp->buffer, size, Pudp); 68a951c980SBrian Tierney #endif 69a951c980SBrian Tierney 708556db5dSsethdelliott if (result < 0) { 718556db5dSsethdelliott perror("Nread udp result"); 728556db5dSsethdelliott return (-1); 73a951c980SBrian Tierney } 74a951c980SBrian Tierney sp->result->bytes_received += result; 758556db5dSsethdelliott sp->result->bytes_received_this_interval += result; 768556db5dSsethdelliott 778556db5dSsethdelliott memcpy(&sec, sp->buffer, sizeof(sec)); 788556db5dSsethdelliott memcpy(&usec, sp->buffer+4, sizeof(usec)); 798556db5dSsethdelliott memcpy(&pcount, sp->buffer+8, sizeof(pcount)); 808556db5dSsethdelliott sec = ntohl(sec); 818556db5dSsethdelliott usec = ntohl(usec); 828556db5dSsethdelliott pcount = ntohl(pcount); 838556db5dSsethdelliott sent_time.tv_sec = sec; 848556db5dSsethdelliott sent_time.tv_usec = usec; 858556db5dSsethdelliott 868556db5dSsethdelliott /* Out of order packets */ 878556db5dSsethdelliott if (pcount >= sp->packet_count + 1) { 888556db5dSsethdelliott if (pcount > sp->packet_count + 1) { 898556db5dSsethdelliott sp->cnt_error += (pcount - 1) - sp->packet_count; 908556db5dSsethdelliott } 918556db5dSsethdelliott sp->packet_count = pcount; 928556db5dSsethdelliott } else { 938556db5dSsethdelliott sp->outoforder_packets++; 948556db5dSsethdelliott printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket); 958556db5dSsethdelliott } 96a951c980SBrian Tierney 97a951c980SBrian Tierney /* jitter measurement */ 988556db5dSsethdelliott if (gettimeofday(&arrival_time, NULL) < 0) { 99a951c980SBrian Tierney perror("gettimeofday"); 100a951c980SBrian Tierney } 1018556db5dSsethdelliott transit = timeval_diff(&sent_time, &arrival_time); 102a951c980SBrian Tierney d = transit - sp->prev_transit; 103a951c980SBrian Tierney if (d < 0) 104a951c980SBrian Tierney d = -d; 105a951c980SBrian Tierney sp->prev_transit = transit; 1068556db5dSsethdelliott // XXX: This is NOT the way to calculate jitter 1078556db5dSsethdelliott // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] 108a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 109a951c980SBrian Tierney 1108556db5dSsethdelliott return result; 111a951c980SBrian Tierney } 112a951c980SBrian Tierney 113a951c980SBrian Tierney 114a951c980SBrian Tierney /**************************************************************************/ 115a951c980SBrian Tierney int 116a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp) 117a951c980SBrian Tierney { 1188556db5dSsethdelliott ssize_t result = 0; 119a951c980SBrian Tierney int64_t dtargus; 120a951c980SBrian Tierney int64_t adjustus = 0; 1218556db5dSsethdelliott uint64_t sec, usec, pcount; 1228556db5dSsethdelliott int size = sp->settings->blksize; 1238556db5dSsethdelliott struct timeval before, after; 124a951c980SBrian Tierney 125*aa89cda2Ssethdelliott if (timer_expired(sp->send_timer)) { 126a951c980SBrian Tierney 127a951c980SBrian Tierney dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; 128a951c980SBrian Tierney dtargus /= sp->settings->rate; 129a951c980SBrian Tierney 130a951c980SBrian Tierney assert(dtargus != 0); 131*aa89cda2Ssethdelliott 132a951c980SBrian Tierney if (gettimeofday(&before, 0) < 0) 133a951c980SBrian Tierney perror("gettimeofday"); 1348556db5dSsethdelliott ++sp->packet_count; 1358556db5dSsethdelliott sec = htonl(before.tv_sec); 1368556db5dSsethdelliott usec = htonl(before.tv_usec); 1378556db5dSsethdelliott pcount = htonl(sp->packet_count); 138a951c980SBrian Tierney 1398556db5dSsethdelliott memcpy(sp->buffer, &sec, sizeof(sec)); 1408556db5dSsethdelliott memcpy(sp->buffer+4, &usec, sizeof(usec)); 1418556db5dSsethdelliott memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 142a951c980SBrian Tierney 143a951c980SBrian Tierney #ifdef USE_SEND 144a951c980SBrian Tierney result = send(sp->socket, sp->buffer, size, 0); 145a951c980SBrian Tierney #else 146a951c980SBrian Tierney result = Nwrite(sp->socket, sp->buffer, size, Pudp); 147a951c980SBrian Tierney #endif 148a951c980SBrian Tierney 1498556db5dSsethdelliott if (result < 0) 1508556db5dSsethdelliott perror("Nwrite udp error"); 1518556db5dSsethdelliott 1528556db5dSsethdelliott sp->result->bytes_sent += result; 1538556db5dSsethdelliott sp->result->bytes_sent_this_interval += result; 154*aa89cda2Ssethdelliott 155a951c980SBrian Tierney if (gettimeofday(&after, 0) < 0) 156a951c980SBrian Tierney perror("gettimeofday"); 157a951c980SBrian Tierney 158a951c980SBrian Tierney adjustus = dtargus; 159a951c980SBrian Tierney adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; 160a951c980SBrian Tierney adjustus += (before.tv_usec - after.tv_usec); 161a951c980SBrian Tierney 1628556db5dSsethdelliott if (adjustus > 0) { 163a951c980SBrian Tierney dtargus = adjustus; 164a951c980SBrian Tierney } 165*aa89cda2Ssethdelliott 166a951c980SBrian Tierney update_timer(sp->send_timer, 0, dtargus); 167*aa89cda2Ssethdelliott } 168*aa89cda2Ssethdelliott 169a951c980SBrian Tierney return result; 170a951c980SBrian Tierney } 171a951c980SBrian Tierney 172a951c980SBrian Tierney /**************************************************************************/ 173a951c980SBrian Tierney struct iperf_stream * 174a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp) 175a951c980SBrian Tierney { 176a951c980SBrian Tierney struct iperf_stream *sp; 177a951c980SBrian Tierney 178a951c980SBrian Tierney sp = (struct iperf_stream *) iperf_new_stream(testp); 1798556db5dSsethdelliott if (!sp) { 180a951c980SBrian Tierney perror("malloc"); 181a951c980SBrian Tierney return (NULL); 182a951c980SBrian Tierney } 183a951c980SBrian Tierney sp->rcv = iperf_udp_recv; 184a951c980SBrian Tierney sp->snd = iperf_udp_send; 185a951c980SBrian Tierney 186a951c980SBrian Tierney return sp; 187a951c980SBrian Tierney } 188a951c980SBrian Tierney 189a951c980SBrian Tierney /**************************************************************************/ 190a951c980SBrian Tierney 191a951c980SBrian Tierney /** 192a951c980SBrian Tierney * iperf_udp_accept -- accepts a new UDP connection 193a951c980SBrian Tierney * on udp_listener_socket 194a951c980SBrian Tierney *returns 0 on success 195a951c980SBrian Tierney * 196a951c980SBrian Tierney */ 197a951c980SBrian Tierney 198a951c980SBrian Tierney 199a951c980SBrian Tierney int 200a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test) 201a951c980SBrian Tierney { 202a951c980SBrian Tierney struct iperf_stream *sp; 203a951c980SBrian Tierney struct sockaddr_in sa_peer; 2048556db5dSsethdelliott int buf; 205a951c980SBrian Tierney socklen_t len; 2068556db5dSsethdelliott int sz, s; 207a951c980SBrian Tierney 2088556db5dSsethdelliott s = test->listener_udp; 209a951c980SBrian Tierney 210a951c980SBrian Tierney len = sizeof sa_peer; 2118556db5dSsethdelliott if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { 2128556db5dSsethdelliott perror("recvfrom in udp accept"); 2138556db5dSsethdelliott return (-1); 2148556db5dSsethdelliott } 215a951c980SBrian Tierney 2168556db5dSsethdelliott if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { 217a3281a3dSBrian Tierney perror("iperf_udp_accept: connect error"); 218a951c980SBrian Tierney return -1; 219a951c980SBrian Tierney } 2208556db5dSsethdelliott 221a951c980SBrian Tierney sp = test->new_stream(test); 2228556db5dSsethdelliott if (!sp) 2238556db5dSsethdelliott return (-1); 2248556db5dSsethdelliott sp->socket = s; 225a951c980SBrian Tierney iperf_init_stream(sp, test); 226a951c980SBrian Tierney iperf_add_stream(test, sp); 2278556db5dSsethdelliott FD_SET(s, &test->read_set); 2288556db5dSsethdelliott FD_SET(s, &test->write_set); 2298556db5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 230a951c980SBrian Tierney 2318556db5dSsethdelliott test->listener_udp = netannounce(Pudp, NULL, test->server_port); 2328556db5dSsethdelliott if (test->listener_udp < 0) 233a951c980SBrian Tierney return -1; 234a951c980SBrian Tierney 2358556db5dSsethdelliott FD_SET(test->listener_udp, &test->read_set); 2368556db5dSsethdelliott test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd; 237a951c980SBrian Tierney 2388556db5dSsethdelliott /* Let the client know we're ready "accept" another UDP "stream" */ 2398556db5dSsethdelliott if (write(sp->socket, &buf, sizeof(buf)) < 0) { 2408556db5dSsethdelliott perror("write listen message"); 2418556db5dSsethdelliott return -1; 242a951c980SBrian Tierney } 243a951c980SBrian Tierney 2448556db5dSsethdelliott connect_msg(sp); 2458556db5dSsethdelliott test->streams_accepted++; 246a951c980SBrian Tierney 247a951c980SBrian Tierney return 0; 248a951c980SBrian Tierney } 249a951c980SBrian Tierney 250