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 { 56a951c980SBrian Tierney int result, message; 57a951c980SBrian Tierney int size = sp->settings->blksize; 58a951c980SBrian Tierney double transit = 0, d = 0; 59a951c980SBrian Tierney struct udp_datagram *udp = (struct udp_datagram *) sp->buffer; 60a951c980SBrian Tierney struct timeval arrival_time; 61a951c980SBrian Tierney 62a951c980SBrian Tierney printf("in iperf_udp_recv: reading %d bytes \n", size); 63a951c980SBrian Tierney if (!sp->buffer) 64a951c980SBrian Tierney { 65a951c980SBrian Tierney fprintf(stderr, "receive buffer not allocated \n"); 66a951c980SBrian Tierney exit(0); 67a951c980SBrian Tierney } 68a951c980SBrian Tierney #ifdef USE_SEND 69a951c980SBrian Tierney do 70a951c980SBrian Tierney { 71a951c980SBrian Tierney result = recv(sp->socket, sp->buffer, size, 0); 72a951c980SBrian Tierney 73a951c980SBrian Tierney } while (result == -1 && errno == EINTR); 74a951c980SBrian Tierney #else 75a951c980SBrian Tierney result = Nread(sp->socket, sp->buffer, size, Pudp); 76a951c980SBrian Tierney #endif 77a951c980SBrian Tierney 78a951c980SBrian Tierney /* interprete the type of message in packet */ 79a951c980SBrian Tierney if (result > 0) 80a951c980SBrian Tierney { 81a951c980SBrian Tierney message = udp->state; 82a951c980SBrian Tierney } 83a951c980SBrian Tierney if (message != 7) 84a951c980SBrian Tierney { 85a951c980SBrian Tierney //printf("result = %d state = %d, %d = error\n", result, sp->buffer[0], errno); 86a951c980SBrian Tierney } 87a951c980SBrian Tierney if (message == STREAM_RUNNING && (sp->stream_id == udp->stream_id)) 88a951c980SBrian Tierney { 89a951c980SBrian Tierney sp->result->bytes_received += result; 90a951c980SBrian Tierney if (udp->packet_count == sp->packet_count + 1) 91a951c980SBrian Tierney sp->packet_count++; 92a951c980SBrian Tierney 93a951c980SBrian Tierney /* jitter measurement */ 94a951c980SBrian Tierney if (gettimeofday(&arrival_time, NULL) < 0) 95a951c980SBrian Tierney { 96a951c980SBrian Tierney perror("gettimeofday"); 97a951c980SBrian Tierney } 98a951c980SBrian Tierney transit = timeval_diff(&udp->sent_time, &arrival_time); 99a951c980SBrian Tierney d = transit - sp->prev_transit; 100a951c980SBrian Tierney if (d < 0) 101a951c980SBrian Tierney d = -d; 102a951c980SBrian Tierney sp->prev_transit = transit; 103a951c980SBrian Tierney sp->jitter += (d - sp->jitter) / 16.0; 104a951c980SBrian Tierney 105a951c980SBrian Tierney 106a951c980SBrian Tierney /* OUT OF ORDER PACKETS */ 107a951c980SBrian Tierney if (udp->packet_count != sp->packet_count) 108a951c980SBrian Tierney { 109a951c980SBrian Tierney if (udp->packet_count < sp->packet_count + 1) 110a951c980SBrian Tierney { 111a951c980SBrian Tierney sp->outoforder_packets++; 112a951c980SBrian Tierney printf("OUT OF ORDER - incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket); 113a951c980SBrian Tierney } else 114a951c980SBrian Tierney sp->cnt_error += udp->packet_count - sp->packet_count; 115a951c980SBrian Tierney } 116a951c980SBrian Tierney /* store the latest packet id */ 117a951c980SBrian Tierney if (udp->packet_count > sp->packet_count) 118a951c980SBrian Tierney sp->packet_count = udp->packet_count; 119a951c980SBrian Tierney 120a951c980SBrian Tierney //printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket); 121a951c980SBrian Tierney 122a951c980SBrian Tierney } 123a951c980SBrian Tierney return message; 124a951c980SBrian Tierney 125a951c980SBrian Tierney } 126a951c980SBrian Tierney 127a951c980SBrian Tierney 128a951c980SBrian Tierney /**************************************************************************/ 129a951c980SBrian Tierney int 130a951c980SBrian Tierney iperf_udp_send(struct iperf_stream * sp) 131a951c980SBrian Tierney { 132a951c980SBrian Tierney int result = 0; 133a951c980SBrian Tierney struct timeval before, after; 134a951c980SBrian Tierney int64_t dtargus; 135a951c980SBrian Tierney int64_t adjustus = 0; 136a951c980SBrian Tierney 137a951c980SBrian Tierney //printf("in iperf_udp_send \n"); 138a951c980SBrian Tierney /* 139a951c980SBrian Tierney * the || part ensures that last packet is sent to server - the 140a951c980SBrian Tierney * STREAM_END MESSAGE 141a951c980SBrian Tierney */ 142a951c980SBrian Tierney if (sp->send_timer->expired(sp->send_timer) || sp->settings->state == STREAM_END) 143a951c980SBrian Tierney { 144a951c980SBrian Tierney int size = sp->settings->blksize; 145a951c980SBrian Tierney 146a951c980SBrian Tierney /* this is for udp packet/jitter/lost packet measurements */ 147a951c980SBrian Tierney struct udp_datagram *udp = (struct udp_datagram *) sp->buffer; 148a951c980SBrian Tierney struct param_exchange *param = NULL; 149a951c980SBrian Tierney 150a951c980SBrian Tierney dtargus = (int64_t) (sp->settings->blksize) * SEC_TO_US * 8; 151a951c980SBrian Tierney dtargus /= sp->settings->rate; 152a951c980SBrian Tierney 153a951c980SBrian Tierney assert(dtargus != 0); 154a951c980SBrian Tierney 155a951c980SBrian Tierney switch (sp->settings->state) 156a951c980SBrian Tierney { 157a951c980SBrian Tierney case STREAM_BEGIN: 158a951c980SBrian Tierney udp->state = STREAM_BEGIN; 159a951c980SBrian Tierney udp->stream_id = (int) sp; 160a951c980SBrian Tierney /* udp->packet_count = ++sp->packet_count; */ 161a951c980SBrian Tierney break; 162a951c980SBrian Tierney 163a951c980SBrian Tierney case STREAM_END: 164a951c980SBrian Tierney udp->state = STREAM_END; 165a951c980SBrian Tierney udp->stream_id = (int) sp; 166a951c980SBrian Tierney break; 167a951c980SBrian Tierney 168a951c980SBrian Tierney case RESULT_REQUEST: 169a951c980SBrian Tierney udp->state = RESULT_REQUEST; 170a951c980SBrian Tierney udp->stream_id = (int) sp; 171a951c980SBrian Tierney break; 172a951c980SBrian Tierney 173a951c980SBrian Tierney case ALL_STREAMS_END: 174a951c980SBrian Tierney udp->state = ALL_STREAMS_END; 175a951c980SBrian Tierney break; 176a951c980SBrian Tierney 177a951c980SBrian Tierney case STREAM_RUNNING: 178a951c980SBrian Tierney udp->state = STREAM_RUNNING; 179a951c980SBrian Tierney udp->stream_id = (int) sp; 180a951c980SBrian Tierney udp->packet_count = ++sp->packet_count; 181a951c980SBrian Tierney break; 182a951c980SBrian Tierney } 183a951c980SBrian Tierney 184a951c980SBrian Tierney if (sp->settings->state == STREAM_BEGIN) 185a951c980SBrian Tierney { 186a951c980SBrian Tierney sp->settings->state = STREAM_RUNNING; 187a951c980SBrian Tierney } 188a951c980SBrian Tierney if (gettimeofday(&before, 0) < 0) 189a951c980SBrian Tierney perror("gettimeofday"); 190a951c980SBrian Tierney 191a951c980SBrian Tierney udp->sent_time = before; 192a951c980SBrian Tierney 193a951c980SBrian Tierney printf("iperf_udp_send: writing %d bytes \n", size); 194a951c980SBrian Tierney #ifdef USE_SEND 195a951c980SBrian Tierney result = send(sp->socket, sp->buffer, size, 0); 196a951c980SBrian Tierney #else 197a951c980SBrian Tierney result = Nwrite(sp->socket, sp->buffer, size, Pudp); 198a951c980SBrian Tierney #endif 199a951c980SBrian Tierney 200a951c980SBrian Tierney if (gettimeofday(&after, 0) < 0) 201a951c980SBrian Tierney perror("gettimeofday"); 202a951c980SBrian Tierney 203a951c980SBrian Tierney /* 204a951c980SBrian Tierney * CHECK: Packet length and ID if(sp->settings->state == 205a951c980SBrian Tierney * STREAM_RUNNING) printf("State = %d Outgoing packet = %d AND SP = 206a951c980SBrian Tierney * %d\n",sp->settings->state, sp->packet_count, sp->socket); 207a951c980SBrian Tierney */ 208a951c980SBrian Tierney 209a951c980SBrian Tierney if (sp->settings->state == STREAM_RUNNING) 210a951c980SBrian Tierney sp->result->bytes_sent += result; 211a951c980SBrian Tierney 212a951c980SBrian Tierney adjustus = dtargus; 213a951c980SBrian Tierney adjustus += (before.tv_sec - after.tv_sec) * SEC_TO_US; 214a951c980SBrian Tierney adjustus += (before.tv_usec - after.tv_usec); 215a951c980SBrian Tierney 216a951c980SBrian Tierney if (adjustus > 0) 217a951c980SBrian Tierney { 218a951c980SBrian Tierney dtargus = adjustus; 219a951c980SBrian Tierney } 220a951c980SBrian Tierney /* RESET THE TIMER */ 221a951c980SBrian Tierney update_timer(sp->send_timer, 0, dtargus); 222a951c980SBrian Tierney param = NULL; 223a951c980SBrian Tierney 224a951c980SBrian Tierney } /* timer_expired_micro */ 225a951c980SBrian Tierney return result; 226a951c980SBrian Tierney } 227a951c980SBrian Tierney 228a951c980SBrian Tierney /**************************************************************************/ 229a951c980SBrian Tierney struct iperf_stream * 230a951c980SBrian Tierney iperf_new_udp_stream(struct iperf_test * testp) 231a951c980SBrian Tierney { 232a951c980SBrian Tierney struct iperf_stream *sp; 233a951c980SBrian Tierney 234a951c980SBrian Tierney sp = (struct iperf_stream *) iperf_new_stream(testp); 235a951c980SBrian Tierney if (!sp) 236a951c980SBrian Tierney { 237a951c980SBrian Tierney perror("malloc"); 238a951c980SBrian Tierney return (NULL); 239a951c980SBrian Tierney } 240a951c980SBrian Tierney sp->rcv = iperf_udp_recv; 241a951c980SBrian Tierney sp->snd = iperf_udp_send; 242a951c980SBrian Tierney 243a951c980SBrian Tierney return sp; 244a951c980SBrian Tierney } 245a951c980SBrian Tierney 246a951c980SBrian Tierney /**************************************************************************/ 247a951c980SBrian Tierney 248a951c980SBrian Tierney /** 249a951c980SBrian Tierney * iperf_udp_accept -- accepts a new UDP connection 250a951c980SBrian Tierney * on udp_listener_socket 251a951c980SBrian Tierney *returns 0 on success 252a951c980SBrian Tierney * 253a951c980SBrian Tierney */ 254a951c980SBrian Tierney 255a951c980SBrian Tierney 256a951c980SBrian Tierney int 257a951c980SBrian Tierney iperf_udp_accept(struct iperf_test * test) 258a951c980SBrian Tierney { 259a951c980SBrian Tierney 260a951c980SBrian Tierney struct iperf_stream *sp; 261a951c980SBrian Tierney struct sockaddr_in sa_peer; 262a951c980SBrian Tierney char *buf; 263a951c980SBrian Tierney socklen_t len; 264a951c980SBrian Tierney int sz; 265a951c980SBrian Tierney 266a951c980SBrian Tierney buf = (char *) malloc(test->default_settings->blksize); 267a951c980SBrian Tierney struct udp_datagram *udp = (struct udp_datagram *) buf; 268a951c980SBrian Tierney 269a951c980SBrian Tierney len = sizeof sa_peer; 270a951c980SBrian Tierney 271a951c980SBrian Tierney sz = recvfrom(test->listener_sock_udp, buf, test->default_settings->blksize, 0, (struct sockaddr *) & sa_peer, &len); 272a951c980SBrian Tierney 273a951c980SBrian Tierney if (!sz) 274a951c980SBrian Tierney return -1; 275a951c980SBrian Tierney 276a951c980SBrian Tierney if (connect(test->listener_sock_udp, (struct sockaddr *) & sa_peer, len) < 0) 277a951c980SBrian Tierney { 278*a3281a3dSBrian Tierney perror("iperf_udp_accept: connect error"); 279*a3281a3dSBrian Tierney exit(-1); /* XXX: for debugging */ 280a951c980SBrian Tierney return -1; 281a951c980SBrian Tierney } 282a951c980SBrian Tierney sp = test->new_stream(test); 283a951c980SBrian Tierney 284a951c980SBrian Tierney sp->socket = test->listener_sock_udp; 285a951c980SBrian Tierney 286a951c980SBrian Tierney setnonblocking(sp->socket); 287a951c980SBrian Tierney 288a951c980SBrian Tierney iperf_init_stream(sp, test); 289a951c980SBrian Tierney iperf_add_stream(test, sp); 290a951c980SBrian Tierney 291a951c980SBrian Tierney 292a951c980SBrian Tierney test->listener_sock_udp = netannounce(Pudp, NULL, test->server_port); 293a951c980SBrian Tierney if (test->listener_sock_udp < 0) 294a951c980SBrian Tierney return -1; 295a951c980SBrian Tierney 296a951c980SBrian Tierney FD_SET(test->listener_sock_udp, &test->read_set); 297a951c980SBrian Tierney test->max_fd = (test->max_fd < test->listener_sock_udp) ? test->listener_sock_udp : test->max_fd; 298a951c980SBrian Tierney 299a951c980SBrian Tierney if (test->default_settings->state != RESULT_REQUEST) 300a951c980SBrian Tierney connect_msg(sp); 301a951c980SBrian Tierney 302a951c980SBrian Tierney printf("iperf_udp_accept: 1st UDP data packet for socket %d has arrived \n", sp->socket); 303a951c980SBrian Tierney sp->stream_id = udp->stream_id; 304a951c980SBrian Tierney sp->result->bytes_received += sz; 305a951c980SBrian Tierney 306a951c980SBrian Tierney /* Count OUT OF ORDER PACKETS */ 307a951c980SBrian Tierney if (udp->packet_count != 0) 308a951c980SBrian Tierney { 309a951c980SBrian Tierney if (udp->packet_count < sp->packet_count + 1) 310a951c980SBrian Tierney sp->outoforder_packets++; 311a951c980SBrian Tierney else 312a951c980SBrian Tierney sp->cnt_error += udp->packet_count - sp->packet_count; 313a951c980SBrian Tierney } 314a951c980SBrian Tierney /* store the latest packet id */ 315a951c980SBrian Tierney if (udp->packet_count > sp->packet_count) 316a951c980SBrian Tierney sp->packet_count = udp->packet_count; 317a951c980SBrian Tierney 318a951c980SBrian Tierney //printf("incoming packet = %d and received packet = %d AND SP = %d\n", udp->packet_count, sp->packet_count, sp->socket); 319a951c980SBrian Tierney 320a951c980SBrian Tierney free(buf); 321a951c980SBrian Tierney return 0; 322a951c980SBrian Tierney } 323a951c980SBrian Tierney 324