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 { 56*8556db5dSsethdelliott int result; 57a951c980SBrian Tierney int size = sp->settings->blksize; 58*8556db5dSsethdelliott int sec, usec, pcount; 59a951c980SBrian Tierney double transit = 0, d = 0; 60*8556db5dSsethdelliott struct timeval sent_time, arrival_time; 61a951c980SBrian Tierney 62*8556db5dSsethdelliott // XXX: Is this necessary? We've already checked the buffer to see if it's allocated. 63*8556db5dSsethdelliott if (!sp->buffer) { 64a951c980SBrian Tierney fprintf(stderr, "receive buffer not allocated \n"); 65a951c980SBrian Tierney exit(0); 66a951c980SBrian Tierney } 67a951c980SBrian Tierney #ifdef USE_SEND 68*8556db5dSsethdelliott do { 69a951c980SBrian Tierney result = recv(sp->socket, sp->buffer, size, 0); 70a951c980SBrian Tierney } while (result == -1 && errno == EINTR); 71a951c980SBrian Tierney #else 72a951c980SBrian Tierney result = Nread(sp->socket, sp->buffer, size, Pudp); 73a951c980SBrian Tierney #endif 74a951c980SBrian Tierney 75*8556db5dSsethdelliott if (result < 0) { 76*8556db5dSsethdelliott perror("Nread udp result"); 77*8556db5dSsethdelliott return (-1); 78a951c980SBrian Tierney } 79a951c980SBrian Tierney sp->result->bytes_received += result; 80*8556db5dSsethdelliott sp->result->bytes_received_this_interval += result; 81*8556db5dSsethdelliott 82*8556db5dSsethdelliott memcpy(&sec, sp->buffer, sizeof(sec)); 83*8556db5dSsethdelliott memcpy(&usec, sp->buffer+4, sizeof(usec)); 84*8556db5dSsethdelliott memcpy(&pcount, sp->buffer+8, sizeof(pcount)); 85*8556db5dSsethdelliott sec = ntohl(sec); 86*8556db5dSsethdelliott usec = ntohl(usec); 87*8556db5dSsethdelliott pcount = ntohl(pcount); 88*8556db5dSsethdelliott sent_time.tv_sec = sec; 89*8556db5dSsethdelliott sent_time.tv_usec = usec; 90*8556db5dSsethdelliott 91*8556db5dSsethdelliott /* Out of order packets */ 92*8556db5dSsethdelliott if (pcount >= sp->packet_count + 1) { 93*8556db5dSsethdelliott if (pcount > sp->packet_count + 1) { 94*8556db5dSsethdelliott sp->cnt_error += (pcount - 1) - sp->packet_count; 95*8556db5dSsethdelliott } 96*8556db5dSsethdelliott sp->packet_count = pcount; 97*8556db5dSsethdelliott } else { 98*8556db5dSsethdelliott sp->outoforder_packets++; 99*8556db5dSsethdelliott printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", pcount, sp->packet_count, sp->socket); 100*8556db5dSsethdelliott } 101a951c980SBrian Tierney 102a951c980SBrian Tierney /* jitter measurement */ 103*8556db5dSsethdelliott if (gettimeofday(&arrival_time, NULL) < 0) { 104a951c980SBrian Tierney perror("gettimeofday"); 105a951c980SBrian Tierney } 106*8556db5dSsethdelliott transit = timeval_diff(&sent_time, &arrival_time); 107a951c980SBrian Tierney d = transit - sp->prev_transit; 108a951c980SBrian Tierney if (d < 0) 109a951c980SBrian Tierney d = -d; 110a951c980SBrian Tierney sp->prev_transit = transit; 111*8556db5dSsethdelliott // XXX: This is NOT the way to calculate jitter 112*8556db5dSsethdelliott // J = |(R1 - S1) - (R0 - S0)| [/ number of packets, for average] 113a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 114a951c980SBrian Tierney 115*8556db5dSsethdelliott return result; 116a951c980SBrian Tierney } 117a951c980SBrian Tierney 118a951c980SBrian Tierney 119a951c980SBrian Tierney /**************************************************************************/ 120a951c980SBrian Tierney int 121a951c980SBrian Tierney iperf_udp_send(struct iperf_stream *sp) 122a951c980SBrian Tierney { 123*8556db5dSsethdelliott ssize_t result = 0; 124a951c980SBrian Tierney int64_t dtargus; 125a951c980SBrian Tierney int64_t adjustus = 0; 126*8556db5dSsethdelliott uint64_t sec, usec, pcount; 127*8556db5dSsethdelliott int size = sp->settings->blksize; 128*8556db5dSsethdelliott struct timeval before, after; 129a951c980SBrian Tierney 130a951c980SBrian Tierney /* 131a951c980SBrian Tierney * the || part ensures that last packet is sent to server - the 132a951c980SBrian Tierney * STREAM_END MESSAGE 133a951c980SBrian Tierney */ 134*8556db5dSsethdelliott // if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END) { 135a951c980SBrian Tierney 136*8556db5dSsethdelliott /* 137a951c980SBrian Tierney dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; 138a951c980SBrian Tierney dtargus /= sp->settings->rate; 139a951c980SBrian Tierney 140a951c980SBrian Tierney assert(dtargus != 0); 141*8556db5dSsethdelliott */ 142a951c980SBrian Tierney if (gettimeofday(&before, 0) < 0) 143a951c980SBrian Tierney perror("gettimeofday"); 144*8556db5dSsethdelliott ++sp->packet_count; 145*8556db5dSsethdelliott sec = htonl(before.tv_sec); 146*8556db5dSsethdelliott usec = htonl(before.tv_usec); 147*8556db5dSsethdelliott pcount = htonl(sp->packet_count); 148a951c980SBrian Tierney 149*8556db5dSsethdelliott memcpy(sp->buffer, &sec, sizeof(sec)); 150*8556db5dSsethdelliott memcpy(sp->buffer+4, &usec, sizeof(usec)); 151*8556db5dSsethdelliott memcpy(sp->buffer+8, &pcount, sizeof(pcount)); 152a951c980SBrian Tierney 153a951c980SBrian Tierney #ifdef USE_SEND 154a951c980SBrian Tierney result = send(sp->socket, sp->buffer, size, 0); 155a951c980SBrian Tierney #else 156a951c980SBrian Tierney result = Nwrite(sp->socket, sp->buffer, size, Pudp); 157a951c980SBrian Tierney #endif 158a951c980SBrian Tierney 159*8556db5dSsethdelliott if (result < 0) 160*8556db5dSsethdelliott perror("Nwrite udp error"); 161*8556db5dSsethdelliott 162*8556db5dSsethdelliott sp->result->bytes_sent += result; 163*8556db5dSsethdelliott sp->result->bytes_sent_this_interval += result; 164*8556db5dSsethdelliott /* 165a951c980SBrian Tierney if (gettimeofday(&after, 0) < 0) 166a951c980SBrian Tierney perror("gettimeofday"); 167a951c980SBrian Tierney 168*8556db5dSsethdelliott // 169*8556db5dSsethdelliott // CHECK: Packet length and ID if(sp->settings->state == 170*8556db5dSsethdelliott // STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP = 171*8556db5dSsethdelliott // %d\n",sp->settings->state, sp->packet_count, sp->socket); 172*8556db5dSsethdelliott // 173a951c980SBrian Tierney 174a951c980SBrian Tierney 175a951c980SBrian Tierney adjustus = dtargus; 176a951c980SBrian Tierney adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; 177a951c980SBrian Tierney adjustus += (before.tv_usec - after.tv_usec); 178a951c980SBrian Tierney 179*8556db5dSsethdelliott if (adjustus > 0) { 180a951c980SBrian Tierney dtargus = adjustus; 181a951c980SBrian Tierney } 182*8556db5dSsethdelliott // RESET THE TIMER 183a951c980SBrian Tierney update_timer(sp->send_timer, 0, dtargus); 184*8556db5dSsethdelliott // } // timer_expired_micro 185*8556db5dSsethdelliott */ 186a951c980SBrian Tierney return result; 187a951c980SBrian Tierney } 188a951c980SBrian Tierney 189a951c980SBrian Tierney /**************************************************************************/ 190a951c980SBrian Tierney struct iperf_stream * 191a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp) 192a951c980SBrian Tierney { 193a951c980SBrian Tierney struct iperf_stream *sp; 194a951c980SBrian Tierney 195a951c980SBrian Tierney sp = (struct iperf_stream *) iperf_new_stream(testp); 196*8556db5dSsethdelliott if (!sp) { 197a951c980SBrian Tierney perror("malloc"); 198a951c980SBrian Tierney return (NULL); 199a951c980SBrian Tierney } 200a951c980SBrian Tierney sp->rcv = iperf_udp_recv; 201a951c980SBrian Tierney sp->snd = iperf_udp_send; 202a951c980SBrian Tierney 203a951c980SBrian Tierney return sp; 204a951c980SBrian Tierney } 205a951c980SBrian Tierney 206a951c980SBrian Tierney /**************************************************************************/ 207a951c980SBrian Tierney 208a951c980SBrian Tierney /** 209a951c980SBrian Tierney * iperf_udp_accept -- accepts a new UDP connection 210a951c980SBrian Tierney * on udp_listener_socket 211a951c980SBrian Tierney *returns 0 on success 212a951c980SBrian Tierney * 213a951c980SBrian Tierney */ 214a951c980SBrian Tierney 215a951c980SBrian Tierney 216a951c980SBrian Tierney int 217a951c980SBrian Tierney iperf_udp_accept(struct iperf_test *test) 218a951c980SBrian Tierney { 219a951c980SBrian Tierney struct iperf_stream *sp; 220a951c980SBrian Tierney struct sockaddr_in sa_peer; 221*8556db5dSsethdelliott int buf; 222a951c980SBrian Tierney socklen_t len; 223*8556db5dSsethdelliott int sz, s; 224a951c980SBrian Tierney 225*8556db5dSsethdelliott s = test->listener_udp; 226a951c980SBrian Tierney 227a951c980SBrian Tierney len = sizeof sa_peer; 228*8556db5dSsethdelliott if ((sz = recvfrom(test->listener_udp, &buf, sizeof(buf), 0, (struct sockaddr *) &sa_peer, &len)) < 0) { 229*8556db5dSsethdelliott perror("recvfrom in udp accept"); 230*8556db5dSsethdelliott return (-1); 231*8556db5dSsethdelliott } 232a951c980SBrian Tierney 233*8556db5dSsethdelliott if (connect(s, (struct sockaddr *) &sa_peer, len) < 0) { 234a3281a3dSBrian Tierney perror("iperf_udp_accept: connect error"); 235a951c980SBrian Tierney return -1; 236a951c980SBrian Tierney } 237*8556db5dSsethdelliott 238a951c980SBrian Tierney sp = test->new_stream(test); 239*8556db5dSsethdelliott if (!sp) 240*8556db5dSsethdelliott return (-1); 241*8556db5dSsethdelliott sp->socket = s; 242a951c980SBrian Tierney iperf_init_stream(sp, test); 243a951c980SBrian Tierney iperf_add_stream(test, sp); 244*8556db5dSsethdelliott FD_SET(s, &test->read_set); 245*8556db5dSsethdelliott FD_SET(s, &test->write_set); 246*8556db5dSsethdelliott test->max_fd = (s > test->max_fd) ? s : test->max_fd; 247a951c980SBrian Tierney 248*8556db5dSsethdelliott test->listener_udp = netannounce(Pudp, NULL, test->server_port); 249*8556db5dSsethdelliott if (test->listener_udp < 0) 250a951c980SBrian Tierney return -1; 251a951c980SBrian Tierney 252*8556db5dSsethdelliott FD_SET(test->listener_udp, &test->read_set); 253*8556db5dSsethdelliott test->max_fd = (test->max_fd < test->listener_udp) ? test->listener_udp : test->max_fd; 254a951c980SBrian Tierney 255*8556db5dSsethdelliott /* Let the client know we're ready "accept" another UDP "stream" */ 256*8556db5dSsethdelliott if (write(sp->socket, &buf, sizeof(buf)) < 0) { 257*8556db5dSsethdelliott perror("write listen message"); 258*8556db5dSsethdelliott return -1; 259a951c980SBrian Tierney } 260a951c980SBrian Tierney 261*8556db5dSsethdelliott connect_msg(sp); 262*8556db5dSsethdelliott test->streams_accepted++; 263a951c980SBrian Tierney 264a951c980SBrian Tierney return 0; 265a951c980SBrian Tierney } 266a951c980SBrian Tierney 267