1
1
iperf3/src/iperf_tcp.c

282 строки
6.9 KiB
C
Исходник Обычный вид История

2009-11-02 22:43:19 +00:00
/*
* Copyright (c) 2009-2011, 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.
*
* This code is distributed under a BSD style license, see the LICENSE file
* for complete information.
2009-11-02 22:43:19 +00:00
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <sys/time.h>
#include <sys/select.h>
2009-11-02 22:43:19 +00:00
#include "iperf.h"
#include "iperf_api.h"
#include "iperf_tcp.h"
#include "net.h"
/* iperf_tcp_recv
2009-11-02 22:43:19 +00:00
*
* receives the data for TCP
2009-11-02 22:43:19 +00:00
*/
int
iperf_tcp_recv(struct iperf_stream *sp)
2009-11-02 22:43:19 +00:00
{
int r;
2009-11-02 22:43:19 +00:00
r = Nread(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
if (r < 0)
return r;
sp->result->bytes_received += r;
sp->result->bytes_received_this_interval += r;
2009-11-02 22:43:19 +00:00
return r;
2009-11-02 22:43:19 +00:00
}
/* iperf_tcp_send
2009-11-02 22:43:19 +00:00
*
* sends the data for TCP
2009-11-02 22:43:19 +00:00
*/
int
iperf_tcp_send(struct iperf_stream *sp)
2009-11-02 22:43:19 +00:00
{
int r;
2009-11-02 22:43:19 +00:00
if (sp->test->zerocopy)
r = Nsendfile(sp->buffer_fd, sp->socket, sp->buffer, sp->settings->blksize);
else
r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
if (r < 0)
return r;
sp->result->bytes_sent += r;
sp->result->bytes_sent_this_interval += r;
2009-11-02 22:43:19 +00:00
return r;
2009-11-02 22:43:19 +00:00
}
/* iperf_tcp_accept
2009-11-02 22:43:19 +00:00
*
* accept a new TCP stream connection
2009-11-02 22:43:19 +00:00
*/
int
iperf_tcp_accept(struct iperf_test * test)
{
int s;
int rbuf = ACCESS_DENIED;
char cookie[COOKIE_SIZE];
2009-11-02 22:43:19 +00:00
socklen_t len;
struct sockaddr_storage addr;
2009-11-02 22:43:19 +00:00
len = sizeof(addr);
if ((s = accept(test->listener, (struct sockaddr *) &addr, &len)) < 0) {
i_errno = IESTREAMCONNECT;
return -1;
}
2009-11-02 22:43:19 +00:00
if (Nread(s, cookie, COOKIE_SIZE, Ptcp) < 0) {
i_errno = IERECVCOOKIE;
return -1;
}
2010-07-23 18:39:14 +00:00
if (strcmp(test->cookie, cookie) != 0) {
if (Nwrite(s, (char*) &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)
{
struct addrinfo hints, *res;
char portstr[6];
int s, opt;
s = test->listener;
if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
FD_CLR(s, &test->read_set);
close(s);
snprintf(portstr, 6, "%d", test->server_port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = (test->settings->domain == AF_UNSPEC ? AF_INET6 : test->settings->domain);
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(test->bind_address, portstr, &hints, &res) != 0) {
i_errno = IESTREAMLISTEN;
return -1;
}
if ((s = socket(res->ai_family, 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;
}
}
// XXX: Setting MSS is very buggy!
2010-07-23 18:39:14 +00:00
if ((opt = test->settings->mss)) {
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
i_errno = IESETMSS;
return -1;
}
}
if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
}
opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
i_errno = IEREUSEADDR;
return -1;
}
if (test->settings->domain == AF_UNSPEC || test->settings->domain == AF_INET6) {
if (test->settings->domain == AF_UNSPEC)
opt = 0;
else if (test->settings->domain == AF_INET6)
opt = 1;
setsockopt(s, SOL_SOCKET, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
}
if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
close(s);
i_errno = IESTREAMLISTEN;
return -1;
}
freeaddrinfo(res);
if (listen(s, 5) < 0) {
i_errno = IESTREAMLISTEN;
return -1;
}
test->listener = s;
}
return s;
2009-11-02 22:43:19 +00:00
}
/* iperf_tcp_connect
*
* connect to a TCP stream listener
*/
int
iperf_tcp_connect(struct iperf_test *test)
{
struct addrinfo hints, *local_res, *server_res;
char portstr[6];
int s, opt;
if (test->bind_address) {
memset(&hints, 0, sizeof(hints));
2010-07-27 20:27:34 +00:00
hints.ai_family = test->settings->domain;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(test->bind_address, NULL, &hints, &local_res) != 0) {
i_errno = IESTREAMCONNECT;
return -1;
}
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = test->settings->domain;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, sizeof(portstr), "%d", test->server_port);
if (getaddrinfo(test->server_hostname, portstr, &hints, &server_res) != 0) {
i_errno = IESTREAMCONNECT;
return -1;
}
if ((s = socket(server_res->ai_family, SOCK_STREAM, 0)) < 0) {
i_errno = IESTREAMCONNECT;
return -1;
}
if (test->bind_address) {
if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
i_errno = IESTREAMCONNECT;
return -1;
}
freeaddrinfo(local_res);
}
/* Set socket options */
if (test->no_delay) {
opt = 1;
if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)) < 0) {
i_errno = IESETNODELAY;
return -1;
}
}
2010-07-23 18:39:14 +00:00
if ((opt = test->settings->mss)) {
if (setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &opt, sizeof(opt)) < 0) {
i_errno = IESETMSS;
return -1;
}
}
if ((opt = test->settings->socket_bufsize)) {
if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) < 0) {
i_errno = IESETBUF;
return -1;
}
}
if (connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen) < 0 && errno != EINPROGRESS) {
i_errno = IESTREAMCONNECT;
return -1;
}
freeaddrinfo(server_res);
/* Send cookie for verification */
2010-07-23 18:39:14 +00:00
if (Nwrite(s, test->cookie, COOKIE_SIZE, Ptcp) < 0) {
i_errno = IESENDCOOKIE;
return -1;
}
return s;
}