/* * Copyright (c) 2009, The Regents of the University of California, through * Lawrence Berkeley National Laboratory (subject to receipt of any required * approvals from the U.S. Dept. of Energy). All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "iperf.h" #include "iperf_api.h" #include "iperf_tcp.h" #include "iperf_error.h" #include "net.h" /* iperf_tcp_recv * * receives the data for TCP */ int iperf_tcp_recv(struct iperf_stream *sp) { int result = 0; int size = sp->settings->blksize; result = Nread(sp->socket, sp->buffer, size, Ptcp); if (result < 0) { return (-1); } sp->result->bytes_received += result; sp->result->bytes_received_this_interval += result; return (result); } /* iperf_tcp_send * * sends the data for TCP */ int iperf_tcp_send(struct iperf_stream *sp) { int result; int size = sp->settings->blksize; result = Nwrite(sp->socket, sp->buffer, size, Ptcp); if (result < 0) { return (-1); } sp->result->bytes_sent += result; sp->result->bytes_sent_this_interval += result; return (result); } /* iperf_tcp_accept * * accept a new TCP stream connection */ int iperf_tcp_accept(struct iperf_test * test) { int s; int rbuf = ACCESS_DENIED; char cookie[COOKIE_SIZE]; socklen_t len; struct sockaddr_in addr; len = sizeof(addr); if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) { i_errno = IESTREAMCONNECT; return (-1); } if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IERECVCOOKIE; return (-1); } if (strcmp(test->cookie, cookie) != 0) { if (Nwrite(s, &rbuf, sizeof(char), Ptcp) < 0) { i_errno = IESENDMESSAGE; return (-1); } close(s); } return (s); } /* iperf_tcp_listen * * start up a listener for TCP stream connections */ int iperf_tcp_listen(struct iperf_test *test) { int s, opt; struct sockaddr_in sa; s = test->listener; if (test->no_delay || test->settings->mss) { FD_CLR(s, &test->read_set); close(s); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { i_errno = IESTREAMLISTEN; return (-1); } if (test->no_delay) { opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { i_errno = IESETNODELAY; return (-1); } printf(" TCP NODELAY: on\n"); } // XXX: Setting MSS is very buggy! if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { i_errno = IESETMSS; return (-1); } printf(" TCP MSS: %d\n", opt); } opt = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { i_errno = IEREUSEADDR; return (-1); } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); sa.sin_port = htons(test->server_port); if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) { close(s); i_errno = IESTREAMLISTEN; return (-1); } if (listen(s, 5) < 0) { i_errno = IESTREAMLISTEN; return (-1); } test->listener = s; } return (s); } /* iperf_tcp_connect * * connect to a TCP stream listener */ int iperf_tcp_connect(struct iperf_test *test) { int s, opt; struct sockaddr_in sa; struct hostent *hent; if ((hent = gethostbyname(test->server_hostname)) == 0) { i_errno = IESTREAMCONNECT; return (-1); } if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { i_errno = IESTREAMCONNECT; return (-1); } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; memcpy(&sa.sin_addr.s_addr, hent->h_addr, sizeof(sa.sin_addr.s_addr)); sa.sin_port = htons(test->server_port); /* Set TCP options */ if (test->no_delay) { opt = 1; if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) { i_errno = IESETNODELAY; return (-1); } } if ((opt = test->settings->mss)) { if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) { i_errno = IESETMSS; return (-1); } } if (connect(s, (struct sockaddr *) &sa, sizeof(sa)) < 0 && errno != EINPROGRESS) { i_errno = IESTREAMCONNECT; return (-1); } /* Send cookie for verification */ if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) { i_errno = IESENDCOOKIE; return (-1); } return (s); }