A bunch of changes mixed together in this commit, but the significant
one is the new -Z flag. - Fixed potential bug in net.c's Nread and Nwrite routines. If they had ever needed to loop they would have read/written the wrong address, due to incorrect pointer arithmetic - sizeof(void) is not 1. Fix was to change the type of the buffer pointer to char*, which also meant adding casts to some callers. - Better checking for conflicts between command-line flags - now they should no longer be order-dependent. - Added a new -Z / --zerocopy flag, to use a "zero copy" method of sending data, such as sendfile(2) instead of the usual write(2). - Renumbered error enum to make inserting new ones easier.
This commit is contained in:
parent
358985eb58
commit
987b432316
@ -84,8 +84,8 @@ struct iperf_stream
|
||||
struct iperf_stream_result *result; /* structure pointer to result */
|
||||
Timer *send_timer;
|
||||
int udp_green_light;
|
||||
char *buffer_malloc; /* data to send, malloced */
|
||||
char *buffer; /* data to send, page-aligned */
|
||||
int buffer_fd; /* data to send, file descriptor */
|
||||
char *buffer; /* data to send, mmapped */
|
||||
|
||||
/*
|
||||
* for udp measurements - This can be a structure outside stream, and
|
||||
@ -145,6 +145,7 @@ struct iperf_test
|
||||
int v6domain; /* -6 option */
|
||||
int verbose; /* -V option - verbose mode */
|
||||
int json_output; /* -J option - JSON output */
|
||||
int zerocopy; /* -Z option - use sendfile */
|
||||
|
||||
/* Select related parameters */
|
||||
int max_fd;
|
||||
|
@ -96,6 +96,10 @@ use IPv6
|
||||
.TP
|
||||
.BR -S ", " --tos " \fIn\fR"
|
||||
set the IP 'type of service'
|
||||
.TP
|
||||
.BR -Z ", " --zerocopy " "
|
||||
Use a "zero copy" method of sending data, such as sendfile(2),
|
||||
instead of the usual write(2).
|
||||
|
||||
|
||||
.SH DIAGNOSTICS
|
||||
|
130
src/iperf_api.c
130
src/iperf_api.c
@ -26,6 +26,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sched.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
@ -397,6 +398,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
{"no-delay", no_argument, NULL, 'N'},
|
||||
{"version6", no_argument, NULL, '6'},
|
||||
{"tos", required_argument, NULL, 'S'},
|
||||
{"zerocopy", no_argument, NULL, 'Z'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
|
||||
/* XXX: The following ifdef needs to be split up. linux-congestion is not necessarily supported
|
||||
@ -404,15 +406,17 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
*/
|
||||
#ifdef ADD_WHEN_SUPPORTED
|
||||
{"tos", required_argument, NULL, 'S'},
|
||||
{"linux-congestion", required_argument, NULL, 'Z'},
|
||||
{"linux-congestion", required_argument, NULL, 'L'},
|
||||
#endif
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
char ch;
|
||||
int blksize;
|
||||
int server_flag, client_flag;
|
||||
|
||||
blksize = 0;
|
||||
while ((ch = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N6S:h", longopts, NULL)) != -1) {
|
||||
server_flag = client_flag = 0;
|
||||
while ((ch = getopt_long(argc, argv, "p:f:i:DVJdvsc:ub:t:n:l:P:Rw:B:M:N6S:Zh", longopts, NULL)) != -1) {
|
||||
switch (ch) {
|
||||
case 'p':
|
||||
test->server_port = atoi(optarg);
|
||||
@ -431,11 +435,8 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if (test->role == 'c') {
|
||||
i_errno = IESERVCLIENT;
|
||||
return -1;
|
||||
}
|
||||
test->daemon = 1;
|
||||
server_flag = 1;
|
||||
break;
|
||||
case 'V':
|
||||
test->verbose = 1;
|
||||
@ -467,109 +468,81 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
strncpy(test->server_hostname, optarg, strlen(optarg)+1);
|
||||
break;
|
||||
case 'u':
|
||||
if (test->role == 's') {
|
||||
warning("ignoring client only argument --udp (-u)");
|
||||
/* XXX: made a warning
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
*/
|
||||
}
|
||||
set_protocol(test, Pudp);
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'b':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->settings->rate = unit_atof(optarg);
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 't':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->duration = atoi(optarg);
|
||||
if (test->duration > MAX_TIME) {
|
||||
i_errno = IEDURATION;
|
||||
return -1;
|
||||
}
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'n':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->settings->bytes = unit_atoi(optarg);
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
blksize = unit_atoi(optarg);
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'P':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->num_streams = atoi(optarg);
|
||||
if (test->num_streams > MAX_STREAMS) {
|
||||
i_errno = IENUMSTREAMS;
|
||||
return -1;
|
||||
}
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'R':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->reverse = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'w':
|
||||
// XXX: This is a socket buffer, not specific to TCP
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->settings->socket_bufsize = unit_atof(optarg);
|
||||
if (test->settings->socket_bufsize > MAX_TCP_BUFFER) {
|
||||
i_errno = IEBUFSIZE;
|
||||
return -1;
|
||||
}
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'B':
|
||||
test->bind_address = (char *) malloc(strlen(optarg)+1);
|
||||
strncpy(test->bind_address, optarg, strlen(optarg)+1);
|
||||
break;
|
||||
case 'M':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->settings->mss = atoi(optarg);
|
||||
if (test->settings->mss > MAX_MSS) {
|
||||
i_errno = IEMSS;
|
||||
return -1;
|
||||
}
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'N':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
test->no_delay = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case '6':
|
||||
test->settings->domain = AF_INET6;
|
||||
break;
|
||||
case 'S':
|
||||
if (test->role == 's') {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
// XXX: Checking for errors in strtol is not portable. Leave as is?
|
||||
test->settings->tos = strtol(optarg, NULL, 0);
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'Z':
|
||||
if (!has_sendfile()) {
|
||||
i_errno = IENOSENDFILE;
|
||||
return -1;
|
||||
}
|
||||
test->zerocopy = 1;
|
||||
client_flag = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
@ -578,6 +551,16 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check flag / role compatibility. */
|
||||
if (test->role == 'c' && server_flag) {
|
||||
i_errno = IESERVERONLY;
|
||||
return -1;
|
||||
}
|
||||
if (test->role == 's' && client_flag) {
|
||||
i_errno = IECLIENTONLY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (blksize == 0) {
|
||||
if (test->protocol->id == Pudp)
|
||||
blksize = DEFAULT_UDP_BLKSIZE;
|
||||
@ -763,12 +746,12 @@ iperf_exchange_parameters(struct iperf_test *test)
|
||||
return -1;
|
||||
}
|
||||
msg = htonl(i_errno);
|
||||
if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) {
|
||||
if (Nwrite(test->ctrl_sck, (char*) &msg, sizeof(msg), Ptcp) < 0) {
|
||||
i_errno = IECTRLWRITE;
|
||||
return -1;
|
||||
}
|
||||
msg = htonl(errno);
|
||||
if (Nwrite(test->ctrl_sck, &msg, sizeof(msg), Ptcp) < 0) {
|
||||
if (Nwrite(test->ctrl_sck, (char*) &msg, sizeof(msg), Ptcp) < 0) {
|
||||
i_errno = IECTRLWRITE;
|
||||
return -1;
|
||||
}
|
||||
@ -1050,7 +1033,7 @@ JSON_write(int fd, cJSON *json)
|
||||
else {
|
||||
hsize = strlen(str);
|
||||
nsize = htonl(hsize);
|
||||
if (Nwrite(fd, &nsize, sizeof(nsize), Ptcp) < 0)
|
||||
if (Nwrite(fd, (char*) &nsize, sizeof(nsize), Ptcp) < 0)
|
||||
r = -1;
|
||||
else {
|
||||
if (Nwrite(fd, str, hsize, Ptcp) < 0)
|
||||
@ -1070,7 +1053,7 @@ JSON_read(int fd)
|
||||
char *str;
|
||||
cJSON *json = NULL;
|
||||
|
||||
if (Nread(fd, &nsize, sizeof(nsize), Ptcp) >= 0) {
|
||||
if (Nread(fd, (char*) &nsize, sizeof(nsize), Ptcp) >= 0) {
|
||||
hsize = ntohl(nsize);
|
||||
str = (char *) malloc((hsize+1) * sizeof(char)); /* +1 for EOS */
|
||||
if (str != NULL) {
|
||||
@ -1673,7 +1656,8 @@ iperf_free_stream(struct iperf_stream *sp)
|
||||
struct iperf_interval_results *irp, *nirp;
|
||||
|
||||
/* XXX: need to free interval list too! */
|
||||
free(sp->buffer_malloc);
|
||||
munmap(sp->buffer, sp->test->settings->blksize);
|
||||
close(sp->buffer_fd);
|
||||
for (irp = TAILQ_FIRST(&sp->result->interval_results); irp != TAILQ_END(sp->result->interval_results); irp = nirp) {
|
||||
nirp = TAILQ_NEXT(irp, irlistentries);
|
||||
free(irp);
|
||||
@ -1684,17 +1668,15 @@ iperf_free_stream(struct iperf_stream *sp)
|
||||
free(sp);
|
||||
}
|
||||
|
||||
#define PAGE 65536
|
||||
/* A guess - we should actually detect real page size. But as long as
|
||||
** this is a multiple of the real one, it works for alignment purposes.
|
||||
*/
|
||||
|
||||
/**************************************************************************/
|
||||
struct iperf_stream *
|
||||
iperf_new_stream(struct iperf_test *test, int s)
|
||||
{
|
||||
int i;
|
||||
struct iperf_stream *sp;
|
||||
char template[] = "/tmp/iperf3.XXXXXX";
|
||||
|
||||
h_errno = 0;
|
||||
|
||||
sp = (struct iperf_stream *) malloc(sizeof(struct iperf_stream));
|
||||
if (!sp) {
|
||||
@ -1705,14 +1687,9 @@ iperf_new_stream(struct iperf_test *test, int s)
|
||||
memset(sp, 0, sizeof(struct iperf_stream));
|
||||
|
||||
sp->test = test;
|
||||
sp->buffer_malloc = (char *) malloc(test->settings->blksize + PAGE);
|
||||
sp->result = (struct iperf_stream_result *) malloc(sizeof(struct iperf_stream_result));
|
||||
sp->settings = test->settings;
|
||||
|
||||
if (!sp->buffer_malloc) {
|
||||
i_errno = IECREATESTREAM;
|
||||
return NULL;
|
||||
}
|
||||
if (!sp->result) {
|
||||
i_errno = IECREATESTREAM;
|
||||
return NULL;
|
||||
@ -1721,8 +1698,21 @@ iperf_new_stream(struct iperf_test *test, int s)
|
||||
memset(sp->result, 0, sizeof(struct iperf_stream_result));
|
||||
TAILQ_INIT(&sp->result->interval_results);
|
||||
|
||||
/* Randomize the buffer */
|
||||
sp->buffer = (char*) (((uint64_t) sp->buffer_malloc / PAGE + 1 ) * PAGE);
|
||||
/* Create and randomize the buffer */
|
||||
sp->buffer_fd = mkstemp(template);
|
||||
if (sp->buffer_fd == -1) {
|
||||
i_errno = IECREATESTREAM;
|
||||
return NULL;
|
||||
}
|
||||
if (ftruncate(sp->buffer_fd, test->settings->blksize) < 0) {
|
||||
i_errno = IECREATESTREAM;
|
||||
return NULL;
|
||||
}
|
||||
sp->buffer = (char *) mmap(NULL, test->settings->blksize, PROT_READ|PROT_WRITE, MAP_PRIVATE, sp->buffer_fd, 0);
|
||||
if (sp->buffer == MAP_FAILED) {
|
||||
i_errno = IECREATESTREAM;
|
||||
return NULL;
|
||||
}
|
||||
srandom(time(NULL));
|
||||
for (i = 0; i < test->settings->blksize; ++i)
|
||||
sp->buffer[i] = random();
|
||||
|
100
src/iperf_api.h
100
src/iperf_api.h
@ -207,58 +207,60 @@ enum {
|
||||
/* Parameter errors */
|
||||
IESERVCLIENT = 1, // Iperf cannot be both server and client
|
||||
IENOROLE = 2, // Iperf must either be a client (-c) or server (-s)
|
||||
IECLIENTONLY = 3, // This option is client only
|
||||
IEDURATION = 4, // test duration too long. Maximum value = %dMAX_TIME
|
||||
IENUMSTREAMS = 5, // Number of parallel streams too large. Maximum value = %dMAX_STREAMS
|
||||
IEBLOCKSIZE = 6, // Block size too large. Maximum value = %dMAX_BLOCKSIZE
|
||||
IEBUFSIZE = 7, // Socket buffer size too large. Maximum value = %dMAX_TCP_BUFFER
|
||||
IEINTERVAL = 8, // Report interval too large. Maxumum value = %dMAX_INTERVAL
|
||||
IEMSS = 9, // MSS too large. Maximum value = %dMAX_MSS
|
||||
IESERVERONLY = 3, // This option is server only
|
||||
IECLIENTONLY = 4, // This option is client only
|
||||
IEDURATION = 5, // test duration too long. Maximum value = %dMAX_TIME
|
||||
IENUMSTREAMS = 6, // Number of parallel streams too large. Maximum value = %dMAX_STREAMS
|
||||
IEBLOCKSIZE = 7, // Block size too large. Maximum value = %dMAX_BLOCKSIZE
|
||||
IEBUFSIZE = 8, // Socket buffer size too large. Maximum value = %dMAX_TCP_BUFFER
|
||||
IEINTERVAL = 9, // Report interval too large. Maxumum value = %dMAX_INTERVAL
|
||||
IEMSS = 10, // MSS too large. Maximum value = %dMAX_MSS
|
||||
IENOSENDFILE = 11, // This OS does not support sendfile
|
||||
/* Test errors */
|
||||
IENEWTEST = 10, // Unable to create a new test (check perror)
|
||||
IEINITTEST = 11, // Test initialization failed (check perror)
|
||||
IELISTEN = 12, // Unable to listen for connections (check perror)
|
||||
IECONNECT = 13, // Unable to connect to server (check herror/perror) [from netdial]
|
||||
IEACCEPT = 14, // Unable to accept connection from client (check herror/perror)
|
||||
IESENDCOOKIE = 15, // Unable to send cookie to server (check perror)
|
||||
IERECVCOOKIE = 16, // Unable to receive cookie from client (check perror)
|
||||
IECTRLWRITE = 17, // Unable to write to the control socket (check perror)
|
||||
IECTRLREAD = 18, // Unable to read from the control socket (check perror)
|
||||
IECTRLCLOSE = 19, // Control socket has closed unexpectedly
|
||||
IEMESSAGE = 20, // Received an unknown message
|
||||
IESENDMESSAGE = 21, // Unable to send control message to client/server (check perror)
|
||||
IERECVMESSAGE = 22, // Unable to receive control message from client/server (check perror)
|
||||
IESENDPARAMS = 23, // Unable to send parameters to server (check perror)
|
||||
IERECVPARAMS = 24, // Unable to receive parameters from client (check perror)
|
||||
IEPACKAGERESULTS = 25, // Unable to package results (check perror)
|
||||
IESENDRESULTS = 26, // Unable to send results to client/server (check perror)
|
||||
IERECVRESULTS = 27, // Unable to receive results from client/server (check perror)
|
||||
IESELECT = 28, // Select failed (check perror)
|
||||
IECLIENTTERM = 29, // The client has terminated
|
||||
IESERVERTERM = 30, // The server has terminated
|
||||
IEACCESSDENIED = 31, // The server is busy running a test. Try again later.
|
||||
IESETNODELAY = 32, // Unable to set TCP NODELAY (check perror)
|
||||
IESETMSS = 33, // Unable to set TCP MSS (check perror)
|
||||
IESETBUF = 34, // Unable to set socket buffer size (check perror)
|
||||
IESETTOS = 35, // Unable to set IP TOS (check perror)
|
||||
IESETCOS = 36, // Unable to set IPv6 traffic class (check perror)
|
||||
IEREUSEADDR = 37, // Unable to set reuse address on socket (check perror)
|
||||
IENONBLOCKING = 38, // Unable to set socket to non-blocking (check perror)
|
||||
IESETWINDOWSIZE = 39, // Unable to set socket window size (check perror)
|
||||
IEPROTOCOL = 40, // Protocol does not exist
|
||||
IENEWTEST = 100, // Unable to create a new test (check perror)
|
||||
IEINITTEST = 101, // Test initialization failed (check perror)
|
||||
IELISTEN = 102, // Unable to listen for connections (check perror)
|
||||
IECONNECT = 103, // Unable to connect to server (check herror/perror) [from netdial]
|
||||
IEACCEPT = 104, // Unable to accept connection from client (check herror/perror)
|
||||
IESENDCOOKIE = 105, // Unable to send cookie to server (check perror)
|
||||
IERECVCOOKIE = 106, // Unable to receive cookie from client (check perror)
|
||||
IECTRLWRITE = 107, // Unable to write to the control socket (check perror)
|
||||
IECTRLREAD = 108, // Unable to read from the control socket (check perror)
|
||||
IECTRLCLOSE = 109, // Control socket has closed unexpectedly
|
||||
IEMESSAGE = 110, // Received an unknown message
|
||||
IESENDMESSAGE = 111, // Unable to send control message to client/server (check perror)
|
||||
IERECVMESSAGE = 112, // Unable to receive control message from client/server (check perror)
|
||||
IESENDPARAMS = 113, // Unable to send parameters to server (check perror)
|
||||
IERECVPARAMS = 114, // Unable to receive parameters from client (check perror)
|
||||
IEPACKAGERESULTS = 115, // Unable to package results (check perror)
|
||||
IESENDRESULTS = 116, // Unable to send results to client/server (check perror)
|
||||
IERECVRESULTS = 117, // Unable to receive results from client/server (check perror)
|
||||
IESELECT = 118, // Select failed (check perror)
|
||||
IECLIENTTERM = 119, // The client has terminated
|
||||
IESERVERTERM = 120, // The server has terminated
|
||||
IEACCESSDENIED = 121, // The server is busy running a test. Try again later.
|
||||
IESETNODELAY = 122, // Unable to set TCP NODELAY (check perror)
|
||||
IESETMSS = 123, // Unable to set TCP MSS (check perror)
|
||||
IESETBUF = 124, // Unable to set socket buffer size (check perror)
|
||||
IESETTOS = 125, // Unable to set IP TOS (check perror)
|
||||
IESETCOS = 126, // Unable to set IPv6 traffic class (check perror)
|
||||
IEREUSEADDR = 127, // Unable to set reuse address on socket (check perror)
|
||||
IENONBLOCKING = 128, // Unable to set socket to non-blocking (check perror)
|
||||
IESETWINDOWSIZE = 129, // Unable to set socket window size (check perror)
|
||||
IEPROTOCOL = 130, // Protocol does not exist
|
||||
/* Stream errors */
|
||||
IECREATESTREAM = 41, // Unable to create a new stream (check herror/perror)
|
||||
IEINITSTREAM = 42, // Unable to initialize stream (check herror/perror)
|
||||
IESTREAMLISTEN = 43, // Unable to start stream listener (check perror)
|
||||
IESTREAMCONNECT = 44, // Unable to connect stream (check herror/perror)
|
||||
IESTREAMACCEPT = 45, // Unable to accepte stream connection (check perror)
|
||||
IESTREAMWRITE = 46, // Unable to write to stream socket (check perror)
|
||||
IESTREAMREAD = 47, // Unable to read from stream (check perror)
|
||||
IESTREAMCLOSE = 48, // Stream has closed unexpectedly
|
||||
IESTREAMID = 49, // Stream has invalid ID
|
||||
IECREATESTREAM = 200, // Unable to create a new stream (check herror/perror)
|
||||
IEINITSTREAM = 201, // Unable to initialize stream (check herror/perror)
|
||||
IESTREAMLISTEN = 202, // Unable to start stream listener (check perror)
|
||||
IESTREAMCONNECT = 203, // Unable to connect stream (check herror/perror)
|
||||
IESTREAMACCEPT = 204, // Unable to accepte stream connection (check perror)
|
||||
IESTREAMWRITE = 205, // Unable to write to stream socket (check perror)
|
||||
IESTREAMREAD = 206, // Unable to read from stream (check perror)
|
||||
IESTREAMCLOSE = 207, // Stream has closed unexpectedly
|
||||
IESTREAMID = 208, // Stream has invalid ID
|
||||
/* Timer errors */
|
||||
IENEWTIMER = 50, // Unable to create new timer (check perror)
|
||||
IEUPDATETIMER = 51, // Unable to update timer (check perror)
|
||||
IENEWTIMER = 300, // Unable to create new timer (check perror)
|
||||
IEUPDATETIMER = 301, // Unable to update timer (check perror)
|
||||
};
|
||||
|
||||
#endif /* !__IPERF_API_H */
|
||||
|
@ -105,12 +105,12 @@ iperf_handle_message_client(struct iperf_test *test)
|
||||
i_errno = IEACCESSDENIED;
|
||||
return -1;
|
||||
case SERVER_ERROR:
|
||||
if (Nread(test->ctrl_sck, &i_errno, sizeof(i_errno), Ptcp) < 0) {
|
||||
if (Nread(test->ctrl_sck, (char*) &i_errno, sizeof(i_errno), Ptcp) < 0) {
|
||||
i_errno = IECTRLREAD;
|
||||
return -1;
|
||||
}
|
||||
i_errno = ntohl(i_errno);
|
||||
if (Nread(test->ctrl_sck, &perr, sizeof(perr), Ptcp) < 0) {
|
||||
if (Nread(test->ctrl_sck, (char*) &perr, sizeof(perr), Ptcp) < 0) {
|
||||
i_errno = IECTRLREAD;
|
||||
return -1;
|
||||
}
|
||||
|
@ -72,6 +72,9 @@ iperf_strerror(int i_errno)
|
||||
case IENOROLE:
|
||||
snprintf(errstr, len, "must either be a client (-c) or server (-s)");
|
||||
break;
|
||||
case IESERVERONLY:
|
||||
snprintf(errstr, len, "some option you are trying to set is server only");
|
||||
break;
|
||||
case IECLIENTONLY:
|
||||
snprintf(errstr, len, "some option you are trying to set is client only");
|
||||
break;
|
||||
@ -93,6 +96,9 @@ iperf_strerror(int i_errno)
|
||||
case IEMSS:
|
||||
snprintf(errstr, len, "TCP MSS too large (maximum = %d bytes)", MAX_MSS);
|
||||
break;
|
||||
case IENOSENDFILE:
|
||||
snprintf(errstr, len, "this OS does not support sendfile");
|
||||
break;
|
||||
case IENEWTEST:
|
||||
snprintf(errstr, len, "unable to create a new test");
|
||||
perr = 1;
|
||||
|
@ -138,7 +138,7 @@ iperf_accept(struct iperf_test *test)
|
||||
i_errno = IERECVCOOKIE;
|
||||
return -1;
|
||||
}
|
||||
if (Nwrite(s, &rbuf, sizeof(int), Ptcp) < 0) {
|
||||
if (Nwrite(s, (char*) &rbuf, sizeof(int), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
return -1;
|
||||
}
|
||||
|
@ -56,7 +56,10 @@ iperf_tcp_send(struct iperf_stream *sp)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = Nwrite(sp->socket, sp->buffer, sp->settings->blksize, Ptcp);
|
||||
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;
|
||||
@ -93,7 +96,7 @@ iperf_tcp_accept(struct iperf_test * test)
|
||||
}
|
||||
|
||||
if (strcmp(test->cookie, cookie) != 0) {
|
||||
if (Nwrite(s, &rbuf, sizeof(char), Ptcp) < 0) {
|
||||
if (Nwrite(s, (char*) &rbuf, sizeof(char), Ptcp) < 0) {
|
||||
i_errno = IESENDMESSAGE;
|
||||
return -1;
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ const char usage_longstr[] = "Usage: iperf [-s|-c host] [options]\n"
|
||||
" -N, --nodelay set TCP no delay, disabling Nagle's Algorithm\n"
|
||||
" -6, --version6 use IPv6\n"
|
||||
" -S, --tos N set the IP 'type of service'\n"
|
||||
" -Z, --zerocopy use a 'zero copy' method of sending data\n"
|
||||
|
||||
#ifdef NOT_YET_SUPPORTED /* still working on these */
|
||||
" -D, --daemon run the server as a daemon\n"
|
||||
|
133
src/net.c
133
src/net.c
@ -20,6 +20,18 @@
|
||||
#include <string.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#ifdef linux
|
||||
#include <sys/sendfile.h>
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/uio.h>
|
||||
#else
|
||||
#if defined(__APPLE__) && defined(__MACH__) /* OS X */
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "iperf_util.h"
|
||||
#include "net.h"
|
||||
#include "timer.h"
|
||||
@ -117,26 +129,26 @@ netannounce(int domain, int proto, char *local, int port)
|
||||
|
||||
|
||||
/*******************************************************************/
|
||||
/* reads 'count' byptes from a socket */
|
||||
/* reads 'count' bytes from a socket */
|
||||
/********************************************************************/
|
||||
|
||||
int
|
||||
Nread(int fd, void *buf, int count, int prot)
|
||||
Nread(int fd, char *buf, size_t count, int prot)
|
||||
{
|
||||
register int n;
|
||||
register int nleft = count;
|
||||
register ssize_t r;
|
||||
register size_t nleft = count;
|
||||
|
||||
while (nleft > 0) {
|
||||
if ((n = read(fd, buf, nleft)) < 0) {
|
||||
if ((r = read(fd, buf, nleft)) < 0) {
|
||||
if (errno == EINTR)
|
||||
n = 0;
|
||||
r = 0;
|
||||
else
|
||||
return NET_HARDERROR;
|
||||
} else if (n == 0)
|
||||
} else if (r == 0)
|
||||
break;
|
||||
|
||||
nleft -= n;
|
||||
buf += n;
|
||||
nleft -= r;
|
||||
buf += r;
|
||||
}
|
||||
return count - nleft;
|
||||
}
|
||||
@ -147,13 +159,13 @@ Nread(int fd, void *buf, int count, int prot)
|
||||
*/
|
||||
|
||||
int
|
||||
Nwrite(int fd, void *buf, int count, int prot)
|
||||
Nwrite(int fd, const char *buf, size_t count, int prot)
|
||||
{
|
||||
register int n;
|
||||
register int nleft = count;
|
||||
register ssize_t r;
|
||||
register size_t nleft = count;
|
||||
|
||||
while (nleft > 0) {
|
||||
if ((n = write(fd, buf, nleft)) < 0) {
|
||||
if ((r = write(fd, buf, nleft)) < 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
return count - nleft;
|
||||
@ -166,8 +178,84 @@ Nwrite(int fd, void *buf, int count, int prot)
|
||||
return NET_HARDERROR;
|
||||
}
|
||||
}
|
||||
nleft -= n;
|
||||
buf += n;
|
||||
nleft -= r;
|
||||
buf += r;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
has_sendfile(void)
|
||||
{
|
||||
#ifdef linux
|
||||
return 1;
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
return 1;
|
||||
#else
|
||||
#if defined(__APPLE__) && defined(__MACH__) /* OS X */
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* N S E N D F I L E
|
||||
*/
|
||||
|
||||
int
|
||||
Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
|
||||
{
|
||||
off_t offset;
|
||||
#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
off_t sent;
|
||||
#endif
|
||||
register size_t nleft;
|
||||
register ssize_t r;
|
||||
|
||||
nleft = count;
|
||||
while (nleft > 0) {
|
||||
offset = count - nleft;
|
||||
#ifdef linux
|
||||
r = sendfile(tofd, fromfd, &offset, nleft);
|
||||
#else
|
||||
#ifdef __FreeBSD__
|
||||
r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
|
||||
if (r == 0)
|
||||
r = sent;
|
||||
#else
|
||||
#if defined(__APPLE__) && defined(__MACH__) /* OS X */
|
||||
sent = nleft;
|
||||
r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
|
||||
if (r == 0)
|
||||
r = sent;
|
||||
#else
|
||||
/* Shouldn't happen. */
|
||||
r = -1;
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
if (r < 0) {
|
||||
switch (errno) {
|
||||
case EINTR:
|
||||
return count - nleft;
|
||||
|
||||
case EAGAIN:
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
return NET_SOFTERROR;
|
||||
|
||||
default:
|
||||
return NET_HARDERROR;
|
||||
}
|
||||
}
|
||||
nleft -= r;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@ -206,16 +294,13 @@ getsock_tcp_mss(int inSock)
|
||||
int
|
||||
set_tcp_options(int sock, int no_delay, int mss)
|
||||
{
|
||||
|
||||
socklen_t len;
|
||||
socklen_t len;
|
||||
int rc;
|
||||
int new_mss;
|
||||
|
||||
if (no_delay == 1) {
|
||||
int no_delay = 1;
|
||||
|
||||
len = sizeof(no_delay);
|
||||
int rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char *)&no_delay, len);
|
||||
|
||||
rc = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&no_delay, len);
|
||||
if (rc == -1) {
|
||||
perror("TCP_NODELAY");
|
||||
return -1;
|
||||
@ -223,11 +308,7 @@ set_tcp_options(int sock, int no_delay, int mss)
|
||||
}
|
||||
#ifdef TCP_MAXSEG
|
||||
if (mss > 0) {
|
||||
int rc;
|
||||
int new_mss;
|
||||
|
||||
len = sizeof(new_mss);
|
||||
|
||||
assert(sock != -1);
|
||||
|
||||
/* set */
|
||||
|
14
src/net.h
14
src/net.h
@ -10,12 +10,14 @@
|
||||
#ifndef __NET_H
|
||||
#define __NET_H
|
||||
|
||||
int netdial(int, int, char *, char *, int);
|
||||
int netannounce(int, int, char *, int);
|
||||
int Nwrite(int, void *, int, int) /* __attribute__((hot)) */;
|
||||
int Nread(int, void *, int, int);
|
||||
int getsock_tcp_mss(int);
|
||||
int set_tcp_options(int, int, int);
|
||||
int netdial(int domain, int proto, char *local, char *server, int port);
|
||||
int netannounce(int domain, int proto, char *local, int port);
|
||||
int Nread(int fd, char *buf, size_t count, int prot);
|
||||
int Nwrite(int fd, const char *buf, size_t count, int prot) /* __attribute__((hot)) */;
|
||||
int has_sendfile(void);
|
||||
int Nsendfile(int fromfd, int tofd, const char *buf, size_t count) /* __attribute__((hot)) */;
|
||||
int getsock_tcp_mss(int inSock);
|
||||
int set_tcp_options(int sock, int no_delay, int mss);
|
||||
int setnonblocking(int fd);
|
||||
|
||||
#define NET_SOFTERROR -1
|
||||
|
Loading…
Reference in New Issue
Block a user