17d375156SJon Dugan /*
238bac802SBruce A. Mah * iperf, Copyright (c) 2014-2019, The Regents of the University of
3da9f046fSBruce A. Mah * California, through Lawrence Berkeley National Laboratory (subject
4da9f046fSBruce A. Mah * to receipt of any required approvals from the U.S. Dept. of
5da9f046fSBruce A. Mah * Energy). All rights reserved.
67d375156SJon Dugan *
7da9f046fSBruce A. Mah * If you have questions about your rights to use or distribute this
8da9f046fSBruce A. Mah * software, please contact Berkeley Lab's Technology Transfer
9da9f046fSBruce A. Mah * Department at [email protected].
10da9f046fSBruce A. Mah *
11da9f046fSBruce A. Mah * NOTICE. This software is owned by the U.S. Department of Energy.
12da9f046fSBruce A. Mah * As such, the U.S. Government has been granted for itself and others
13da9f046fSBruce A. Mah * acting on its behalf a paid-up, nonexclusive, irrevocable,
14da9f046fSBruce A. Mah * worldwide license in the Software to reproduce, prepare derivative
15da9f046fSBruce A. Mah * works, and perform publicly and display publicly. Beginning five
16da9f046fSBruce A. Mah * (5) years after the date permission to assert copyright is obtained
17da9f046fSBruce A. Mah * from the U.S. Department of Energy, and subject to any subsequent
18da9f046fSBruce A. Mah * five (5) year renewals, the U.S. Government is granted for itself
19da9f046fSBruce A. Mah * and others acting on its behalf a paid-up, nonexclusive,
20da9f046fSBruce A. Mah * irrevocable, worldwide license in the Software to reproduce,
21da9f046fSBruce A. Mah * prepare derivative works, distribute copies to the public, perform
22da9f046fSBruce A. Mah * publicly and display publicly, and to permit others to do so.
23da9f046fSBruce A. Mah *
24da9f046fSBruce A. Mah * This code is distributed under a BSD style license, see the LICENSE
25da9f046fSBruce A. Mah * file for complete information.
267d375156SJon Dugan */
273f8c33cdSBruce A. Mah #include "iperf_config.h"
287d375156SJon Dugan
290fdaab07SJon Dugan #include <stdio.h>
300fdaab07SJon Dugan #include <unistd.h>
319286415cSJon Dugan #include <errno.h>
32666040bdSXiang Xiao #include <arpa/inet.h>
330fdaab07SJon Dugan #include <sys/socket.h>
340fdaab07SJon Dugan #include <sys/types.h>
350fdaab07SJon Dugan #include <netinet/in.h>
36a951c980SBrian Tierney #include <assert.h>
370fdaab07SJon Dugan #include <netdb.h>
380fdaab07SJon Dugan #include <string.h>
39d88f4cecSPhilip Prindeville #include <fcntl.h>
40b481169aSBruce A. Mah #include <limits.h>
410fdaab07SJon Dugan
423f8c33cdSBruce A. Mah #ifdef HAVE_SENDFILE
43987b4323SJef Poskanzer #ifdef linux
44987b4323SJef Poskanzer #include <sys/sendfile.h>
45987b4323SJef Poskanzer #else
46987b4323SJef Poskanzer #ifdef __FreeBSD__
47987b4323SJef Poskanzer #include <sys/uio.h>
48987b4323SJef Poskanzer #else
493433c4d2SJef Poskanzer #if defined(__APPLE__) && defined(__MACH__) /* OS X */
503433c4d2SJef Poskanzer #include <AvailabilityMacros.h>
513433c4d2SJef Poskanzer #if defined(MAC_OS_X_VERSION_10_6)
52987b4323SJef Poskanzer #include <sys/uio.h>
53987b4323SJef Poskanzer #endif
54987b4323SJef Poskanzer #endif
55987b4323SJef Poskanzer #endif
563433c4d2SJef Poskanzer #endif
577f636033SBruce A. Mah #endif /* HAVE_SENDFILE */
58987b4323SJef Poskanzer
599d7d60acSBruce A. Mah #ifdef HAVE_POLL_H
609d7d60acSBruce A. Mah #include <poll.h>
619d7d60acSBruce A. Mah #endif /* HAVE_POLL_H */
629d7d60acSBruce A. Mah
6321581a72SBruce A. Mah #include "iperf.h"
649673370fSJef Poskanzer #include "iperf_util.h"
65c00858d2SBrian Tierney #include "net.h"
66c00858d2SBrian Tierney #include "timer.h"
67c00858d2SBrian Tierney
689d7d60acSBruce A. Mah /*
6938bac802SBruce A. Mah * Declaration of gerror in iperf_error.c. Most other files in iperf3 can get this
7038bac802SBruce A. Mah * by including "iperf.h", but net.c lives "below" this layer. Clearly the
7138bac802SBruce A. Mah * presence of this declaration is a sign we need to revisit this layering.
7238bac802SBruce A. Mah */
7338bac802SBruce A. Mah extern int gerror;
7438bac802SBruce A. Mah
7538bac802SBruce A. Mah /*
769d7d60acSBruce A. Mah * timeout_connect adapted from netcat, via OpenBSD and FreeBSD
779d7d60acSBruce A. Mah * Copyright (c) 2001 Eric Jackson <[email protected]>
789d7d60acSBruce A. Mah */
799d7d60acSBruce A. Mah int
timeout_connect(int s,const struct sockaddr * name,socklen_t namelen,int timeout)809d7d60acSBruce A. Mah timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
819d7d60acSBruce A. Mah int timeout)
829d7d60acSBruce A. Mah {
839d7d60acSBruce A. Mah struct pollfd pfd;
849d7d60acSBruce A. Mah socklen_t optlen;
859d7d60acSBruce A. Mah int flags, optval;
869d7d60acSBruce A. Mah int ret;
879d7d60acSBruce A. Mah
887a15a7aeSBruce A. Mah flags = 0;
899d7d60acSBruce A. Mah if (timeout != -1) {
909d7d60acSBruce A. Mah flags = fcntl(s, F_GETFL, 0);
919d7d60acSBruce A. Mah if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1)
929d7d60acSBruce A. Mah return -1;
939d7d60acSBruce A. Mah }
949d7d60acSBruce A. Mah
959d7d60acSBruce A. Mah if ((ret = connect(s, name, namelen)) != 0 && errno == EINPROGRESS) {
969d7d60acSBruce A. Mah pfd.fd = s;
979d7d60acSBruce A. Mah pfd.events = POLLOUT;
989d7d60acSBruce A. Mah if ((ret = poll(&pfd, 1, timeout)) == 1) {
999d7d60acSBruce A. Mah optlen = sizeof(optval);
1009d7d60acSBruce A. Mah if ((ret = getsockopt(s, SOL_SOCKET, SO_ERROR,
1019d7d60acSBruce A. Mah &optval, &optlen)) == 0) {
1029d7d60acSBruce A. Mah errno = optval;
1039d7d60acSBruce A. Mah ret = optval == 0 ? 0 : -1;
1049d7d60acSBruce A. Mah }
1059d7d60acSBruce A. Mah } else if (ret == 0) {
1069d7d60acSBruce A. Mah errno = ETIMEDOUT;
1079d7d60acSBruce A. Mah ret = -1;
1089d7d60acSBruce A. Mah } else
1099d7d60acSBruce A. Mah ret = -1;
1109d7d60acSBruce A. Mah }
1119d7d60acSBruce A. Mah
1129d7d60acSBruce A. Mah if (timeout != -1 && fcntl(s, F_SETFL, flags) == -1)
1139d7d60acSBruce A. Mah ret = -1;
1149d7d60acSBruce A. Mah
1159d7d60acSBruce A. Mah return (ret);
1169d7d60acSBruce A. Mah }
1179d7d60acSBruce A. Mah
118e99faeaeSBrian Tierney /* netdial and netannouce code comes from libtask: http://swtch.com/libtask/
119e99faeaeSBrian Tierney * Copyright: http://swtch.com/libtask/COPYRIGHT
120e99faeaeSBrian Tierney */
121e99faeaeSBrian Tierney
122b915645aSShuo Chen /* create a socket */
1230fdaab07SJon Dugan int
create_socket(int domain,int proto,const char * local,const char * bind_dev,int local_port,const char * server,int port,struct addrinfo ** server_res_out)124b915645aSShuo Chen create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out)
1250fdaab07SJon Dugan {
12621581a72SBruce A. Mah struct addrinfo hints, *local_res = NULL, *server_res = NULL;
127b6072241STodd C. Miller int s, saved_errno;
128b915645aSShuo Chen char portstr[6];
129982c704aSsethdelliott
130a1344edeSsethdelliott if (local) {
1315e0e1e97Ssethdelliott memset(&hints, 0, sizeof(hints));
132f99bd3b2Ssethdelliott hints.ai_family = domain;
1335e0e1e97Ssethdelliott hints.ai_socktype = proto;
13438bac802SBruce A. Mah if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
135ec2d0670SJef Poskanzer return -1;
1365e0e1e97Ssethdelliott }
1375e0e1e97Ssethdelliott
1385e0e1e97Ssethdelliott memset(&hints, 0, sizeof(hints));
139f99bd3b2Ssethdelliott hints.ai_family = domain;
1405e0e1e97Ssethdelliott hints.ai_socktype = proto;
141b915645aSShuo Chen snprintf(portstr, sizeof(portstr), "%d", port);
142b915645aSShuo Chen if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) {
143b915645aSShuo Chen if (local)
144b915645aSShuo Chen freeaddrinfo(local_res);
145ec2d0670SJef Poskanzer return -1;
146b915645aSShuo Chen }
1475e0e1e97Ssethdelliott
148a6b3f26bSJef Poskanzer s = socket(server_res->ai_family, proto, 0);
14932ebd649SJef Poskanzer if (s < 0) {
15032ebd649SJef Poskanzer if (local)
15132ebd649SJef Poskanzer freeaddrinfo(local_res);
15232ebd649SJef Poskanzer freeaddrinfo(server_res);
153ec2d0670SJef Poskanzer return -1;
15432ebd649SJef Poskanzer }
155a6b3f26bSJef Poskanzer
15621581a72SBruce A. Mah if (bind_dev) {
15721581a72SBruce A. Mah #if defined(HAVE_SO_BINDTODEVICE)
15821581a72SBruce A. Mah if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
15921581a72SBruce A. Mah bind_dev, IFNAMSIZ) < 0)
16021581a72SBruce A. Mah #endif // HAVE_SO_BINDTODEVICE
16121581a72SBruce A. Mah {
16221581a72SBruce A. Mah saved_errno = errno;
16321581a72SBruce A. Mah close(s);
16421581a72SBruce A. Mah freeaddrinfo(local_res);
16521581a72SBruce A. Mah freeaddrinfo(server_res);
16621581a72SBruce A. Mah errno = saved_errno;
16721581a72SBruce A. Mah return -1;
16821581a72SBruce A. Mah }
16921581a72SBruce A. Mah }
17021581a72SBruce A. Mah
171e7aa59b6SBruce A. Mah /* Bind the local address if given a name (with or without --cport) */
172a6b3f26bSJef Poskanzer if (local) {
173023fb45eSKevin Constantine if (local_port) {
174023fb45eSKevin Constantine struct sockaddr_in *lcladdr;
175023fb45eSKevin Constantine lcladdr = (struct sockaddr_in *)local_res->ai_addr;
176023fb45eSKevin Constantine lcladdr->sin_port = htons(local_port);
177023fb45eSKevin Constantine }
178023fb45eSKevin Constantine
17932ebd649SJef Poskanzer if (bind(s, (struct sockaddr *) local_res->ai_addr, local_res->ai_addrlen) < 0) {
180b6072241STodd C. Miller saved_errno = errno;
18132ebd649SJef Poskanzer close(s);
18232ebd649SJef Poskanzer freeaddrinfo(local_res);
18332ebd649SJef Poskanzer freeaddrinfo(server_res);
184b6072241STodd C. Miller errno = saved_errno;
185a6b3f26bSJef Poskanzer return -1;
18632ebd649SJef Poskanzer }
187a6b3f26bSJef Poskanzer freeaddrinfo(local_res);
188a1344edeSsethdelliott }
189e7aa59b6SBruce A. Mah /* No local name, but --cport given */
190e7aa59b6SBruce A. Mah else if (local_port) {
191e7aa59b6SBruce A. Mah size_t addrlen;
192e7aa59b6SBruce A. Mah struct sockaddr_storage lcl;
193e7aa59b6SBruce A. Mah
194e7aa59b6SBruce A. Mah /* IPv4 */
195e7aa59b6SBruce A. Mah if (server_res->ai_family == AF_INET) {
196e7aa59b6SBruce A. Mah struct sockaddr_in *lcladdr = (struct sockaddr_in *) &lcl;
197e7aa59b6SBruce A. Mah lcladdr->sin_family = AF_INET;
198e7aa59b6SBruce A. Mah lcladdr->sin_port = htons(local_port);
199e7aa59b6SBruce A. Mah lcladdr->sin_addr.s_addr = INADDR_ANY;
200e7aa59b6SBruce A. Mah addrlen = sizeof(struct sockaddr_in);
201e7aa59b6SBruce A. Mah }
202e7aa59b6SBruce A. Mah /* IPv6 */
203e7aa59b6SBruce A. Mah else if (server_res->ai_family == AF_INET6) {
204e7aa59b6SBruce A. Mah struct sockaddr_in6 *lcladdr = (struct sockaddr_in6 *) &lcl;
205e7aa59b6SBruce A. Mah lcladdr->sin6_family = AF_INET6;
206e7aa59b6SBruce A. Mah lcladdr->sin6_port = htons(local_port);
207e7aa59b6SBruce A. Mah lcladdr->sin6_addr = in6addr_any;
208e7aa59b6SBruce A. Mah addrlen = sizeof(struct sockaddr_in6);
209e7aa59b6SBruce A. Mah }
210e7aa59b6SBruce A. Mah /* Unknown protocol */
211e7aa59b6SBruce A. Mah else {
212b915645aSShuo Chen close(s);
213b915645aSShuo Chen freeaddrinfo(server_res);
214e7aa59b6SBruce A. Mah errno = EAFNOSUPPORT;
215e7aa59b6SBruce A. Mah return -1;
216e7aa59b6SBruce A. Mah }
217e7aa59b6SBruce A. Mah
218e7aa59b6SBruce A. Mah if (bind(s, (struct sockaddr *) &lcl, addrlen) < 0) {
219e7aa59b6SBruce A. Mah saved_errno = errno;
220e7aa59b6SBruce A. Mah close(s);
221e7aa59b6SBruce A. Mah freeaddrinfo(server_res);
222e7aa59b6SBruce A. Mah errno = saved_errno;
223e7aa59b6SBruce A. Mah return -1;
224e7aa59b6SBruce A. Mah }
225e7aa59b6SBruce A. Mah }
226a1344edeSsethdelliott
227b915645aSShuo Chen *server_res_out = server_res;
228b915645aSShuo Chen return s;
229b915645aSShuo Chen }
230b915645aSShuo Chen
231b915645aSShuo Chen /* make connection to server */
232b915645aSShuo Chen int
netdial(int domain,int proto,const char * local,const char * bind_dev,int local_port,const char * server,int port,int timeout)233b915645aSShuo Chen netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout)
234b915645aSShuo Chen {
235b915645aSShuo Chen struct addrinfo *server_res = NULL;
236b915645aSShuo Chen int s, saved_errno;
237b915645aSShuo Chen
238b915645aSShuo Chen s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res);
239b915645aSShuo Chen if (s < 0) {
240b915645aSShuo Chen return -1;
241b915645aSShuo Chen }
242b915645aSShuo Chen
2439d7d60acSBruce A. Mah if (timeout_connect(s, (struct sockaddr *) server_res->ai_addr, server_res->ai_addrlen, timeout) < 0 && errno != EINPROGRESS) {
244b6072241STodd C. Miller saved_errno = errno;
24532ebd649SJef Poskanzer close(s);
24632ebd649SJef Poskanzer freeaddrinfo(server_res);
247b6072241STodd C. Miller errno = saved_errno;
248a6b3f26bSJef Poskanzer return -1;
24932ebd649SJef Poskanzer }
250982c704aSsethdelliott
251a6b3f26bSJef Poskanzer freeaddrinfo(server_res);
252ec2d0670SJef Poskanzer return s;
2538556db5dSsethdelliott }
2548556db5dSsethdelliott
255a951c980SBrian Tierney /***************************************************************/
256a951c980SBrian Tierney
2570fdaab07SJon Dugan int
netannounce(int domain,int proto,const char * local,const char * bind_dev,int port)25821581a72SBruce A. Mah netannounce(int domain, int proto, const char *local, const char *bind_dev, int port)
2590fdaab07SJon Dugan {
2605e0e1e97Ssethdelliott struct addrinfo hints, *res;
2615e0e1e97Ssethdelliott char portstr[6];
262b6072241STodd C. Miller int s, opt, saved_errno;
2630fdaab07SJon Dugan
2645e0e1e97Ssethdelliott snprintf(portstr, 6, "%d", port);
2655e0e1e97Ssethdelliott memset(&hints, 0, sizeof(hints));
26676b5942fSBruce A. Mah /*
26776b5942fSBruce A. Mah * If binding to the wildcard address with no explicit address
26876b5942fSBruce A. Mah * family specified, then force us to get an AF_INET6 socket. On
26976b5942fSBruce A. Mah * CentOS 6 and MacOS, getaddrinfo(3) with AF_UNSPEC in ai_family,
27076b5942fSBruce A. Mah * and ai_flags containing AI_PASSIVE returns a result structure
27176b5942fSBruce A. Mah * with ai_family set to AF_INET, with the result that we create
27276b5942fSBruce A. Mah * and bind an IPv4 address wildcard address and by default, we
27376b5942fSBruce A. Mah * can't accept IPv6 connections.
27476b5942fSBruce A. Mah *
27576b5942fSBruce A. Mah * On FreeBSD, under the above circumstances, ai_family in the
27676b5942fSBruce A. Mah * result structure is set to AF_INET6.
27776b5942fSBruce A. Mah */
27876b5942fSBruce A. Mah if (domain == AF_UNSPEC && !local) {
27976b5942fSBruce A. Mah hints.ai_family = AF_INET6;
28076b5942fSBruce A. Mah }
28176b5942fSBruce A. Mah else {
2825b760eefSBruce A. Mah hints.ai_family = domain;
28376b5942fSBruce A. Mah }
2845e0e1e97Ssethdelliott hints.ai_socktype = proto;
2855e0e1e97Ssethdelliott hints.ai_flags = AI_PASSIVE;
28638bac802SBruce A. Mah if ((gerror = getaddrinfo(local, portstr, &hints, &res)) != 0)
287ec2d0670SJef Poskanzer return -1;
288a1344edeSsethdelliott
289a6b3f26bSJef Poskanzer s = socket(res->ai_family, proto, 0);
29032ebd649SJef Poskanzer if (s < 0) {
29132ebd649SJef Poskanzer freeaddrinfo(res);
292a6b3f26bSJef Poskanzer return -1;
29332ebd649SJef Poskanzer }
294a6b3f26bSJef Poskanzer
29521581a72SBruce A. Mah if (bind_dev) {
29621581a72SBruce A. Mah #if defined(HAVE_SO_BINDTODEVICE)
29721581a72SBruce A. Mah if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
29821581a72SBruce A. Mah bind_dev, IFNAMSIZ) < 0)
29921581a72SBruce A. Mah #endif // HAVE_SO_BINDTODEVICE
30021581a72SBruce A. Mah {
30121581a72SBruce A. Mah saved_errno = errno;
30221581a72SBruce A. Mah close(s);
30321581a72SBruce A. Mah freeaddrinfo(res);
30421581a72SBruce A. Mah errno = saved_errno;
30521581a72SBruce A. Mah return -1;
30621581a72SBruce A. Mah }
30721581a72SBruce A. Mah }
30821581a72SBruce A. Mah
309a6b3f26bSJef Poskanzer opt = 1;
310cfe8c5fbSBruce A. Mah if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
311cfe8c5fbSBruce A. Mah (char *) &opt, sizeof(opt)) < 0) {
312b6072241STodd C. Miller saved_errno = errno;
313cfe8c5fbSBruce A. Mah close(s);
314cfe8c5fbSBruce A. Mah freeaddrinfo(res);
315b6072241STodd C. Miller errno = saved_errno;
316cfe8c5fbSBruce A. Mah return -1;
317cfe8c5fbSBruce A. Mah }
31876b5942fSBruce A. Mah /*
31976b5942fSBruce A. Mah * If we got an IPv6 socket, figure out if it should accept IPv4
32076b5942fSBruce A. Mah * connections as well. We do that if and only if no address
321bef5ef87SBruce A. Mah * family was specified explicitly. Note that we can only
322bef5ef87SBruce A. Mah * do this if the IPV6_V6ONLY socket option is supported. Also,
323bef5ef87SBruce A. Mah * OpenBSD explicitly omits support for IPv4-mapped addresses,
324bef5ef87SBruce A. Mah * even though it implements IPV6_V6ONLY.
32576b5942fSBruce A. Mah */
326bef5ef87SBruce A. Mah #if defined(IPV6_V6ONLY) && !defined(__OpenBSD__)
3275b760eefSBruce A. Mah if (res->ai_family == AF_INET6 && (domain == AF_UNSPEC || domain == AF_INET6)) {
328a6b3f26bSJef Poskanzer if (domain == AF_UNSPEC)
329a6b3f26bSJef Poskanzer opt = 0;
3305b760eefSBruce A. Mah else
331a6b3f26bSJef Poskanzer opt = 1;
332cfe8c5fbSBruce A. Mah if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
333cfe8c5fbSBruce A. Mah (char *) &opt, sizeof(opt)) < 0) {
334b6072241STodd C. Miller saved_errno = errno;
335cfe8c5fbSBruce A. Mah close(s);
336cfe8c5fbSBruce A. Mah freeaddrinfo(res);
337b6072241STodd C. Miller errno = saved_errno;
338cfe8c5fbSBruce A. Mah return -1;
339cfe8c5fbSBruce A. Mah }
340a6b3f26bSJef Poskanzer }
341147d3369SBruce A. Mah #endif /* IPV6_V6ONLY */
342a6b3f26bSJef Poskanzer
3435e0e1e97Ssethdelliott if (bind(s, (struct sockaddr *) res->ai_addr, res->ai_addrlen) < 0) {
344b6072241STodd C. Miller saved_errno = errno;
3450fdaab07SJon Dugan close(s);
34632ebd649SJef Poskanzer freeaddrinfo(res);
347b6072241STodd C. Miller errno = saved_errno;
348ec2d0670SJef Poskanzer return -1;
3490fdaab07SJon Dugan }
350982c704aSsethdelliott
3515e0e1e97Ssethdelliott freeaddrinfo(res);
3525e0e1e97Ssethdelliott
353b60a49ddSsethdelliott if (proto == SOCK_STREAM) {
354b481169aSBruce A. Mah if (listen(s, INT_MAX) < 0) {
355b6072241STodd C. Miller saved_errno = errno;
35632ebd649SJef Poskanzer close(s);
357b6072241STodd C. Miller errno = saved_errno;
358ec2d0670SJef Poskanzer return -1;
359b60a49ddSsethdelliott }
360b60a49ddSsethdelliott }
3610fdaab07SJon Dugan
362ec2d0670SJef Poskanzer return s;
3630fdaab07SJon Dugan }
364c00858d2SBrian Tierney
365c00858d2SBrian Tierney
366c00858d2SBrian Tierney /*******************************************************************/
367987b4323SJef Poskanzer /* reads 'count' bytes from a socket */
368c00858d2SBrian Tierney /********************************************************************/
369c00858d2SBrian Tierney
370c00858d2SBrian Tierney int
Nread(int fd,char * buf,size_t count,int prot)371987b4323SJef Poskanzer Nread(int fd, char *buf, size_t count, int prot)
372c00858d2SBrian Tierney {
373987b4323SJef Poskanzer register ssize_t r;
374987b4323SJef Poskanzer register size_t nleft = count;
375982c704aSsethdelliott
376fd10304cSsethdelliott while (nleft > 0) {
377c57e9f24SJef Poskanzer r = read(fd, buf, nleft);
378c57e9f24SJef Poskanzer if (r < 0) {
37925eb62c7SBruce A. Mah if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
380081ba8e4SBruce A. Mah break;
381fd10304cSsethdelliott else
38243929b36SJef Poskanzer return NET_HARDERROR;
383987b4323SJef Poskanzer } else if (r == 0)
384fd10304cSsethdelliott break;
385fd10304cSsethdelliott
386987b4323SJef Poskanzer nleft -= r;
387987b4323SJef Poskanzer buf += r;
388c00858d2SBrian Tierney }
389ec2d0670SJef Poskanzer return count - nleft;
390c00858d2SBrian Tierney }
391c00858d2SBrian Tierney
392c00858d2SBrian Tierney
393c00858d2SBrian Tierney /*
394c00858d2SBrian Tierney * N W R I T E
395c00858d2SBrian Tierney */
396fd10304cSsethdelliott
397c00858d2SBrian Tierney int
Nwrite(int fd,const char * buf,size_t count,int prot)398987b4323SJef Poskanzer Nwrite(int fd, const char *buf, size_t count, int prot)
399c00858d2SBrian Tierney {
400987b4323SJef Poskanzer register ssize_t r;
401987b4323SJef Poskanzer register size_t nleft = count;
402fd10304cSsethdelliott
403fd10304cSsethdelliott while (nleft > 0) {
404c57e9f24SJef Poskanzer r = write(fd, buf, nleft);
405c57e9f24SJef Poskanzer if (r < 0) {
40643929b36SJef Poskanzer switch (errno) {
40743929b36SJef Poskanzer case EINTR:
408081ba8e4SBruce A. Mah case EAGAIN:
40925eb62c7SBruce A. Mah #if (EAGAIN != EWOULDBLOCK)
41025eb62c7SBruce A. Mah case EWOULDBLOCK:
41125eb62c7SBruce A. Mah #endif
41243929b36SJef Poskanzer return count - nleft;
41343929b36SJef Poskanzer
41443929b36SJef Poskanzer case ENOBUFS:
41543929b36SJef Poskanzer return NET_SOFTERROR;
41643929b36SJef Poskanzer
41743929b36SJef Poskanzer default:
41843929b36SJef Poskanzer return NET_HARDERROR;
419c00858d2SBrian Tierney }
420c57e9f24SJef Poskanzer } else if (r == 0)
421c57e9f24SJef Poskanzer return NET_SOFTERROR;
422987b4323SJef Poskanzer nleft -= r;
423987b4323SJef Poskanzer buf += r;
424987b4323SJef Poskanzer }
425987b4323SJef Poskanzer return count;
426987b4323SJef Poskanzer }
427987b4323SJef Poskanzer
428987b4323SJef Poskanzer
429987b4323SJef Poskanzer int
has_sendfile(void)430987b4323SJef Poskanzer has_sendfile(void)
431987b4323SJef Poskanzer {
43278525e46Scarlsborg #if defined(HAVE_SENDFILE)
433987b4323SJef Poskanzer return 1;
43478525e46Scarlsborg #else /* HAVE_SENDFILE */
435987b4323SJef Poskanzer return 0;
43678525e46Scarlsborg #endif /* HAVE_SENDFILE */
4373f8c33cdSBruce A. Mah
438987b4323SJef Poskanzer }
439987b4323SJef Poskanzer
440987b4323SJef Poskanzer
441987b4323SJef Poskanzer /*
442987b4323SJef Poskanzer * N S E N D F I L E
443987b4323SJef Poskanzer */
444987b4323SJef Poskanzer
445987b4323SJef Poskanzer int
Nsendfile(int fromfd,int tofd,const char * buf,size_t count)446987b4323SJef Poskanzer Nsendfile(int fromfd, int tofd, const char *buf, size_t count)
447987b4323SJef Poskanzer {
4483f8c33cdSBruce A. Mah #if defined(HAVE_SENDFILE)
449*8e0a54ebSMarcin Niestroj off_t offset;
450c39c4f50SJef Poskanzer #if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6))
451987b4323SJef Poskanzer off_t sent;
452987b4323SJef Poskanzer #endif
453987b4323SJef Poskanzer register size_t nleft;
454987b4323SJef Poskanzer register ssize_t r;
455987b4323SJef Poskanzer
456987b4323SJef Poskanzer nleft = count;
457987b4323SJef Poskanzer while (nleft > 0) {
458987b4323SJef Poskanzer offset = count - nleft;
459987b4323SJef Poskanzer #ifdef linux
460987b4323SJef Poskanzer r = sendfile(tofd, fromfd, &offset, nleft);
461588ee522SBrian Candler if (r > 0)
462588ee522SBrian Candler nleft -= r;
463588ee522SBrian Candler #elif defined(__FreeBSD__)
464987b4323SJef Poskanzer r = sendfile(fromfd, tofd, offset, nleft, NULL, &sent, 0);
465588ee522SBrian Candler nleft -= sent;
466588ee522SBrian Candler #elif defined(__APPLE__) && defined(__MACH__) && defined(MAC_OS_X_VERSION_10_6) /* OS X */
467987b4323SJef Poskanzer sent = nleft;
468987b4323SJef Poskanzer r = sendfile(fromfd, tofd, offset, &sent, NULL, 0);
469588ee522SBrian Candler nleft -= sent;
470987b4323SJef Poskanzer #else
471987b4323SJef Poskanzer /* Shouldn't happen. */
472987b4323SJef Poskanzer r = -1;
473987b4323SJef Poskanzer errno = ENOSYS;
474987b4323SJef Poskanzer #endif
475987b4323SJef Poskanzer if (r < 0) {
476987b4323SJef Poskanzer switch (errno) {
477987b4323SJef Poskanzer case EINTR:
478081ba8e4SBruce A. Mah case EAGAIN:
47925eb62c7SBruce A. Mah #if (EAGAIN != EWOULDBLOCK)
48025eb62c7SBruce A. Mah case EWOULDBLOCK:
48125eb62c7SBruce A. Mah #endif
482a80368bbSBrian Candler if (count == nleft)
483a80368bbSBrian Candler return NET_SOFTERROR;
484987b4323SJef Poskanzer return count - nleft;
485987b4323SJef Poskanzer
486987b4323SJef Poskanzer case ENOBUFS:
487987b4323SJef Poskanzer case ENOMEM:
488987b4323SJef Poskanzer return NET_SOFTERROR;
489987b4323SJef Poskanzer
490987b4323SJef Poskanzer default:
491987b4323SJef Poskanzer return NET_HARDERROR;
492987b4323SJef Poskanzer }
493588ee522SBrian Candler }
494588ee522SBrian Candler #ifdef linux
495588ee522SBrian Candler else if (r == 0)
496c57e9f24SJef Poskanzer return NET_SOFTERROR;
497588ee522SBrian Candler #endif
498c00858d2SBrian Tierney }
499ec2d0670SJef Poskanzer return count;
5009ac254daSBruce A. Mah #else /* HAVE_SENDFILE */
5019ac254daSBruce A. Mah errno = ENOSYS; /* error if somehow get called without HAVE_SENDFILE */
502588ee522SBrian Candler return NET_HARDERROR;
5039ac254daSBruce A. Mah #endif /* HAVE_SENDFILE */
504fd10304cSsethdelliott }
505a951c980SBrian Tierney
506a951c980SBrian Tierney /*************************************************************************/
507a951c980SBrian Tierney
508a951c980SBrian Tierney int
setnonblocking(int fd,int nonblocking)5090f53b154SJef Poskanzer setnonblocking(int fd, int nonblocking)
510a951c980SBrian Tierney {
5110da578e7SJef Poskanzer int flags, newflags;
512a951c980SBrian Tierney
5130da578e7SJef Poskanzer flags = fcntl(fd, F_GETFL, 0);
5140da578e7SJef Poskanzer if (flags < 0) {
5150da578e7SJef Poskanzer perror("fcntl(F_GETFL)");
5160da578e7SJef Poskanzer return -1;
5170da578e7SJef Poskanzer }
5180f53b154SJef Poskanzer if (nonblocking)
5190da578e7SJef Poskanzer newflags = flags | (int) O_NONBLOCK;
5200f53b154SJef Poskanzer else
5210f53b154SJef Poskanzer newflags = flags & ~((int) O_NONBLOCK);
5220da578e7SJef Poskanzer if (newflags != flags)
5230da578e7SJef Poskanzer if (fcntl(fd, F_SETFL, newflags) < 0) {
524a951c980SBrian Tierney perror("fcntl(F_SETFL)");
525a951c980SBrian Tierney return -1;
526a951c980SBrian Tierney }
527a951c980SBrian Tierney return 0;
528a951c980SBrian Tierney }
529a6b3f26bSJef Poskanzer
530a6b3f26bSJef Poskanzer /****************************************************************************/
531a6b3f26bSJef Poskanzer
532a6b3f26bSJef Poskanzer int
getsockdomain(int sock)533a6b3f26bSJef Poskanzer getsockdomain(int sock)
534a6b3f26bSJef Poskanzer {
535eb3faee6SMatthieu Coudron struct sockaddr_storage sa;
53678a71116SJef Poskanzer socklen_t len = sizeof(sa);
537a6b3f26bSJef Poskanzer
538eb3faee6SMatthieu Coudron if (getsockname(sock, (struct sockaddr *)&sa, &len) < 0) {
539a6b3f26bSJef Poskanzer return -1;
540eb3faee6SMatthieu Coudron }
541eb3faee6SMatthieu Coudron return ((struct sockaddr *) &sa)->sa_family;
542a6b3f26bSJef Poskanzer }
543