1999-12-02 02:42:23 -05:00
|
|
|
|
/* Establishing and handling network connections.
|
2002-01-24 22:34:23 -05:00
|
|
|
|
Copyright (C) 1995, 1996, 1997, 2001, 2002 Free Software Foundation, Inc.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
This file is part of GNU Wget.
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
GNU Wget is free software; you can redistribute it and/or modify
|
1999-12-02 02:42:23 -05:00
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
2001-05-27 15:35:15 -04:00
|
|
|
|
GNU Wget is distributed in the hope that it will be useful,
|
1999-12-02 02:42:23 -05:00
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2001-05-27 15:35:15 -04:00
|
|
|
|
along with Wget; if not, write to the Free Software
|
1999-12-02 02:42:23 -05:00
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
|
# include <unistd.h>
|
|
|
|
|
#endif
|
2001-11-26 00:36:33 -05:00
|
|
|
|
#include <assert.h>
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
#ifdef WINDOWS
|
|
|
|
|
# include <winsock.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/socket.h>
|
|
|
|
|
# include <netdb.h>
|
|
|
|
|
# include <netinet/in.h>
|
2001-11-16 11:58:08 -05:00
|
|
|
|
#ifndef __BEOS__
|
1999-12-02 02:42:23 -05:00
|
|
|
|
# include <arpa/inet.h>
|
2001-11-16 11:58:08 -05:00
|
|
|
|
#endif
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#endif /* WINDOWS */
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
# include <string.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <strings.h>
|
|
|
|
|
#endif /* HAVE_STRING_H */
|
|
|
|
|
#ifdef HAVE_SYS_SELECT_H
|
|
|
|
|
# include <sys/select.h>
|
|
|
|
|
#endif /* HAVE_SYS_SELECT_H */
|
|
|
|
|
|
|
|
|
|
#include "wget.h"
|
2002-04-13 18:18:28 -04:00
|
|
|
|
#include "utils.h"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#include "host.h"
|
2002-01-24 22:34:23 -05:00
|
|
|
|
#include "connect.h"
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
#ifndef errno
|
|
|
|
|
extern int errno;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Variables shared by bindport and acceptport: */
|
|
|
|
|
static int msock = -1;
|
|
|
|
|
static struct sockaddr *addr;
|
|
|
|
|
|
2002-01-24 22:34:23 -05:00
|
|
|
|
static ip_address bind_address;
|
|
|
|
|
static int bind_address_resolved;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
resolve_bind_address (void)
|
|
|
|
|
{
|
|
|
|
|
struct address_list *al;
|
|
|
|
|
|
|
|
|
|
if (bind_address_resolved || opt.bind_address == NULL)
|
|
|
|
|
/* Nothing to do. */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
al = lookup_host (opt.bind_address, 1);
|
|
|
|
|
if (!al)
|
|
|
|
|
{
|
|
|
|
|
logprintf (LOG_NOTQUIET,
|
|
|
|
|
_("Unable to convert `%s' to a bind address. Reverting to ANY.\n"),
|
|
|
|
|
opt.bind_address);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
address_list_copy_one (al, 0, &bind_address);
|
|
|
|
|
address_list_release (al);
|
|
|
|
|
bind_address_resolved = 1;
|
|
|
|
|
}
|
2002-04-11 21:14:18 -04:00
|
|
|
|
|
2002-04-13 18:18:28 -04:00
|
|
|
|
struct cwt_context {
|
|
|
|
|
int fd;
|
|
|
|
|
const struct sockaddr *addr;
|
|
|
|
|
int addrlen;
|
|
|
|
|
int result;
|
|
|
|
|
};
|
2002-04-11 21:14:18 -04:00
|
|
|
|
|
2002-04-13 18:18:28 -04:00
|
|
|
|
static void
|
|
|
|
|
connect_with_timeout_callback (void *arg)
|
2002-04-11 21:14:18 -04:00
|
|
|
|
{
|
2002-04-13 18:18:28 -04:00
|
|
|
|
struct cwt_context *ctx = (struct cwt_context *)arg;
|
|
|
|
|
ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
|
2002-04-11 21:14:18 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Like connect, but specifies a timeout. If connecting takes longer
|
|
|
|
|
than TIMEOUT seconds, -1 is returned and errno is set to
|
|
|
|
|
ETIMEDOUT. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
connect_with_timeout (int fd, const struct sockaddr *addr, int addrlen,
|
|
|
|
|
int timeout)
|
|
|
|
|
{
|
2002-04-13 18:18:28 -04:00
|
|
|
|
struct cwt_context ctx;
|
|
|
|
|
ctx.fd = fd;
|
|
|
|
|
ctx.addr = addr;
|
|
|
|
|
ctx.addrlen = addrlen;
|
2002-01-24 22:34:23 -05:00
|
|
|
|
|
2002-04-13 18:18:28 -04:00
|
|
|
|
if (run_with_timeout (timeout, connect_with_timeout_callback, &ctx))
|
2002-04-11 21:14:18 -04:00
|
|
|
|
{
|
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2002-04-13 18:18:28 -04:00
|
|
|
|
if (ctx.result == -1 && errno == EINTR)
|
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
return ctx.result;
|
2002-04-11 21:14:18 -04:00
|
|
|
|
}
|
|
|
|
|
|
2001-11-26 00:36:33 -05:00
|
|
|
|
/* A kludge, but still better than passing the host name all the way
|
|
|
|
|
to connect_to_one. */
|
|
|
|
|
static const char *connection_host_name;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2001-11-26 00:36:33 -05:00
|
|
|
|
void
|
|
|
|
|
set_connection_host_name (const char *host)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
2001-11-26 00:36:33 -05:00
|
|
|
|
if (host)
|
|
|
|
|
assert (connection_host_name == NULL);
|
|
|
|
|
else
|
|
|
|
|
assert (connection_host_name != NULL);
|
2001-11-25 12:13:20 -05:00
|
|
|
|
|
2001-11-26 00:36:33 -05:00
|
|
|
|
connection_host_name = host;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Connect to a remote host whose address has been resolved. */
|
2001-11-27 07:49:13 -05:00
|
|
|
|
int
|
2002-01-24 00:45:54 -05:00
|
|
|
|
connect_to_one (ip_address *addr, unsigned short port, int silent)
|
2001-11-26 00:36:33 -05:00
|
|
|
|
{
|
2002-01-24 00:45:54 -05:00
|
|
|
|
wget_sockaddr sa;
|
2001-11-26 00:36:33 -05:00
|
|
|
|
int sock, save_errno;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
/* Set port and protocol */
|
2002-01-24 00:45:54 -05:00
|
|
|
|
wget_sockaddr_set_address (&sa, ip_default_family, port, addr);
|
2001-11-26 00:36:33 -05:00
|
|
|
|
|
|
|
|
|
if (!silent)
|
|
|
|
|
{
|
|
|
|
|
char *pretty_addr = pretty_print_address (addr);
|
|
|
|
|
if (connection_host_name
|
|
|
|
|
&& 0 != strcmp (connection_host_name, pretty_addr))
|
|
|
|
|
logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
|
|
|
|
|
connection_host_name, pretty_addr, port);
|
|
|
|
|
else
|
|
|
|
|
logprintf (LOG_VERBOSE, _("Connecting to %s:%hu... "),
|
|
|
|
|
pretty_addr, port);
|
|
|
|
|
}
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
/* Make an internet socket, stream type. */
|
2002-01-24 00:45:54 -05:00
|
|
|
|
sock = socket (ip_default_family, SOCK_STREAM, 0);
|
2001-11-26 00:36:33 -05:00
|
|
|
|
if (sock < 0)
|
|
|
|
|
goto out;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2002-01-24 22:34:23 -05:00
|
|
|
|
resolve_bind_address ();
|
|
|
|
|
if (bind_address_resolved)
|
2000-10-24 02:19:17 -04:00
|
|
|
|
{
|
|
|
|
|
/* Bind the client side to the requested address. */
|
2002-01-24 22:34:23 -05:00
|
|
|
|
wget_sockaddr bsa;
|
|
|
|
|
wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address);
|
|
|
|
|
if (bind (sock, &bsa.sa, sockaddr_len ()))
|
2001-11-26 00:36:33 -05:00
|
|
|
|
{
|
|
|
|
|
close (sock);
|
|
|
|
|
sock = -1;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2000-10-24 02:19:17 -04:00
|
|
|
|
}
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Connect the socket to the remote host. */
|
2002-04-11 21:14:18 -04:00
|
|
|
|
if (connect_with_timeout (sock, &sa.sa, sockaddr_len (), opt.timeout) < 0)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
2001-11-26 00:36:33 -05:00
|
|
|
|
close (sock);
|
|
|
|
|
sock = -1;
|
|
|
|
|
goto out;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
2001-11-26 00:36:33 -05:00
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (sock >= 0)
|
|
|
|
|
{
|
|
|
|
|
/* Success. */
|
|
|
|
|
if (!silent)
|
|
|
|
|
logprintf (LOG_VERBOSE, _("connected.\n"));
|
|
|
|
|
DEBUGP (("Created socket %d.\n", sock));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
save_errno = errno;
|
|
|
|
|
if (!silent)
|
|
|
|
|
logprintf (LOG_VERBOSE, "failed: %s.\n", strerror (errno));
|
|
|
|
|
errno = save_errno;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sock;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Connect to a remote host whose address has been resolved. */
|
|
|
|
|
int
|
|
|
|
|
connect_to_many (struct address_list *al, unsigned short port, int silent)
|
|
|
|
|
{
|
2001-11-27 09:55:40 -05:00
|
|
|
|
int i, start, end;
|
2001-11-26 00:36:33 -05:00
|
|
|
|
|
2001-11-27 09:55:40 -05:00
|
|
|
|
address_list_get_bounds (al, &start, &end);
|
|
|
|
|
for (i = start; i < end; i++)
|
2001-11-26 00:36:33 -05:00
|
|
|
|
{
|
2002-01-24 00:45:54 -05:00
|
|
|
|
ip_address addr;
|
2001-11-26 00:36:33 -05:00
|
|
|
|
int sock;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
address_list_copy_one (al, i, &addr);
|
2001-11-26 00:36:33 -05:00
|
|
|
|
|
2002-01-24 00:45:54 -05:00
|
|
|
|
sock = connect_to_one (&addr, port, silent);
|
2001-11-26 00:36:33 -05:00
|
|
|
|
if (sock >= 0)
|
2001-11-27 09:55:40 -05:00
|
|
|
|
/* Success. */
|
2001-11-26 00:36:33 -05:00
|
|
|
|
return sock;
|
|
|
|
|
|
2001-11-27 09:55:40 -05:00
|
|
|
|
address_list_set_faulty (al, i);
|
2001-11-26 00:36:33 -05:00
|
|
|
|
|
|
|
|
|
/* The attempt to connect has failed. Continue with the loop
|
|
|
|
|
and try next address. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
2000-11-19 15:50:10 -05:00
|
|
|
|
int
|
|
|
|
|
test_socket_open (int sock)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_SELECT
|
|
|
|
|
fd_set check_set;
|
|
|
|
|
struct timeval to;
|
|
|
|
|
|
|
|
|
|
/* Check if we still have a valid (non-EOF) connection. From Andrew
|
|
|
|
|
* Maholski's code in the Unix Socket FAQ. */
|
|
|
|
|
|
|
|
|
|
FD_ZERO (&check_set);
|
|
|
|
|
FD_SET (sock, &check_set);
|
|
|
|
|
|
|
|
|
|
/* Wait one microsecond */
|
|
|
|
|
to.tv_sec = 0;
|
|
|
|
|
to.tv_usec = 1;
|
|
|
|
|
|
|
|
|
|
/* If we get a timeout, then that means still connected */
|
|
|
|
|
if (select (sock + 1, &check_set, NULL, NULL, &to) == 0)
|
|
|
|
|
{
|
|
|
|
|
/* Connection is valid (not EOF), so continue */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
#else
|
|
|
|
|
/* Without select, it's hard to know for sure. */
|
|
|
|
|
return 1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
/* Bind the local port PORT. This does all the necessary work, which
|
|
|
|
|
is creating a socket, setting SO_REUSEADDR option on it, then
|
|
|
|
|
calling bind() and listen(). If *PORT is 0, a random port is
|
|
|
|
|
chosen by the system, and its value is stored to *PORT. The
|
|
|
|
|
internal variable MPORT is set to the value of the ensuing master
|
|
|
|
|
socket. Call acceptport() to block for and accept a connection. */
|
|
|
|
|
uerr_t
|
2002-01-24 00:45:54 -05:00
|
|
|
|
bindport (unsigned short *port, int family)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
int optval = 1;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
wget_sockaddr srv;
|
|
|
|
|
memset (&srv, 0, sizeof (wget_sockaddr));
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
msock = -1;
|
2002-01-24 00:45:54 -05:00
|
|
|
|
|
|
|
|
|
if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
return CONSOCKERR;
|
|
|
|
|
if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
|
(char *)&optval, sizeof (optval)) < 0)
|
|
|
|
|
return CONSOCKERR;
|
2000-10-24 02:19:17 -04:00
|
|
|
|
|
2002-01-24 22:34:23 -05:00
|
|
|
|
resolve_bind_address ();
|
|
|
|
|
wget_sockaddr_set_address (&srv, ip_default_family, htons (*port),
|
|
|
|
|
bind_address_resolved ? &bind_address : NULL);
|
2002-01-24 00:45:54 -05:00
|
|
|
|
if (bind (msock, &srv.sa, sockaddr_len ()) < 0)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
CLOSE (msock);
|
|
|
|
|
msock = -1;
|
|
|
|
|
return BINDERR;
|
|
|
|
|
}
|
|
|
|
|
DEBUGP (("Master socket fd %d bound.\n", msock));
|
|
|
|
|
if (!*port)
|
|
|
|
|
{
|
2001-01-10 10:06:00 -05:00
|
|
|
|
/* #### addrlen should be a 32-bit type, which int is not
|
|
|
|
|
guaranteed to be. Oh, and don't try to make it a size_t,
|
|
|
|
|
because that can be 64-bit. */
|
2002-01-24 00:45:54 -05:00
|
|
|
|
int sa_len = sockaddr_len ();
|
|
|
|
|
if (getsockname (msock, &srv.sa, &sa_len) < 0)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
|
|
|
|
CLOSE (msock);
|
|
|
|
|
msock = -1;
|
|
|
|
|
return CONPORTERR;
|
|
|
|
|
}
|
2002-01-24 00:45:54 -05:00
|
|
|
|
*port = wget_sockaddr_get_port (&srv);
|
|
|
|
|
DEBUGP (("using port %i.\n", *port));
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
if (listen (msock, 1) < 0)
|
|
|
|
|
{
|
|
|
|
|
CLOSE (msock);
|
|
|
|
|
msock = -1;
|
|
|
|
|
return LISTENERR;
|
|
|
|
|
}
|
|
|
|
|
return BINDOK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SELECT
|
2002-04-14 01:19:27 -04:00
|
|
|
|
/* Wait for file descriptor FD to be available, timing out after
|
|
|
|
|
MAXTIME seconds. "Available" means readable if writep is 0,
|
|
|
|
|
writeable otherwise.
|
|
|
|
|
|
|
|
|
|
Returns 1 if FD is available, 0 for timeout and -1 for error. */
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
2000-12-05 18:09:41 -05:00
|
|
|
|
int
|
1999-12-02 02:42:23 -05:00
|
|
|
|
select_fd (int fd, int maxtime, int writep)
|
|
|
|
|
{
|
2002-04-14 01:19:27 -04:00
|
|
|
|
fd_set fds;
|
|
|
|
|
fd_set *rd = NULL, *wrt = NULL;
|
|
|
|
|
struct timeval tmout;
|
|
|
|
|
int result;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
FD_ZERO (&fds);
|
|
|
|
|
FD_SET (fd, &fds);
|
2002-04-14 01:19:27 -04:00
|
|
|
|
*(writep ? &wrt : &rd) = &fds;
|
|
|
|
|
|
|
|
|
|
tmout.tv_sec = maxtime;
|
|
|
|
|
tmout.tv_usec = 0;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
result = select (fd + 1, rd, wrt, NULL, &tmout);
|
|
|
|
|
while (result < 0 && errno == EINTR);
|
|
|
|
|
|
|
|
|
|
/* When we've timed out, set errno to ETIMEDOUT for the convenience
|
|
|
|
|
of the caller. */
|
|
|
|
|
if (result == 0)
|
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
|
|
|
|
|
|
return result;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
#endif /* HAVE_SELECT */
|
|
|
|
|
|
|
|
|
|
/* Call accept() on MSOCK and store the result to *SOCK. This assumes
|
|
|
|
|
that bindport() has been used to initialize MSOCK to a correct
|
|
|
|
|
value. It blocks the caller until a connection is established. If
|
|
|
|
|
no connection is established for OPT.TIMEOUT seconds, the function
|
|
|
|
|
exits with an error status. */
|
|
|
|
|
uerr_t
|
|
|
|
|
acceptport (int *sock)
|
|
|
|
|
{
|
2002-01-24 00:45:54 -05:00
|
|
|
|
int addrlen = sockaddr_len ();
|
1999-12-02 02:42:23 -05:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SELECT
|
|
|
|
|
if (select_fd (msock, opt.timeout, 0) <= 0)
|
|
|
|
|
return ACCEPTERR;
|
|
|
|
|
#endif
|
|
|
|
|
if ((*sock = accept (msock, addr, &addrlen)) < 0)
|
|
|
|
|
return ACCEPTERR;
|
|
|
|
|
DEBUGP (("Created socket fd %d.\n", *sock));
|
|
|
|
|
return ACCEPTOK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close SOCK, as well as the most recently remembered MSOCK, created
|
|
|
|
|
via bindport(). If SOCK is -1, close MSOCK only. */
|
|
|
|
|
void
|
|
|
|
|
closeport (int sock)
|
|
|
|
|
{
|
|
|
|
|
/*shutdown (sock, 2);*/
|
|
|
|
|
if (sock != -1)
|
|
|
|
|
CLOSE (sock);
|
|
|
|
|
if (msock != -1)
|
|
|
|
|
CLOSE (msock);
|
|
|
|
|
msock = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-01-24 00:45:54 -05:00
|
|
|
|
/* Return the local IP address associated with the connection on FD. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
conaddr (int fd, ip_address *ip)
|
1999-12-02 02:42:23 -05:00
|
|
|
|
{
|
2002-01-24 00:45:54 -05:00
|
|
|
|
wget_sockaddr mysrv;
|
|
|
|
|
|
|
|
|
|
/* see bindport() for discussion of using `int' here. */
|
|
|
|
|
int addrlen = sizeof (mysrv);
|
|
|
|
|
|
|
|
|
|
if (getsockname (fd, &mysrv.sa, (int *)&addrlen) < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
switch (mysrv.sa.sa_family)
|
|
|
|
|
{
|
|
|
|
|
#ifdef INET6
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
memcpy (ip, &mysrv.sin6.sin6_addr, 16);
|
|
|
|
|
return 1;
|
|
|
|
|
#endif
|
|
|
|
|
case AF_INET:
|
|
|
|
|
map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip);
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read at most LEN bytes from FD, storing them to BUF. This is
|
|
|
|
|
virtually the same as read(), but takes care of EINTR braindamage
|
|
|
|
|
and uses select() to timeout the stale connections (a connection is
|
|
|
|
|
stale if more than OPT.TIMEOUT time is spent in select() or
|
|
|
|
|
read()). */
|
2002-04-14 01:19:27 -04:00
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
int
|
|
|
|
|
iread (int fd, char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SELECT
|
2002-04-14 01:19:27 -04:00
|
|
|
|
if (opt.timeout)
|
|
|
|
|
if (select_fd (fd, opt.timeout, 0) <= 0)
|
|
|
|
|
return -1;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#endif
|
2002-04-14 01:19:27 -04:00
|
|
|
|
do
|
|
|
|
|
res = READ (fd, buf, len);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
while (res == -1 && errno == EINTR);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write LEN bytes from BUF to FD. This is similar to iread(), but
|
2002-04-14 01:19:27 -04:00
|
|
|
|
unlike iread(), it makes sure that all of BUF is actually written
|
|
|
|
|
to FD, so callers needn't bother with checking that the return
|
|
|
|
|
value equals to LEN. Instead, you should simply check for -1. */
|
|
|
|
|
|
1999-12-02 02:42:23 -05:00
|
|
|
|
int
|
|
|
|
|
iwrite (int fd, char *buf, int len)
|
|
|
|
|
{
|
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
|
|
/* `write' may write less than LEN bytes, thus the outward loop
|
|
|
|
|
keeps trying it until all was written, or an error occurred. The
|
|
|
|
|
inner loop is reserved for the usual EINTR f*kage, and the
|
|
|
|
|
innermost loop deals with the same during select(). */
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_SELECT
|
2002-04-14 01:19:27 -04:00
|
|
|
|
if (opt.timeout)
|
|
|
|
|
if (select_fd (fd, opt.timeout, 1) <= 0)
|
|
|
|
|
return -1;
|
1999-12-02 02:42:23 -05:00
|
|
|
|
#endif
|
2002-04-14 01:19:27 -04:00
|
|
|
|
do
|
|
|
|
|
res = WRITE (fd, buf, len);
|
1999-12-02 02:42:23 -05:00
|
|
|
|
while (res == -1 && errno == EINTR);
|
|
|
|
|
if (res <= 0)
|
|
|
|
|
break;
|
|
|
|
|
buf += res;
|
|
|
|
|
len -= res;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|