Correctly print SSL errors
Hrvoje Niksic <[email protected]> Sun, 03 Jul 2005 23:20:24 +0200
| Newsgroups | gmane.comp.web.wget.patches |
|---|---|
| Message-ID | <[email protected]> |
The current code erroneously uses strerror(errno) to print SSL errors. This fixes the problem by introducing an fd_errstr function to handle the error messages at the "transport layer" Wget uses to abstract SSL. 2005-07-03 Hrvoje Niksic <[email protected]> * 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. Index: src/http.c =================================================================== --- src/http.c (revision 1956) +++ src/http.c (working copy) @@ -352,7 +352,7 @@ 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; } @@ -838,7 +838,7 @@ /* 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; @@ -1075,6 +1075,7 @@ 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 */ @@ -1212,6 +1213,7 @@ hs->len = 0; hs->contlen = -1; hs->res = -1; + hs->errstr = ""; hs->newloc = NULL; hs->remote_time = NULL; hs->error = NULL; @@ -1484,7 +1486,7 @@ if (write_error < 0) { logprintf (LOG_VERBOSE, _("Failed writing to proxy: %s.\n"), - strerror (errno)); + fd_errstr (sock)); CLOSE_INVALIDATE (sock); return WRITEFAILED; } @@ -1493,7 +1495,7 @@ if (!head) { logprintf (LOG_VERBOSE, _("Failed reading proxy response: %s\n"), - strerror (errno)); + fd_errstr (sock)); CLOSE_INVALIDATE (sock); return HERR; } @@ -1554,7 +1556,7 @@ 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; @@ -1578,7 +1580,7 @@ else { logprintf (LOG_NOTQUIET, _("Read error (%s) in headers.\n"), - strerror (errno)); + fd_errstr (sock)); CLOSE_INVALIDATE (sock); request_free (req); return HERR; @@ -1966,20 +1968,14 @@ 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; @@ -2502,7 +2498,7 @@ 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; @@ -2514,7 +2510,7 @@ 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; Index: src/ftp.c =================================================================== --- src/ftp.c (revision 1956) +++ src/ftp.c (working copy) @@ -952,7 +952,7 @@ 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); @@ -971,39 +971,29 @@ 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 (!output_stream || con->cmd & DO_LIST) + fclose (fp); - /* If get_contents couldn't write to fp, bail out. */ + /* 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); Index: src/mswindows.c =================================================================== --- src/mswindows.c (revision 1956) +++ src/mswindows.c (working copy) @@ -709,7 +709,7 @@ &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; } Index: src/connect.c =================================================================== --- src/connect.c (revision 1956) +++ src/connect.c (working copy) @@ -732,14 +732,10 @@ 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; }; @@ -751,9 +747,7 @@ 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; @@ -763,11 +757,7 @@ 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); @@ -819,8 +809,8 @@ 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) @@ -843,8 +833,8 @@ 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); } @@ -868,8 +858,8 @@ 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); } @@ -893,8 +883,8 @@ { 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) @@ -905,6 +895,34 @@ 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 @@ -920,8 +938,8 @@ 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); Index: src/connect.h =================================================================== --- src/connect.h (revision 1956) +++ src/connect.h (working copy) @@ -60,17 +60,21 @@ 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 *); +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 */ Index: src/openssl.c =================================================================== --- src/openssl.c (revision 1956) +++ src/openssl.c (working copy) @@ -126,9 +126,9 @@ 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 @@ -238,7 +238,7 @@ 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 @@ -251,7 +251,7 @@ 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 @@ -263,7 +263,7 @@ 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)) @@ -275,7 +275,7 @@ 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 @@ -284,10 +284,43 @@ 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); @@ -300,6 +333,14 @@ 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 @@ -327,8 +368,7 @@ /* 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;