#include "host.h"
#include "netrc.h"
#include "convert.h" /* for downloaded_file */
+#include "recur.h" /* for INFINITE_RECURSION */
#ifndef errno
extern int errno;
}
#ifdef ENABLE_IPV6
-static int
-getfamily (int fd)
-{
- struct sockaddr_storage ss;
- struct sockaddr *sa = (struct sockaddr *)&ss;
- socklen_t len = sizeof (ss);
-
- assert (fd >= 0);
-
- if (getpeername (fd, sa, &len) < 0)
- /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
- abort ();
-
- return sa->sa_family;
-}
-
/*
* This function sets up a passive data connection with the FTP server.
* It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
{
uerr_t err;
- int family;
- family = getfamily (rbuf->fd);
- assert (family == AF_INET || family == AF_INET6);
+ /* We need to determine the address family and need to call
+ getpeername, so while we're at it, store the address to ADDR.
+ ftp_pasv and ftp_lpsv can simply override it. */
+ if (!socket_ip_address (RBUF_FD (rbuf), addr, ENDPOINT_PEER))
+ abort ();
/* If our control connection is over IPv6, then we first try EPSV and then
* LPSV if the former is not supported. If the control connection is over
* IPv4, we simply issue the good old PASV request. */
- if (family == AF_INET6)
+ switch (addr->type)
{
+ case IPV4_ADDRESS:
+ if (!opt.server_response)
+ logputs (LOG_VERBOSE, "==> PASV ... ");
+ err = ftp_pasv (rbuf, addr, port);
+ break;
+ case IPV6_ADDRESS:
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> EPSV ... ");
err = ftp_epsv (rbuf, addr, port);
logputs (LOG_VERBOSE, "==> LPSV ... ");
err = ftp_lpsv (rbuf, addr, port);
}
- }
- else
- {
- if (!opt.server_response)
- logputs (LOG_VERBOSE, "==> PASV ... ");
- err = ftp_pasv (rbuf, addr, port);
+ break;
+ default:
+ abort ();
}
return err;
ftp_do_port (struct rbuf *rbuf, int *local_sock)
{
uerr_t err;
- int family;
+ ip_address cip;
assert (rbuf != NULL);
assert (rbuf_initialized_p (rbuf));
- family = getfamily (rbuf->fd);
- assert (family == AF_INET || family == AF_INET6);
+ if (!socket_ip_address (RBUF_FD (rbuf), &cip, ENDPOINT_PEER))
+ abort ();
/* If our control connection is over IPv6, then we first try EPRT and then
* LPRT if the former is not supported. If the control connection is over
* IPv4, we simply issue the good old PORT request. */
- if (family == AF_INET6)
+ switch (cip.type)
{
+ case IPV4_ADDRESS:
+ if (!opt.server_response)
+ logputs (LOG_VERBOSE, "==> PORT ... ");
+ err = ftp_port (rbuf, local_sock);
+ break;
+ case IPV6_ADDRESS:
if (!opt.server_response)
logputs (LOG_VERBOSE, "==> EPRT ... ");
err = ftp_eprt (rbuf, local_sock);
logputs (LOG_VERBOSE, "==> LPRT ... ");
err = ftp_lprt (rbuf, local_sock);
}
+ break;
+ default:
+ abort ();
}
- else
- {
- if (!opt.server_response)
- logputs (LOG_VERBOSE, "==> PORT ... ");
- err = ftp_port (rbuf, local_sock);
- }
-
return err;
}
#else
if (csock == E_HOST)
return HOSTERR;
else if (csock < 0)
- return CONNECT_ERROR (errno);
+ return (retryable_socket_connect_error (errno)
+ ? CONERROR : CONIMPOSSIBLE);
if (cmd & LEAVE_PENDING)
rbuf_initialize (&con->rbuf, csock);
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
case FTPSRVERR:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
case FTPLOGREFUSED:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return FTPLOGREFUSED;
break;
case FTPLOGINC:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return FTPLOGINC;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
case FTPSRVERR :
/* PWD unsupported -- assume "/". */
- FREE_MAYBE (con->id);
+ xfree_null (con->id);
con->id = xstrdup ("/");
break;
case FTPOK:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logprintf (LOG_NOTQUIET,
_("Unknown type `%c', closing control connection.\n"),
type_char);
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
case FTPOK:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
u->dir);
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
if (dtsock < 0)
{
int save_errno = errno;
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
pretty_print_address (&passive_addr), passive_port,
strerror (save_errno));
- return CONNECT_ERROR (save_errno);
+ return (retryable_socket_connect_error (save_errno)
+ ? CONERROR : CONIMPOSSIBLE);
}
pasv_mode_open = 1; /* Flag to avoid accept port */
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:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
case CONSOCKERR:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
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));
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (dtsock);
return err;
break;
case FTPPORTERR:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logprintf (LOG_NOTQUIET,
_("\nREST failed; will not truncate `%s'.\n"),
con->target);
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return CONTNOTSUPPORTED;
}
request. */
if (opt.spider)
{
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return RETRFINISHED;
}
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
case FTPNSFOD:
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (dtsock);
+ fd_close (local_sock);
return err;
break;
case FTPOK:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
- CLOSE (csock);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (csock);
+ fd_close (dtsock);
+ fd_close (local_sock);
rbuf_uninitialize (&con->rbuf);
return err;
break;
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
".");
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (dtsock);
+ fd_close (local_sock);
return err;
break;
case FTPOK:
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;
if (!fp)
{
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (dtsock);
+ fd_close (local_sock);
return FOPENERR;
}
}
tms = time_str (NULL);
tmrate = retr_rate (*len - restval, con->dltime, 0);
/* Close data connection socket. */
- CLOSE (dtsock);
- CLOSE (local_sock);
+ fd_close (dtsock);
+ fd_close (local_sock);
/* Close the local file. */
{
/* Close or flush the file. We have to be careful to check for
{
logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
con->target, strerror (errno));
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return FWRITEERR;
}
return FTPRETRINT, since there is a possibility that the
whole file was retrieved nevertheless (but that is for
ftp_loop_internal to decide). */
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
return FTPRETRINT;
} /* err != FTPOK */
{
/* I should probably send 'QUIT' and check for a reply, but this
is faster. #### Is it OK, though? */
- CLOSE (csock);
+ fd_close (csock);
rbuf_uninitialize (&con->rbuf);
}
/* If it was a listing, and opt.server_response is true,
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 */
if (con->st & ON_YOUR_OWN)
{
- CLOSE (RBUF_FD (&con->rbuf));
+ fd_close (RBUF_FD (&con->rbuf));
rbuf_uninitialize (&con->rbuf);
}
if (!opt.spider)
if (rbuf_initialized_p (&con->rbuf) && (con->st & ON_YOUR_OWN))
{
- CLOSE (RBUF_FD (&con->rbuf));
+ fd_close (RBUF_FD (&con->rbuf));
rbuf_uninitialize (&con->rbuf);
}
return TRYLIMEXC;
logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
if (f->perms && f->type == FT_PLAINFILE && dlthis)
- chmod (con->target, f->perms);
+ {
+ if (opt.preserve_perm)
+ chmod (con->target, f->perms);
+ }
else
DEBUGP (("Unrecognized permissions for %s.\n", con->target));
*dt |= RETROKF;
/* If a connection was left, quench it. */
if (rbuf_initialized_p (&con.rbuf))
- CLOSE (RBUF_FD (&con.rbuf));
- FREE_MAYBE (con.id);
+ fd_close (RBUF_FD (&con.rbuf));
+ xfree_null (con.id);
con.id = NULL;
- FREE_MAYBE (con.target);
+ xfree_null (con.target);
con.target = NULL;
return res;
}
struct fileinfo *next = f->next;
xfree (f->name);
- FREE_MAYBE (f->linkto);
+ xfree_null (f->linkto);
xfree (f);
if (next)