blob: 74b9aef8a1542f8c0f905e2918691f4dc0261eec [file] [log] [blame]
/*
* 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"
#include "iperf_server_api.h"
#include "iperf_tcp.h"
#include "timer.h"
#include "net.h"
#include "tcp_window_size.h"
#include "iperf_util.h"
#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)
{
int result = 0;
int size = sp->settings->blksize;
if (!sp->buffer) {
fprintf(stderr, "iperf_tcp_recv: receive buffer not allocated\n");
return -1;
}
#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.
*/
do {
result = recv(sp->socket, sp->buffer, size, MSG_WAITALL);
} while (result == -1 && errno == EINTR);
#else
result = Nread(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result == -1) {
perror("Read error");
return -1;
}
sp->result->bytes_received += result;
sp->result->bytes_received_this_interval += result;
return result;
}
/**************************************************************************/
/**
* 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)
{
int result;
int size = sp->settings->blksize;
if (!sp->buffer) {
fprintf(stderr, "iperf_tcp_send: transmit buffer not allocated\n");
return -1;
}
#ifdef USE_SEND
result = send(sp->socket, sp->buffer, size, 0);
#else
result = Nwrite(sp->socket, sp->buffer, size, Ptcp);
#endif
if (result < 0)
perror("Nwrite error");
sp->result->bytes_sent += result;
sp->result->bytes_sent_this_interval += result;
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);
if (!sp) {
perror("malloc");
return (NULL);
}
sp->rcv = iperf_tcp_recv; /* pointer to receive function */
sp->snd = iperf_tcp_send; /* pointer to send function */
/* XXX: not yet written... (what is this supposed to do? ) */
//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;
int peersock;
struct iperf_stream *sp;
len = sizeof(addr);
peersock = accept(test->listener_tcp, (struct sockaddr *) & addr, &len);
if (peersock < 0) {
// XXX: Needs to implement better error handling
printf("Error in accept(): %s\n", strerror(errno));
return -1;
}
// XXX: Nonblocking off. OKAY since we use select.
// setnonblocking(peersock);
// XXX: This doesn't fit our API model!
sp = test->new_stream(test);
sp->socket = peersock;
iperf_init_stream(sp, test);
iperf_add_stream(test, sp);
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 */
return 0;
}