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:
Jef Poskanzer 2013-03-04 15:55:16 -08:00
parent 358985eb58
commit 987b432316
11 changed files with 248 additions and 158 deletions

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
View File

@ -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 */

View File

@ -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