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" 39*b60a49ddSsethdelliott #include "iperf_error.h" 40a951c980SBrian Tierney #include "timer.h" 41a951c980SBrian Tierney #include "net.h" 42a951c980SBrian Tierney #include "locale.h" 43a951c980SBrian Tierney 44a951c980SBrian Tierney 45a951c980SBrian Tierney /**************************************************************************/ 46a951c980SBrian Tierney 47a951c980SBrian Tierney /** 48a951c980SBrian Tierney * iperf_udp_recv -- receives the client data for UDP 49a951c980SBrian Tierney * 50a951c980SBrian Tierney *returns state of packet received 51a951c980SBrian Tierney * 52a951c980SBrian Tierney */ 53a951c980SBrian Tierney 54a951c980SBrian Tierney int 55a951c980SBrian Tierney iperf_udp_recv(struct iperf_stream *sp) 56a951c980SBrian Tierney { 578556db5dSsethdelliott int result; 58a951c980SBrian Tierney int size = sp->settings->blksize; 598556db5dSsethdelliott int sec, usec, pcount; 60a951c980SBrian Tierney double transit = 0, d = 0; 618556db5dSsethdelliott struct timeval sent_time, arrival_time; 62a951c980SBrian Tierney 63a951c980SBrian Tierney #ifdef USE_SEND 648556db5dSsethdelliott do { 65a951c980SBrian Tierney result = recv(sp->socket, sp->buffer, size, 0); 66a951c980SBrian Tierney } while (result == -1 && errno == EINTR); 67a951c980SBrian Tierney #else 68a951c980SBrian Tierney result = Nread(sp->socket, sp->buffer, size, Pudp); 69a951c980SBrian Tierney #endif 70a951c980SBrian Tierney 718556db5dSsethdelliott if (result < 0) { 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 */ 98*b60a49ddSsethdelliott gettimeofday(&arrival_time, NULL); 99*b60a49ddSsethdelliott 1008556db5dSsethdelliott transit = timeval_diff(&sent_time, &arrival_time); 101a951c980SBrian Tierney d = transit - sp->prev_transit; 102a951c980SBrian Tierney if (d < 0) 103a951c980SBrian Tierney d = -d; 104a951c980SBrian Tierney sp->prev_transit = transit; 1058556db5dSsethdelliott // XXX: This is NOT the way to calculate jitter 1068556db5dSsethdelliott // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] 107a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 108a951c980SBrian Tierney 1098556db5dSsethdelliott return result; 110a951c980SBrian Tierney } 111a951c980SBrian Tierney 112a951c980SBrian Tierney 113a951c980SBrian Tierney /**************************************************************************/ 114a951c980SBrian Tierney int 115a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp) 116a951c980SBrian Tierney { 1178556db5dSsethdelliott ssize_t result = 0; 118a951c980SBrian Tierney int64_t dtargus; 119a951c980SBrian Tierney int64_t adjustus = 0; 1208556db5dSsethdelliott uint64_t sec, usec, pcount; 1218556db5dSsethdelliott int size = sp->settings->blksize; 1228556db5dSsethdelliott struct timeval before, after; 123a951c980SBrian Tierney 124aa89cda2Ssethdelliott if (timer_expired(sp->send_timer)) { 125a951c980SBrian Tierney 126a951c980SBrian Tierney dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; 127a951c980SBrian Tierney dtargus /= sp->settings->rate; 128a951c980SBrian Tierney 129a951c980SBrian Tierney assert(dtargus != 0); 130aa89cda2Ssethdelliott 131*b60a49ddSsethdelliott gettimeofday(&before, 0); 132*b60a49ddSsethdelliott 1338556db5dSsethdelliott ++sp->packet_count; 1348556db5dSsethdelliott sec = htonl(before.tv_sec); 1358556db5dSsethdelliott usec = htonl(before.tv_usec); 1368556db5dSsethdelliott pcount = htonl(sp->packet_count); 137a951c980SBrian Tierney 1388556db5dSsethdelliott memcpy(sp->buffer, &sec, sizeof(sec)); 1398556db5dSsethdelliott memcpy(sp->buffer+4, &usec, sizeof(usec)); 1408556db5dSsethdelliott memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 141a951c980SBrian Tierney 142a951c980SBrian Tierney #ifdef USE_SEND 143a951c980SBrian Tierney result = send(sp->socket, sp->buffer, size, 0); 144a951c980SBrian Tierney #else 145a951c980SBrian Tierney result = Nwrite(sp->socket, sp->buffer, size, Pudp); 146a951c980SBrian Tierney #endif 147a951c980SBrian Tierney 1488556db5dSsethdelliott if (result < 0) 149*b60a49ddSsethdelliott return (-1); 1508556db5dSsethdelliott 1518556db5dSsethdelliott sp->result->bytes_sent += result; 1528556db5dSsethdelliott sp->result->bytes_sent_this_interval += result; 153aa89cda2Ssethdelliott 154*b60a49ddSsethdelliott gettimeofday(&after, 0); 155a951c980SBrian Tierney 156a951c980SBrian Tierney adjustus = dtargus; 157a951c980SBrian Tierney adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; 158a951c980SBrian Tierney adjustus += (before.tv_usec - after.tv_usec); 159a951c980SBrian Tierney 1608556db5dSsethdelliott if (adjustus > 0) { 161a951c980SBrian Tierney dtargus = adjustus; 162a951c980SBrian Tierney } 163aa89cda2Ssethdelliott 164*b60a49ddSsethdelliott if (update_timer(sp->send_timer, 0, dtargus) < 0) 165*b60a49ddSsethdelliott return (-1); 166aa89cda2Ssethdelliott } 167aa89cda2Ssethdelliott 168a951c980SBrian Tierney return result; 169a951c980SBrian Tierney } 170a951c980SBrian Tierney 171a951c980SBrian Tierney /**************************************************************************/ 172a951c980SBrian Tierney struct iperf_stream * 173a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp) 174a951c980SBrian Tierney { 175a951c980SBrian Tierney struct iperf_stream *sp; 176a951c980SBrian Tierney 177a951c980SBrian Tierney sp = (struct iperf_stream *) iperf_new_stream(testp); 1788556db5dSsethdelliott if (!sp) { 179a951c980SBrian Tierney return (NULL); 180a951c980SBrian Tierney } 181a951c980SBrian Tierney sp->rcv = iperf_udp_recv; 182a951c980SBrian Tierney sp->snd = iperf_udp_send; 183a951c980SBrian Tierney 184a951c980SBrian Tierney return sp; 185a951c980SBrian Tierney } 186a951c980SBrian Tierney 187a951c980SBrian Tierney /**************************************************************************/ 188a951c980SBrian Tierney 189a951c980SBrian Tierney /** 190a951c980SBrian Tierney * iperf_udp_accept -- accepts a new UDP connection 191a951c980SBrian Tierney * on udp_listener_socket 192a951c980SBrian Tierney *returns 0 on success 193a951c980SBrian Tierney * 194a951c980SBrian Tierney */ 195a951c980SBrian Tierney 196a951c980SBrian Tierney 197a951c980SBrian Tierney int 198a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test) 199a951c980SBrian Tierney { 200a951c980SBrian Tierney struct iperf_stream *sp; 201a951c980SBrian Tierney struct sockaddr_in sa_peer; 2028556db5dSsethdelliott int buf; 203a951c980SBrian Tierney socklen_t len; 2048556db5dSsethdelliott int sz, s; 205a951c980SBrian Tierney 2068556db5dSsethdelliott s = test->listener_udp; 207a951c980SBrian Tierney 208a951c980SBrian Tierney len = sizeof sa_peer; 2098556db5dSsethdelliott if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { 210*b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 2118556db5dSsethdelliott return (-1); 2128556db5dSsethdelliott } 213a951c980SBrian Tierney 2148556db5dSsethdelliott if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { 215*b60a49ddSsethdelliott i_errno = IESTREAMACCEPT; 216*b60a49ddSsethdelliott return (-1); 217a951c980SBrian Tierney } 2188556db5dSsethdelliott 219a951c980SBrian Tierney sp = test->new_stream(test); 2208556db5dSsethdelliott if (!sp) 2218556db5dSsethdelliott return (-1); 2228556db5dSsethdelliott sp->socket = s; 223*b60a49ddSsethdelliott if (iperf_init_stream(sp, test) < 0) 224*b60a49ddSsethdelliott return (-1); 225a951c980SBrian Tierney iperf_add_stream(test, sp); 2268556db5dSsethdelliott FD_SET(s, &test->read_set); 2278556db5dSsethdelliott FD_SET(s, &test->write_set); 2288556db5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 229a951c980SBrian Tierney 2308556db5dSsethdelliott test->listener_udp = netannounce(Pudp, NULL, test->server_port); 231*b60a49ddSsethdelliott if (test->listener_udp < 0) { 232*b60a49ddSsethdelliott i_errno = IELISTEN; 233*b60a49ddSsethdelliott return (-1); 234*b60a49ddSsethdelliott } 235a951c980SBrian Tierney 2368556db5dSsethdelliott FD_SET(test->listener_udp, &test->read_set); 2378556db5dSsethdelliott test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd; 238a951c980SBrian Tierney 2398556db5dSsethdelliott /* Let the client know we're ready "accept" another UDP "stream" */ 2408556db5dSsethdelliott if (write(sp->socket, &buf, sizeof(buf)) < 0) { 241*b60a49ddSsethdelliott i_errno = IESTREAMWRITE; 242*b60a49ddSsethdelliott return (-1); 243a951c980SBrian Tierney } 244a951c980SBrian Tierney 2458556db5dSsethdelliott connect_msg(sp); 2468556db5dSsethdelliott test->streams_accepted++; 247a951c980SBrian Tierney 248*b60a49ddSsethdelliott return (0); 249a951c980SBrian Tierney } 250a951c980SBrian Tierney 251