+2003-11-13 Hrvoje Niksic <hniksic@xemacs.org>
+
+ * connect.c (bind_local): Renamed bindport to bind_local; return
+ the socket directly. Updated callers.
+ (accept_connection): Renamed acceptport to accept_connection;
+ return the created socket directly. Updated callers.
+
2003-11-13 Hrvoje Niksic <hniksic@xemacs.org>
* init.c (defaults): Turn on opt.ipv4_only if we're compiling with
#endif
}
-/* Create a socket and bind it to PORT locally. Calling accept() on
- such a socket waits for and accepts incoming TCP connections. The
- resulting socket is stored to LOCAL_SOCK. */
+/* Create a socket, bind it to local interface BIND_ADDRESS on port
+ *PORT, set up a listen backlog, and return the resulting socket, or
+ -1 in case of error.
-uerr_t
-bindport (const ip_address *bind_address, int *port, int *local_sock)
+ BIND_ADDRESS is the address of the interface to bind to. If it is
+ NULL, the socket is bound to the default address. PORT should
+ point to the port number that will be used for the binding. If
+ that number is 0, the system will choose a suitable port, and the
+ chosen value will be written to *PORT.
+
+ Calling accept() on such a socket waits for and accepts incoming
+ TCP connections. */
+
+int
+bind_local (const ip_address *bind_address, int *port)
{
int sock;
int family = AF_INET;
family = AF_INET6;
#endif
- if ((sock = socket (family, SOCK_STREAM, 0)) < 0)
- return CONSOCKERR;
+ sock = socket (family, SOCK_STREAM, 0);
+ if (sock < 0)
+ return -1;
#ifdef SO_REUSEADDR
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, setopt_ptr, setopt_size);
if (bind (sock, sa, sockaddr_size (sa)) < 0)
{
xclose (sock);
- return BINDERR;
+ return -1;
}
DEBUGP (("Local socket fd %d bound.\n", sock));
- if (!*port)
+
+ /* If *PORT is 0, find out which port we've bound to. */
+ if (*port == 0)
{
socklen_t sa_len = sockaddr_size (sa);
if (getsockname (sock, sa, &sa_len) < 0)
{
+ /* If we can't find out the socket's local address ("name"),
+ something is seriously wrong with the socket, and it's
+ unusable for us anyway because we must know the chosen
+ port. */
xclose (sock);
- return CONPORTERR;
+ return -1;
}
sockaddr_get_data (sa, NULL, port);
DEBUGP (("binding to address %s using port %i.\n",
if (listen (sock, 1) < 0)
{
xclose (sock);
- return LISTENERR;
+ return -1;
}
- *local_sock = sock;
- return BINDOK;
+ return sock;
}
#ifdef HAVE_SELECT
}
#endif /* HAVE_SELECT */
-/* Accept a connection on LOCAL_SOCK, and store the new socket to
- *SOCK. It blocks the caller until a connection is established. If
- no connection is established for opt.connect_timeout seconds, the
+/* Like a call to accept(), but with the added check for timeout.
+
+ In other words, accept a client connection on LOCAL_SOCK, and
+ return the new socket used for communication with the client.
+ LOCAL_SOCK should have been bound, e.g. using bind_local().
+
+ The caller is blocked until a connection is established. If no
+ connection is established for opt.connect_timeout seconds, the
function exits with an error status. */
-uerr_t
-acceptport (int local_sock, int *sock)
+int
+accept_connection (int local_sock)
{
+ int sock;
+
+ /* We don't need the values provided by accept, but accept
+ apparently requires them to be present. */
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
socklen_t addrlen = sizeof (ss);
#ifdef HAVE_SELECT
if (opt.connect_timeout)
- if (select_fd (local_sock, opt.connect_timeout, WAIT_FOR_READ) <= 0)
- return ACCEPTERR;
+ {
+ int test = select_fd (local_sock, opt.connect_timeout, WAIT_FOR_READ);
+ if (test == 0)
+ errno = ETIMEDOUT;
+ if (test <= 0)
+ return -1;
+ }
#endif
- if ((*sock = accept (local_sock, sa, &addrlen)) < 0)
- return ACCEPTERR;
- DEBUGP (("Created socket fd %d.\n", *sock));
- return ACCEPTOK;
+ sock = accept (local_sock, sa, &addrlen);
+ DEBUGP (("Accepted client at socket %d.\n", sock));
+ return sock;
}
/* Get the IP address associated with the connection on FD and store
int connect_to_host PARAMS ((const char *, int));
int connect_to_ip PARAMS ((const ip_address *, int, const char *));
-uerr_t bindport PARAMS ((const ip_address *, int *, int *));
-uerr_t acceptport PARAMS ((int, int *));
+int bind_local PARAMS ((const ip_address *, int *));
+int accept_connection PARAMS ((int));
enum {
ENDPOINT_LOCAL,
/* Get the address of this side of the connection. */
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
- return BINDERR;
+ return FTPSYSERR;
assert (addr.type == IPV4_ADDRESS);
port = 0;
/* Bind the port. */
- err = bindport (&addr, &port, local_sock);
- if (err != BINDOK)
- return err;
+ *local_sock = bind_local (&addr, &port);
+ if (*local_sock < 0)
+ return FTPSYSERR;
/* Construct the argument of PORT (of the form a,b,c,d,e,f). */
ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
/* Get the address of this side of the connection. */
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
- return BINDERR;
+ return FTPSYSERR;
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
port = 0;
/* Bind the port. */
- err = bindport (&addr, &port, local_sock);
- if (err != BINDOK)
- return err;
+ *local_sock = bind_local (&addr, &port);
+ if (*local_sock < 0)
+ return FTPSYSERR;
/* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
/* Get the address of this side of the connection. */
if (!socket_ip_address (RBUF_FD (rbuf), &addr, ENDPOINT_LOCAL))
- return BINDERR;
+ return FTPSYSERR;
assert (addr.type == IPV4_ADDRESS || addr.type == IPV6_ADDRESS);
port = 0;
/* Bind the port. */
- err = bindport (&addr, &port, local_sock);
- if (err != BINDOK)
- return err;
+ *local_sock = bind_local (&addr, &port);
+ if (*local_sock < 0)
+ return FTPSYSERR;
/* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
if (!pasv_mode_open) /* Try to use a port command if PASV failed */
{
err = ftp_do_port (&con->rbuf, &local_sock);
- /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
- LISTENERR), HOSTERR, FTPPORTERR */
+ /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
+ FTPPORTERR */
switch (err)
{
case FTPRERR:
rbuf_uninitialize (&con->rbuf);
return err;
break;
- case CONPORTERR: case BINDERR: case LISTENERR:
- /* What now? These problems are local... */
+ case FTPSYSERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
strerror (errno));
xclose (dtsock);
- xclose (local_sock);
return err;
break;
case FTPPORTERR:
if (!pasv_mode_open) /* we are not using pasive mode so we need
to accept */
{
- /* Open the data transmission socket by calling acceptport(). */
- err = acceptport (local_sock, &dtsock);
- /* Possible errors: ACCEPTERR. */
- if (err == ACCEPTERR)
+ /* Wait for the server to connect to the address we're waiting
+ at. */
+ dtsock = accept_connection (local_sock);
+ if (dtsock < 0)
{
logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
return err;
return err;
break;
case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
- case WRITEFAILED: case FTPUNKNOWNTYPE: case CONPORTERR:
- case BINDERR: case LISTENERR: case ACCEPTERR:
+ case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
printwhat (count, opt.ntry);
/* non-fatal errors */
{
NOCONERROR, HOSTERR, CONSOCKERR, CONERROR, CONSSLERR,
CONIMPOSSIBLE, NEWLOCATION, NOTENOUGHMEM, CONPORTERR,
- BINDERR, BINDOK, LISTENERR, ACCEPTERR, ACCEPTOK,
- CONCLOSED, FTPOK, FTPLOGINC, FTPLOGREFUSED, FTPPORTERR,
+ CONCLOSED, FTPOK, FTPLOGINC, FTPLOGREFUSED, FTPPORTERR, FTPSYSERR,
FTPNSFOD, FTPRETROK, FTPUNKNOWNTYPE, FTPRERR,
FTPREXC, FTPSRVERR, FTPRETRINT, FTPRESTFAIL, URLERROR,
FOPENERR, FWRITEERR, HOK, HLEXC, HEOF,