+2005-07-03 Hrvoje Niksic <hniksic@xemacs.org>
+
+ * ftp.c (getftp): Ditto.
+
+ * http.c (gethttp): Use fd_errstr.
+
+ * connect.c (fd_register_transport): Restructure parameters to
+ include only a single structure that describes transport
+ implementation.
+
+ * openssl.c (openssl_errstr): New function: dump SSL error strings
+ into a static buffer and return a pointer to the buffer.
+
+ * connect.c (fd_errstr): New function; returns transport-specific
+ error message, or strerror(errno) if transport doesn't supply one.
+
2005-07-03 Hrvoje Niksic <hniksic@xemacs.org>
* mswindows.h: Also wrap accept() and listen().
or SSL_read or whatever is necessary. */
static struct hash_table *transport_map;
-static int transport_map_modified_tick;
+static unsigned int transport_map_modified_tick;
struct transport_info {
- fd_reader_t reader;
- fd_writer_t writer;
- fd_poller_t poller;
- fd_peeker_t peeker;
- fd_closer_t closer;
+ struct transport_implementation *imp;
void *ctx;
};
call getpeername, etc. */
void
-fd_register_transport (int fd, fd_reader_t reader, fd_writer_t writer,
- fd_poller_t poller, fd_peeker_t peeker,
- fd_closer_t closer, void *ctx)
+fd_register_transport (int fd, struct transport_implementation *imp, void *ctx)
{
struct transport_info *info;
assert (fd >= 0);
info = xnew (struct transport_info);
- info->reader = reader;
- info->writer = writer;
- info->poller = poller;
- info->peeker = peeker;
- info->closer = closer;
+ info->imp = imp;
info->ctx = ctx;
if (!transport_map)
transport_map = hash_table_new (0, NULL, NULL);
if (timeout)
{
int test;
- if (info && info->poller)
- test = info->poller (fd, timeout, wf, info->ctx);
+ if (info && info->imp->poller)
+ test = info->imp->poller (fd, timeout, wf, info->ctx);
else
test = sock_poll (fd, timeout, wf);
if (test == 0)
LAZY_RETRIEVE_INFO (info);
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
return -1;
- if (info && info->reader)
- return info->reader (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->reader)
+ return info->imp->reader (fd, buf, bufsize, info->ctx);
else
return sock_read (fd, buf, bufsize);
}
LAZY_RETRIEVE_INFO (info);
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
return -1;
- if (info && info->peeker)
- return info->peeker (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->peeker)
+ return info->imp->peeker (fd, buf, bufsize, info->ctx);
else
return sock_peek (fd, buf, bufsize);
}
{
if (!poll_internal (fd, info, WAIT_FOR_WRITE, timeout))
return -1;
- if (info && info->writer)
- res = info->writer (fd, buf, bufsize, info->ctx);
+ if (info && info->imp->writer)
+ res = info->imp->writer (fd, buf, bufsize, info->ctx);
else
res = sock_write (fd, buf, bufsize);
if (res <= 0)
return res;
}
+/* Report the most recent error(s) on FD. This should only be called
+ after fd_* functions, such as fd_read and fd_write, and only if
+ they return a negative result. For errors coming from other calls
+ such as setsockopt or fopen, strerror should continue to be
+ used.
+
+ If the transport doesn't support error messages or doesn't supply
+ one, strerror(errno) is returned. */
+
+const char *
+fd_errstr (int fd)
+{
+ /* Don't bother with LAZY_RETRIEVE_INFO, as this will only be called
+ in case of error, never in a tight loop. */
+ struct transport_info *info = NULL;
+ if (transport_map)
+ info = hash_table_get (transport_map, (void *) fd);
+
+ if (info && info->imp->errstr)
+ {
+ const char *err = info->imp->errstr (fd, info->ctx);
+ if (err)
+ return err;
+ /* else, fall through and print the system error. */
+ }
+ return strerror (errno);
+}
+
/* Close the file descriptor FD. */
void
if (transport_map)
info = hash_table_get (transport_map, (void *) fd);
- if (info && info->closer)
- info->closer (fd, info->ctx);
+ if (info && info->imp->closer)
+ info->imp->closer (fd, info->ctx);
else
sock_close (fd);
int select_fd (int, double, int);
bool test_socket_open (int);
-typedef int (*fd_reader_t) (int, char *, int, void *);
-typedef int (*fd_writer_t) (int, char *, int, void *);
-typedef int (*fd_poller_t) (int, double, int, void *);
-typedef int (*fd_peeker_t) (int, char *, int, void *);
-typedef void (*fd_closer_t) (int, void *);
-void fd_register_transport (int, fd_reader_t, fd_writer_t,
- fd_poller_t, fd_peeker_t, fd_closer_t, void *);
-void *fd_transport_context (int);
+struct transport_implementation {
+ int (*reader) (int, char *, int, void *);
+ int (*writer) (int, char *, int, void *);
+ int (*poller) (int, double, int, void *);
+ int (*peeker) (int, char *, int, void *);
+ const char *(*errstr) (int, void *);
+ void (*closer) (int, void *);
+};
+void fd_register_transport (int, struct transport_implementation *, void *);
+void *fd_transport_context (int);
int fd_read (int, char *, int, double);
int fd_write (int, char *, int, double);
int fd_peek (int, char *, int, double);
+const char *fd_errstr (int);
void fd_close (int);
+
#endif /* CONNECT_H */
if (*len)
{
print_length (*len, restval, true);
- expected_bytes = *len; /* for get_contents/show_progress */
+ expected_bytes = *len; /* for fd_read_body's progress bar */
}
else if (expected_bytes)
print_length (expected_bytes, restval, false);
tmrate = retr_rate (rd_size, con->dltime);
total_download_time += con->dltime;
- /* Close data connection socket. */
- fd_close (dtsock);
fd_close (local_sock);
/* Close the local file. */
- {
- /* Close or flush the file. We have to be careful to check for
- error here. Checking the result of fwrite() is not enough --
- errors could go unnoticed! */
- int flush_res;
- if (!output_stream || con->cmd & DO_LIST)
- flush_res = fclose (fp);
- else
- flush_res = fflush (fp);
- if (flush_res == EOF)
- res = -2;
- }
-
- /* If get_contents couldn't write to fp, bail out. */
+ if (!output_stream || con->cmd & DO_LIST)
+ fclose (fp);
+
+ /* If fd_read_body couldn't write to fp, bail out. */
if (res == -2)
{
logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
con->target, strerror (errno));
fd_close (csock);
con->csock = -1;
+ fd_close (dtsock);
return FWRITEERR;
}
else if (res == -1)
{
logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
- tms, tmrate, strerror (errno));
+ tms, tmrate, fd_errstr (dtsock));
if (opt.server_response)
logputs (LOG_ALWAYS, "\n");
}
+ fd_close (dtsock);
/* Get the server to tell us if everything is retrieved. */
err = ftp_response (csock, &respline);
write_error = fd_write (fd, request_string, size - 1, -1);
if (write_error < 0)
logprintf (LOG_VERBOSE, _("Failed writing HTTP request: %s.\n"),
- strerror (errno));
+ fd_errstr (fd));
return write_error;
}
/* Don't normally report the error since this is an
optimization that should be invisible to the user. */
DEBUGP (("] aborting (%s).\n",
- ret < 0 ? strerror (errno) : "EOF received"));
+ ret < 0 ? fd_errstr (fd) : "EOF received"));
return false;
}
contlen -= ret;
wgint contlen; /* expected length */
wgint restval; /* the restart value */
int res; /* the result of last read */
+ const char *errstr; /* error message from read error */
char *newloc; /* new location (redirection) */
char *remote_time; /* remote time-stamp string */
char *error; /* textual HTTP error */
hs->len = 0;
hs->contlen = -1;
hs->res = -1;
+ hs->errstr = "";
hs->newloc = NULL;
hs->remote_time = NULL;
hs->error = NULL;
if (write_error < 0)
{
logprintf (LOG_VERBOSE, _("Failed writing to proxy: %s.\n"),
- strerror (errno));
+ fd_errstr (sock));
CLOSE_INVALIDATE (sock);
return WRITEFAILED;
}
if (!head)
{
logprintf (LOG_VERBOSE, _("Failed reading proxy response: %s\n"),
- strerror (errno));
+ fd_errstr (sock));
CLOSE_INVALIDATE (sock);
return HERR;
}
if (write_error < 0)
{
logprintf (LOG_VERBOSE, _("Failed writing HTTP request: %s.\n"),
- strerror (errno));
+ fd_errstr (sock));
CLOSE_INVALIDATE (sock);
request_free (req);
return WRITEFAILED;
else
{
logprintf (LOG_NOTQUIET, _("Read error (%s) in headers.\n"),
- strerror (errno));
+ fd_errstr (sock));
CLOSE_INVALIDATE (sock);
request_free (req);
return HERR;
if (hs->res >= 0)
CLOSE_FINISH (sock);
else
- CLOSE_INVALIDATE (sock);
+ {
+ if (hs->res < 0)
+ hs->errstr = fd_errstr (sock);
+ CLOSE_INVALIDATE (sock);
+ }
- {
- /* Close or flush the file. We have to be careful to check for
- error here. Checking the result of fwrite() is not enough --
- errors could go unnoticed! */
- int flush_res;
- if (!output_stream)
- flush_res = fclose (fp);
- else
- flush_res = fflush (fp);
- if (flush_res == EOF)
- hs->res = -2;
- }
+ if (!output_stream)
+ fclose (fp);
if (hs->res == -2)
return FWRITEERR;
return RETRFINISHED;
logprintf (LOG_VERBOSE,
_("%s (%s) - Read error at byte %s (%s)."),
tms, tmrate, number_to_static_string (hstat.len),
- strerror (errno));
+ hstat.errstr);
printwhat (count, opt.ntry);
free_hstat (&hstat);
continue;
tms, tmrate,
number_to_static_string (hstat.len),
number_to_static_string (hstat.contlen),
- strerror (errno));
+ hstat.errstr);
printwhat (count, opt.ntry);
free_hstat (&hstat);
continue;
&thread_arg, 0, &thread_id);
if (!thread_hnd)
{
- DEBUGP (("CreateThread() failed; %s\n", strerror (GetLastError ())));
+ DEBUGP (("CreateThread() failed; [0x%x]\n", GetLastError ()));
goto blocking_fallback;
}
static void
print_errors (void)
{
- unsigned long curerr = 0;
- while ((curerr = ERR_get_error ()) != 0)
- logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (curerr, NULL));
+ unsigned long err;
+ while ((err = ERR_get_error ()) != 0)
+ logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", ERR_error_string (err, NULL));
}
/* Convert keyfile type as used by options.h to a type as accepted by
openssl_read (int fd, char *buf, int bufsize, void *ctx)
{
int ret;
- SSL *ssl = (SSL *) ctx;
+ SSL *ssl = ctx;
do
ret = SSL_read (ssl, buf, bufsize);
while (ret == -1
openssl_write (int fd, char *buf, int bufsize, void *ctx)
{
int ret = 0;
- SSL *ssl = (SSL *) ctx;
+ SSL *ssl = ctx;
do
ret = SSL_write (ssl, buf, bufsize);
while (ret == -1
static int
openssl_poll (int fd, double timeout, int wait_for, void *ctx)
{
- SSL *ssl = (SSL *) ctx;
+ SSL *ssl = ctx;
if (timeout == 0)
return 1;
if (SSL_pending (ssl))
openssl_peek (int fd, char *buf, int bufsize, void *ctx)
{
int ret;
- SSL *ssl = (SSL *) ctx;
+ SSL *ssl = ctx;
do
ret = SSL_peek (ssl, buf, bufsize);
while (ret == -1
return ret;
}
+static const char *
+openssl_errstr (int fd, void *ctx)
+{
+ /* Unfortunately we cannot use ERR_error_string's internal buf
+ because we must be prepared to printing more than one error in
+ succession. */
+ static char errbuf[512];
+ char *p = errbuf, *end = errbuf + sizeof errbuf;
+ unsigned long err;
+
+ if ((err = ERR_get_error ()) == 0)
+ /* Inform the caller that there have been no errors */
+ return NULL;
+
+ /* Iterate over OpenSSL's error stack and print errors to ERRBUF,
+ each followed by '\n', while being careful not to overrun
+ ERRBUF. */
+ do
+ {
+ ERR_error_string_n (err, p, end - p);
+ p = strchr (p, '\0');
+ if (p < end)
+ *p++ = '\n';
+ }
+ while ((err = ERR_get_error ()) != 0);
+
+ if (p < end)
+ *p++ = '\0';
+ else
+ end[-1] = '\0';
+ return errbuf;
+}
+
static void
openssl_close (int fd, void *ctx)
{
- SSL *ssl = (SSL *) ctx;
+ SSL *ssl = ctx;
SSL_shutdown (ssl);
SSL_free (ssl);
DEBUGP (("Closed %d/SSL 0x%0lx\n", fd, (unsigned long) ssl));
}
+/* openssl_transport is the singleton that describes the SSL transport
+ methods provided by this file. */
+
+static struct transport_implementation openssl_transport = {
+ openssl_read, openssl_write, openssl_poll,
+ openssl_peek, openssl_errstr, openssl_close
+};
+
/* Perform the SSL handshake on file descriptor FD, which is assumed
to be connected to an SSL server. The SSL handle provided by
OpenSSL is registered with the file descriptor FD using
/* Register FD with Wget's transport layer, i.e. arrange that our
functions are used for reading, writing, and polling. */
- fd_register_transport (fd, openssl_read, openssl_write, openssl_poll,
- openssl_peek, openssl_close, ssl);
+ fd_register_transport (fd, &openssl_transport, ssl);
DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
fd, PTR_FORMAT (ssl)));
return true;