2009-11-02 22:43:19 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sched.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
|
|
|
|
#include "iperf.h"
|
|
|
|
#include "iperf_api.h"
|
2009-11-06 07:25:10 +00:00
|
|
|
#include "iperf_server_api.h"
|
2009-11-02 22:43:19 +00:00
|
|
|
#include "iperf_tcp.h"
|
|
|
|
#include "timer.h"
|
|
|
|
#include "net.h"
|
|
|
|
#include "tcp_window_size.h"
|
2010-07-09 00:29:51 +00:00
|
|
|
#include "iperf_util.h"
|
2009-11-02 22:43:19 +00:00
|
|
|
#include "locale.h"
|
|
|
|
|
|
|
|
jmp_buf env; /* to handle longjmp on signal */
|
|
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* iperf_tcp_recv -- receives the data for TCP
|
|
|
|
* and the Param/result message exchange
|
|
|
|
*returns state of packet received
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
iperf_tcp_recv(struct iperf_stream * sp)
|
|
|
|
{
|
2010-06-23 19:13:37 +00:00
|
|
|
int result = 0;
|
2010-06-21 15:08:47 +00:00
|
|
|
int size = sp->settings->blksize;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-06-21 15:08:47 +00:00
|
|
|
if (!sp->buffer) {
|
2010-06-23 19:13:37 +00:00
|
|
|
fprintf(stderr, "iperf_tcp_recv: receive buffer not allocated\n");
|
2010-06-21 15:08:47 +00:00
|
|
|
return -1;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
#ifdef USE_RECV
|
|
|
|
/*
|
|
|
|
* NOTE: Nwrite/Nread seems to be 10-15% faster than send/recv for
|
|
|
|
* localhost on OSX. More testing needed on other OSes to be sure.
|
|
|
|
*/
|
2010-06-23 19:13:37 +00:00
|
|
|
do {
|
|
|
|
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
|
|
|
|
} while (result == -1 && errno == EINTR);
|
2009-11-02 22:43:19 +00:00
|
|
|
#else
|
2010-06-23 19:13:37 +00:00
|
|
|
result = Nread(sp->socket, sp->buffer, size, Ptcp);
|
2009-11-02 22:43:19 +00:00
|
|
|
#endif
|
2010-06-23 19:13:37 +00:00
|
|
|
if (result == -1) {
|
|
|
|
perror("Read error");
|
|
|
|
return -1;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
2010-06-23 19:13:37 +00:00
|
|
|
sp->result->bytes_received += result;
|
|
|
|
sp->result->bytes_received_this_interval += result;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-07-07 21:54:24 +00:00
|
|
|
return result;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* iperf_tcp_send -- sends the client data for TCP
|
|
|
|
* and the Param/result message exchanges
|
|
|
|
* returns: bytes sent
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
iperf_tcp_send(struct iperf_stream * sp)
|
|
|
|
{
|
2010-06-18 21:08:50 +00:00
|
|
|
int result;
|
|
|
|
int size = sp->settings->blksize;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-06-18 21:08:50 +00:00
|
|
|
if (!sp->buffer) {
|
2010-06-23 19:13:37 +00:00
|
|
|
fprintf(stderr, "iperf_tcp_send: transmit buffer not allocated\n");
|
2010-06-18 21:08:50 +00:00
|
|
|
return -1;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
2009-11-02 23:56:55 +00:00
|
|
|
|
2009-11-02 22:43:19 +00:00
|
|
|
#ifdef USE_SEND
|
|
|
|
result = send(sp->socket, sp->buffer, size, 0);
|
|
|
|
#else
|
|
|
|
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
|
|
|
|
#endif
|
|
|
|
if (result < 0)
|
2010-07-14 23:24:58 +00:00
|
|
|
perror("Nwrite error");
|
2009-11-02 23:56:55 +00:00
|
|
|
|
2010-06-23 19:13:37 +00:00
|
|
|
sp->result->bytes_sent += result;
|
|
|
|
sp->result->bytes_sent_this_interval += result;
|
2009-11-02 22:43:19 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
struct iperf_stream *
|
|
|
|
iperf_new_tcp_stream(struct iperf_test * testp)
|
|
|
|
{
|
|
|
|
struct iperf_stream *sp;
|
|
|
|
|
|
|
|
sp = (struct iperf_stream *) iperf_new_stream(testp);
|
2010-06-23 19:13:37 +00:00
|
|
|
if (!sp) {
|
|
|
|
perror("malloc");
|
|
|
|
return (NULL);
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
|
|
|
|
sp->snd = iperf_tcp_send; /* pointer to send function */
|
|
|
|
|
2009-11-06 02:19:20 +00:00
|
|
|
/* XXX: not yet written... (what is this supposed to do? ) */
|
2009-11-02 22:43:19 +00:00
|
|
|
//sp->update_stats = iperf_tcp_update_stats;
|
|
|
|
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* iperf_tcp_accept -- accepts a new TCP connection
|
|
|
|
* on tcp_listener_socket for TCP data and param/result
|
|
|
|
* exchange messages
|
|
|
|
* returns 0 on success
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
iperf_tcp_accept(struct iperf_test * test)
|
|
|
|
{
|
|
|
|
socklen_t len;
|
|
|
|
struct sockaddr_in addr;
|
2010-06-23 19:13:37 +00:00
|
|
|
int peersock;
|
2009-11-02 22:43:19 +00:00
|
|
|
struct iperf_stream *sp;
|
|
|
|
|
|
|
|
len = sizeof(addr);
|
2010-07-14 23:24:58 +00:00
|
|
|
peersock = accept(test->listener_tcp, (struct sockaddr *) & addr, &len);
|
2010-06-21 15:08:47 +00:00
|
|
|
if (peersock < 0) {
|
2010-06-23 19:13:37 +00:00
|
|
|
// XXX: Needs to implement better error handling
|
2010-06-21 15:08:47 +00:00
|
|
|
printf("Error in accept(): %s\n", strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-06-28 22:25:03 +00:00
|
|
|
// XXX: Nonblocking off. OKAY since we use select.
|
|
|
|
// setnonblocking(peersock);
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-06-29 22:02:30 +00:00
|
|
|
// XXX: This doesn't fit our API model!
|
2010-06-23 19:13:37 +00:00
|
|
|
sp = test->new_stream(test);
|
2010-06-21 15:08:47 +00:00
|
|
|
sp->socket = peersock;
|
|
|
|
iperf_init_stream(sp, test);
|
|
|
|
iperf_add_stream(test, sp);
|
2009-11-02 22:43:19 +00:00
|
|
|
|
2010-06-23 19:13:37 +00:00
|
|
|
FD_SET(peersock, &test->read_set); /* add new socket to master set */
|
|
|
|
FD_SET(peersock, &test->write_set);
|
|
|
|
test->max_fd = (test->max_fd < peersock) ? peersock : test->max_fd;
|
|
|
|
|
|
|
|
connect_msg(sp); /* print connect message */
|
2010-06-21 15:08:47 +00:00
|
|
|
|
|
|
|
return 0;
|
2009-11-02 22:43:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|