mirror of
https://github.com/mirror/wget.git
synced 2025-01-15 23:01:07 +08:00
New implementation for openssl_read, openssl_peek ssl_connect_with_timeout (openssl)
Add new implementation for openssl_read, openssl_peek ssl_connect_with_timeout (openssl). Thats allow continue read after ETIMEDOUT (if timeout < opt.read_timeout) without 'Retrying', and do not create thread (under MSWin) for every read. Old implementation, (with fix for 'timeout') avaible for build with: -DOPENSSL_RUN_WITHTIMEOUT Add timeout for transport_implementation {reader,peeker}; * src/init.c (cmd_time): Add check for negative value. * src/connect.h (transport_implementation {reader,peeker}): Change function prototype. * src/connect.c (select_fd_nb): New function, aviod conversion to blocked under MSWin. * src/gnutls.c (gnutls_read): Fix: using timeout, seting ETIMEDOUT, conversion to blocked. (gnutls_peek): Likewise. (wgnutls_errstr): Add errmsg for ETIMEDOUT. (_do_handshake) (_do_reauth): Fix conversion to blocked. * src/openssl.c: Add new implementation for openssl_read, openssl_peek, ssl_connect_with_timeout. (init_prng): when option --random-file given warn user if RAND_load_file() fail.
This commit is contained in:
parent
9dacc2836a
commit
fb5e2e628d
@ -678,8 +678,8 @@ retryable_socket_connect_error (int err)
|
||||
should be taken as such (for example, it doesn't implement Wget's
|
||||
0-timeout-means-no-timeout semantics.) */
|
||||
|
||||
int
|
||||
select_fd (int fd, double maxtime, int wait_for)
|
||||
static int
|
||||
select_fd_internal (int fd, double maxtime, int wait_for, bool convert_back _GL_UNUSED)
|
||||
{
|
||||
fd_set fdset;
|
||||
fd_set *rd = NULL, *wr = NULL;
|
||||
@ -710,7 +710,8 @@ select_fd (int fd, double maxtime, int wait_for)
|
||||
#ifdef WINDOWS
|
||||
/* gnulib select() converts blocking sockets to nonblocking in windows.
|
||||
wget uses blocking sockets so we must convert them back to blocking. */
|
||||
set_windows_fd_as_blocking_socket (fd);
|
||||
if (convert_back)
|
||||
set_windows_fd_as_blocking_socket (fd);
|
||||
#endif
|
||||
}
|
||||
while (result < 0 && errno == EINTR);
|
||||
@ -718,6 +719,20 @@ select_fd (int fd, double maxtime, int wait_for)
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
select_fd (int fd, double maxtime, int wait_for)
|
||||
{
|
||||
return select_fd_internal (fd, maxtime, wait_for, true);
|
||||
}
|
||||
|
||||
#ifdef WINDOWS
|
||||
int
|
||||
select_fd_nb (int fd, double maxtime, int wait_for)
|
||||
{
|
||||
return select_fd_internal (fd, maxtime, wait_for, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return true if the connection to the remote site established
|
||||
through SOCK is still open.
|
||||
|
||||
@ -925,10 +940,11 @@ fd_read (int fd, char *buf, int bufsize, double timeout)
|
||||
{
|
||||
struct transport_info *info;
|
||||
LAZY_RETRIEVE_INFO (info);
|
||||
|
||||
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
|
||||
return -1;
|
||||
if (info && info->imp->reader)
|
||||
return info->imp->reader (fd, buf, bufsize, info->ctx);
|
||||
return info->imp->reader (fd, buf, bufsize, info->ctx, timeout);
|
||||
else
|
||||
return sock_read (fd, buf, bufsize);
|
||||
}
|
||||
@ -953,7 +969,7 @@ fd_peek (int fd, char *buf, int bufsize, double timeout)
|
||||
if (!poll_internal (fd, info, WAIT_FOR_READ, timeout))
|
||||
return -1;
|
||||
if (info && info->imp->peeker)
|
||||
return info->imp->peeker (fd, buf, bufsize, info->ctx);
|
||||
return info->imp->peeker (fd, buf, bufsize, info->ctx, timeout);
|
||||
else
|
||||
return sock_peek (fd, buf, bufsize);
|
||||
}
|
||||
@ -1005,6 +1021,7 @@ 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 *)(intptr_t) fd);
|
||||
|
||||
|
@ -63,10 +63,10 @@ int select_fd (int, double, int);
|
||||
bool test_socket_open (int);
|
||||
|
||||
struct transport_implementation {
|
||||
int (*reader) (int, char *, int, void *);
|
||||
int (*reader) (int, char *, int, void *, double);
|
||||
int (*writer) (int, char *, int, void *);
|
||||
int (*poller) (int, double, int, void *);
|
||||
int (*peeker) (int, char *, int, void *);
|
||||
int (*peeker) (int, char *, int, void *, double);
|
||||
const char *(*errstr) (int, void *);
|
||||
void (*closer) (int, void *);
|
||||
};
|
||||
@ -80,4 +80,10 @@ const char *fd_errstr (int);
|
||||
void fd_close (int);
|
||||
void connect_cleanup (void);
|
||||
|
||||
#ifdef WINDOWS
|
||||
int select_fd_nb (int, double, int);
|
||||
#else
|
||||
#define select_fd_nb select_fd
|
||||
#endif
|
||||
|
||||
#endif /* CONNECT_H */
|
||||
|
70
src/gnutls.c
70
src/gnutls.c
@ -59,11 +59,11 @@ as that of the covered work. */
|
||||
#include "host.h"
|
||||
|
||||
static int
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout);
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout, int is_nonblock);
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030604
|
||||
static int
|
||||
_do_reauth (gnutls_session_t session, int fd, double timeout);
|
||||
_do_reauth (gnutls_session_t session, int fd, double timeout, int is_nonblock);
|
||||
#endif
|
||||
|
||||
static int
|
||||
@ -259,7 +259,12 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
struct ptimer *timer = NULL;
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
int timed_out = 0;
|
||||
double next_timeout;
|
||||
|
||||
errno = 0;
|
||||
if (timeout == -1)
|
||||
timeout = opt.read_timeout;
|
||||
next_timeout = timeout;
|
||||
if (timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
@ -277,36 +282,41 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
|
||||
timer = ptimer_new ();
|
||||
if (timer == NULL)
|
||||
return -1;
|
||||
{
|
||||
ret = -1;
|
||||
goto timer_err;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
double next_timeout = 0;
|
||||
ret = GNUTLS_E_AGAIN;
|
||||
if (timeout)
|
||||
{
|
||||
next_timeout = timeout - ptimer_measure (timer);
|
||||
if (next_timeout < 0)
|
||||
break;
|
||||
if (next_timeout <= 0)
|
||||
{
|
||||
timed_out = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = GNUTLS_E_AGAIN;
|
||||
/* (rehandshake, reauth) needs some workaround for interactive timeout */
|
||||
if (timeout == 0 || gnutls_record_check_pending (ctx->session)
|
||||
|| select_fd (fd, next_timeout, WAIT_FOR_READ))
|
||||
|| select_fd_nb (fd, next_timeout, WAIT_FOR_READ))
|
||||
{
|
||||
ret = gnutls_record_recv (ctx->session, buf, bufsize);
|
||||
timed_out = timeout && ptimer_measure (timer) >= timeout;
|
||||
if (!timed_out && ret == GNUTLS_E_REHANDSHAKE)
|
||||
{
|
||||
DEBUGP (("GnuTLS: *** REHANDSHAKE while reading\n"));
|
||||
if ((ret = _do_handshake (ctx->session, fd, timeout)) == 0)
|
||||
if ((ret = _do_handshake (ctx->session, fd, opt.read_timeout, 1)) == 0)
|
||||
ret = GNUTLS_E_AGAIN; /* restart reading */
|
||||
}
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030604
|
||||
if (!timed_out && ret == GNUTLS_E_REAUTH_REQUEST)
|
||||
{
|
||||
DEBUGP (("GnuTLS: *** re-authentication while reading\n"));
|
||||
if ((ret = _do_reauth (ctx->session, fd, timeout)) == 0)
|
||||
if ((ret = _do_reauth (ctx->session, fd, opt.read_timeout, 1)) == 0)
|
||||
ret = GNUTLS_E_AGAIN; /* restart reading */
|
||||
}
|
||||
#endif
|
||||
@ -317,7 +327,7 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
if (timeout)
|
||||
{
|
||||
ptimer_destroy (timer);
|
||||
|
||||
timer_err: ;
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
return -1;
|
||||
@ -326,7 +336,6 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
if (ioctl (fd, FIONBIO, &zero) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
if (timed_out && ret == GNUTLS_E_AGAIN)
|
||||
errno = ETIMEDOUT;
|
||||
}
|
||||
@ -335,7 +344,7 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
}
|
||||
|
||||
static int
|
||||
wgnutls_read (int fd, char *buf, int bufsize, void *arg)
|
||||
wgnutls_read (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
@ -352,7 +361,7 @@ wgnutls_read (int fd, char *buf, int bufsize, void *arg)
|
||||
return copysize;
|
||||
}
|
||||
|
||||
ret = wgnutls_read_timeout (fd, buf, bufsize, arg, opt.read_timeout);
|
||||
ret = wgnutls_read_timeout (fd, buf, bufsize, arg, timeout);
|
||||
if (ret < 0)
|
||||
ctx->last_error = ret;
|
||||
|
||||
@ -385,7 +394,7 @@ wgnutls_poll (int fd, double timeout, int wait_for, void *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
wgnutls_peek (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
int read = 0;
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
@ -402,12 +411,12 @@ wgnutls_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
|
||||
if (bufsize > offset)
|
||||
{
|
||||
if (opt.read_timeout && gnutls_record_check_pending (ctx->session) == 0
|
||||
if (timeout && gnutls_record_check_pending (ctx->session) == 0
|
||||
&& select_fd (fd, 0.0, WAIT_FOR_READ) <= 0)
|
||||
read = 0;
|
||||
else
|
||||
read = wgnutls_read_timeout (fd, buf + offset, bufsize - offset,
|
||||
ctx, opt.read_timeout);
|
||||
ctx, timeout);
|
||||
if (read < 0)
|
||||
{
|
||||
if (offset)
|
||||
@ -431,7 +440,8 @@ static const char *
|
||||
wgnutls_errstr (int fd _GL_UNUSED, void *arg)
|
||||
{
|
||||
struct wgnutls_transport_context *ctx = arg;
|
||||
return gnutls_strerror (ctx->last_error);
|
||||
return (ctx->last_error == GNUTLS_E_AGAIN && errno == ETIMEDOUT ?
|
||||
strerror (ETIMEDOUT) : gnutls_strerror (ctx->last_error));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -459,14 +469,14 @@ static struct transport_implementation wgnutls_transport =
|
||||
};
|
||||
|
||||
static int
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout)
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout, int is_nonblock)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
int flags = 0;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
if (timeout)
|
||||
if (!is_nonblock && timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
flags = fcntl (fd, F_GETFL, 0);
|
||||
@ -492,12 +502,12 @@ _do_handshake (gnutls_session_t session, int fd, double timeout)
|
||||
if (gnutls_record_get_direction (session))
|
||||
{
|
||||
/* wait for writeability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_WRITE);
|
||||
err = select_fd_nb (fd, timeout, WAIT_FOR_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait for readability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_READ);
|
||||
err = select_fd_nb (fd, timeout, WAIT_FOR_READ);
|
||||
}
|
||||
|
||||
if (err <= 0)
|
||||
@ -527,7 +537,7 @@ _do_handshake (gnutls_session_t session, int fd, double timeout)
|
||||
}
|
||||
while (err && gnutls_error_is_fatal (err) == 0);
|
||||
|
||||
if (timeout)
|
||||
if (!is_nonblock && timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
@ -544,14 +554,14 @@ _do_handshake (gnutls_session_t session, int fd, double timeout)
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030604
|
||||
static int
|
||||
_do_reauth (gnutls_session_t session, int fd, double timeout)
|
||||
_do_reauth (gnutls_session_t session, int fd, double timeout, int is_nonblock)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
int flags = 0;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
if (timeout)
|
||||
if (!is_nonblock && timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
flags = fcntl (fd, F_GETFL, 0);
|
||||
@ -577,12 +587,12 @@ _do_reauth (gnutls_session_t session, int fd, double timeout)
|
||||
if (gnutls_record_get_direction (session))
|
||||
{
|
||||
/* wait for writeability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_WRITE);
|
||||
err = select_fd_nb (fd, timeout, WAIT_FOR_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait for readability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_READ);
|
||||
err = select_fd_nb (fd, timeout, WAIT_FOR_READ);
|
||||
}
|
||||
|
||||
if (err <= 0)
|
||||
@ -604,7 +614,7 @@ _do_reauth (gnutls_session_t session, int fd, double timeout)
|
||||
}
|
||||
while (err && gnutls_error_is_fatal (err) == 0);
|
||||
|
||||
if (timeout)
|
||||
if (!is_nonblock && timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
@ -830,7 +840,7 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
}
|
||||
}
|
||||
|
||||
err = _do_handshake (session, fd, opt.connect_timeout);
|
||||
err = _do_handshake (session, fd, opt.read_timeout, 0);
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
|
@ -1423,6 +1423,13 @@ cmd_time (const char *com, const char *val, void *place)
|
||||
if (!simple_atof (val, end, &number))
|
||||
goto err;
|
||||
|
||||
if (number < 0)
|
||||
{
|
||||
fprintf (stderr, _("%s: %s: Negative time period %s\n"),
|
||||
exec_name, com, quote (val));
|
||||
return false;
|
||||
}
|
||||
|
||||
*(double *)place = number * mult;
|
||||
return true;
|
||||
}
|
||||
|
291
src/openssl.c
291
src/openssl.c
@ -49,11 +49,16 @@ as that of the covered work. */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "connect.h"
|
||||
#include "ptimer.h"
|
||||
#include "url.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef WINDOWS
|
||||
# include <w32sock.h>
|
||||
#endif
|
||||
@ -80,12 +85,20 @@ init_prng (void)
|
||||
/* Get the random file name using RAND_file_name. */
|
||||
namebuf[0] = '\0';
|
||||
random_file = RAND_file_name (namebuf, sizeof (namebuf));
|
||||
if (!file_exists_p (random_file, NULL))
|
||||
random_file = NULL;
|
||||
}
|
||||
|
||||
if (random_file && *random_file)
|
||||
/* Seed at most 16k (apparently arbitrary value borrowed from
|
||||
curl) from random file. */
|
||||
RAND_load_file (random_file, 16384);
|
||||
{
|
||||
int _err = RAND_load_file (random_file, 16384);
|
||||
if(_err == -1)
|
||||
/* later the thread error queue will be cleared */
|
||||
if ( (_err = ERR_peek_last_error ()) )
|
||||
logprintf (LOG_VERBOSE, "WARNING: Could not load random file: %s, %s\n", opt.random_file, ERR_reason_error_string(_err));
|
||||
}
|
||||
|
||||
#ifdef HAVE_RAND_EGD
|
||||
/* Get random data from EGD if opt.egd_file was used. */
|
||||
@ -427,44 +440,236 @@ struct openssl_transport_context
|
||||
char *last_error; /* last error printed with openssl_errstr */
|
||||
};
|
||||
|
||||
typedef int (*ssl_fn_t)(SSL *, void *, int);
|
||||
|
||||
#ifdef OPENSSL_RUN_WITHTIMEOUT
|
||||
|
||||
struct scwt_context
|
||||
{
|
||||
SSL *ssl;
|
||||
int result;
|
||||
};
|
||||
|
||||
static void
|
||||
ssl_connect_with_timeout_callback(void *arg)
|
||||
{
|
||||
struct scwt_context *ctx = (struct scwt_context *)arg;
|
||||
ctx->result = SSL_connect(ctx->ssl);
|
||||
}
|
||||
|
||||
static int
|
||||
ssl_connect_with_timeout(int fd _GL_UNUSED, SSL *conn, double timeout)
|
||||
{
|
||||
struct scwt_context scwt_ctx;
|
||||
scwt_ctx.ssl = conn;
|
||||
errno = 0;
|
||||
if (run_with_timeout(timeout, ssl_connect_with_timeout_callback,
|
||||
&scwt_ctx))
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
return scwt_ctx.result;
|
||||
}
|
||||
|
||||
struct openssl_read_args
|
||||
{
|
||||
int fd;
|
||||
struct openssl_transport_context *ctx;
|
||||
ssl_fn_t fn;
|
||||
char *buf;
|
||||
int bufsize;
|
||||
int retval;
|
||||
};
|
||||
|
||||
static void openssl_read_callback(void *arg)
|
||||
static void openssl_read_peek_callback(void *arg)
|
||||
{
|
||||
struct openssl_read_args *args = (struct openssl_read_args *) arg;
|
||||
struct openssl_transport_context *ctx = args->ctx;
|
||||
ssl_fn_t fn = args->fn;
|
||||
SSL *conn = ctx->conn;
|
||||
char *buf = args->buf;
|
||||
int bufsize = args->bufsize;
|
||||
int ret;
|
||||
|
||||
do
|
||||
ret = SSL_read (conn, buf, bufsize);
|
||||
while (ret == -1 && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
|
||||
&& errno == EINTR);
|
||||
{
|
||||
ret = fn (conn, buf, bufsize);
|
||||
}
|
||||
while (ret == -1 && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL && errno == EINTR);
|
||||
args->retval = ret;
|
||||
}
|
||||
|
||||
static int
|
||||
openssl_read (int fd, char *buf, int bufsize, void *arg)
|
||||
openssl_read_peek (int fd, char *buf, int bufsize, void *arg, double timeout, ssl_fn_t fn)
|
||||
{
|
||||
struct openssl_read_args args;
|
||||
args.fd = fd;
|
||||
args.buf = buf;
|
||||
args.bufsize = bufsize;
|
||||
args.ctx = (struct openssl_transport_context*) arg;
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
int ret = SSL_pending (ctx->conn);
|
||||
|
||||
if (run_with_timeout(opt.read_timeout, openssl_read_callback, &args)) {
|
||||
return -1;
|
||||
if (bufsize == 0)
|
||||
return 0;
|
||||
|
||||
if (ret)
|
||||
ret = fn (ctx->conn, buf, MIN (bufsize, ret));
|
||||
else
|
||||
{
|
||||
struct openssl_read_args args;
|
||||
args.fd = fd;
|
||||
args.buf = buf;
|
||||
args.bufsize = bufsize;
|
||||
args.fn = fn;
|
||||
args.ctx = ctx;
|
||||
|
||||
errno = 0;
|
||||
if (timeout == -1)
|
||||
timeout = opt.read_timeout;
|
||||
|
||||
if (run_with_timeout(timeout, openssl_read_peek_callback, &args))
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
ret = args.retval;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* OPENSSL_RUN_WITHTIMEOUT */
|
||||
|
||||
#ifdef F_GETFL
|
||||
#define NONBLOCK_DECL int flags = 0;
|
||||
#define FD_SET_NONBLOCKED(_fd) \
|
||||
flags = fcntl (_fd, F_GETFL, 0);\
|
||||
if (flags < 0)\
|
||||
return flags;\
|
||||
if (fcntl (_fd, F_SETFL, flags | O_NONBLOCK))\
|
||||
return -1;
|
||||
#define FD_SET_BLOCKED(_fd) \
|
||||
if (fcntl (_fd, F_SETFL, flags) < 0)\
|
||||
return -1;
|
||||
#else
|
||||
#define NONBLOCK_DECL
|
||||
#define FD_SET_NONBLOCKED(_fd) \
|
||||
{\
|
||||
const int one = 1;\
|
||||
if (ioctl (_fd, FIONBIO, &one) < 0)\
|
||||
return -1;\
|
||||
}
|
||||
return args.retval;
|
||||
#define FD_SET_BLOCKED(_fd) \
|
||||
{\
|
||||
const int zero = 0;\
|
||||
if (ioctl (_fd, FIONBIO, &zero) < 0)\
|
||||
return -1;\
|
||||
}
|
||||
#endif /* F_GETFL */
|
||||
|
||||
#define TIMER_INIT(_fd, _ret, _timeout) \
|
||||
{ \
|
||||
NONBLOCK_DECL \
|
||||
int timed_out = 0; \
|
||||
FD_SET_NONBLOCKED(_fd) \
|
||||
struct ptimer *timer = ptimer_new (); \
|
||||
if (timer == NULL) \
|
||||
_ret = -1; \
|
||||
else \
|
||||
{ \
|
||||
if (_timeout == -1) \
|
||||
_timeout = opt.read_timeout;
|
||||
|
||||
#define TIMER_FREE(_fd) \
|
||||
ptimer_destroy (timer); \
|
||||
} \
|
||||
FD_SET_BLOCKED(_fd) \
|
||||
if (timed_out) \
|
||||
{ \
|
||||
errno = ETIMEDOUT; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TIMER_WAIT(_fd, _conn, _ret, _timeout) \
|
||||
{ \
|
||||
int wait_for; \
|
||||
double next_timeout; \
|
||||
int err = SSL_get_error(_conn, _ret); \
|
||||
if (err == SSL_ERROR_WANT_READ) \
|
||||
wait_for = WAIT_FOR_READ; \
|
||||
else if (err == SSL_ERROR_WANT_WRITE) \
|
||||
wait_for = WAIT_FOR_WRITE; \
|
||||
else \
|
||||
break; \
|
||||
next_timeout = _timeout - ptimer_measure (timer); \
|
||||
if (next_timeout < 0) \
|
||||
{ \
|
||||
timed_out = 1; \
|
||||
break; \
|
||||
} \
|
||||
err = select_fd_nb (_fd, next_timeout, wait_for); \
|
||||
if (err <= 0) \
|
||||
{ \
|
||||
if (err == 0) \
|
||||
timed_out = 1; \
|
||||
_ret = -1; \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
|
||||
static int
|
||||
ssl_connect_with_timeout(int fd, SSL *conn, double timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
errno = 0;
|
||||
if (timeout == 0)
|
||||
ret = SSL_connect(conn);
|
||||
else
|
||||
{
|
||||
TIMER_INIT(fd, ret, timeout)
|
||||
ERR_clear_error();
|
||||
while( (ret = SSL_connect(conn)) < 0 )
|
||||
TIMER_WAIT(fd, conn, ret, timeout)
|
||||
TIMER_FREE(fd)
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
openssl_read_peek (int fd, char *buf, int bufsize, void *arg, double timeout, ssl_fn_t fn)
|
||||
{
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
int ret;
|
||||
|
||||
if (bufsize == 0)
|
||||
return 0;
|
||||
/* avoid wrong 'interactive timeout' when errno == ETIMEDOUT */
|
||||
errno = 0;
|
||||
ret = SSL_pending (ctx->conn);
|
||||
/* If we have data available for immediate read, simply return that,
|
||||
or do blocked read when timeout == 0 */
|
||||
if (ret || timeout == 0)
|
||||
do
|
||||
{
|
||||
ret = fn (ctx->conn, buf, (ret ? MIN (bufsize, ret) : bufsize));
|
||||
}
|
||||
while (ret == -1 && SSL_get_error (ctx->conn, ret) == SSL_ERROR_SYSCALL && errno == EINTR);
|
||||
else
|
||||
{
|
||||
TIMER_INIT(fd, ret, timeout)
|
||||
while( (ret = fn (ctx->conn, buf, bufsize)) <= 0 )
|
||||
TIMER_WAIT(fd, ctx->conn, ret, timeout)
|
||||
TIMER_FREE(fd)
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_RUN_WITHTIMEOUT */
|
||||
|
||||
static int
|
||||
openssl_read (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
return openssl_read_peek (fd, buf, bufsize, arg, timeout, SSL_read);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -475,9 +680,7 @@ openssl_write (int fd _GL_UNUSED, char *buf, int bufsize, void *arg)
|
||||
SSL *conn = ctx->conn;
|
||||
do
|
||||
ret = SSL_write (conn, buf, bufsize);
|
||||
while (ret == -1
|
||||
&& SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
|
||||
&& errno == EINTR);
|
||||
while (ret == -1 && SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL && errno == EINTR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -488,25 +691,17 @@ openssl_poll (int fd, double timeout, int wait_for, void *arg)
|
||||
SSL *conn = ctx->conn;
|
||||
if (SSL_pending (conn))
|
||||
return 1;
|
||||
if (timeout == 0)
|
||||
return 1;
|
||||
/* if (timeout == 0)
|
||||
return 1; */
|
||||
if (timeout == -1)
|
||||
timeout = opt.read_timeout;
|
||||
return select_fd (fd, timeout, wait_for);
|
||||
}
|
||||
|
||||
static int
|
||||
openssl_peek (int fd, char *buf, int bufsize, void *arg)
|
||||
openssl_peek (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
int ret;
|
||||
struct openssl_transport_context *ctx = arg;
|
||||
SSL *conn = ctx->conn;
|
||||
if (! openssl_poll (fd, 0.0, WAIT_FOR_READ, arg))
|
||||
return 0;
|
||||
do
|
||||
ret = SSL_peek (conn, buf, bufsize);
|
||||
while (ret == -1
|
||||
&& SSL_get_error (conn, ret) == SSL_ERROR_SYSCALL
|
||||
&& errno == EINTR);
|
||||
return ret;
|
||||
return openssl_read_peek (fd, buf, bufsize, arg, timeout, SSL_peek);
|
||||
}
|
||||
|
||||
static const char *
|
||||
@ -582,19 +777,6 @@ static struct transport_implementation openssl_transport = {
|
||||
openssl_peek, openssl_errstr, openssl_close
|
||||
};
|
||||
|
||||
struct scwt_context
|
||||
{
|
||||
SSL *ssl;
|
||||
int result;
|
||||
};
|
||||
|
||||
static void
|
||||
ssl_connect_with_timeout_callback(void *arg)
|
||||
{
|
||||
struct scwt_context *ctx = (struct scwt_context *)arg;
|
||||
ctx->result = SSL_connect(ctx->ssl);
|
||||
}
|
||||
|
||||
static const char *
|
||||
_sni_hostname(const char *hostname)
|
||||
{
|
||||
@ -623,7 +805,6 @@ bool
|
||||
ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
{
|
||||
SSL *conn;
|
||||
struct scwt_context scwt_ctx;
|
||||
struct openssl_transport_context *ctx;
|
||||
|
||||
DEBUGP (("Initiating SSL handshake.\n"));
|
||||
@ -674,14 +855,9 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
goto error;
|
||||
}
|
||||
|
||||
scwt_ctx.ssl = conn;
|
||||
if (run_with_timeout(opt.read_timeout, ssl_connect_with_timeout_callback,
|
||||
&scwt_ctx)) {
|
||||
DEBUGP (("SSL handshake timed out.\n"));
|
||||
goto timeout;
|
||||
}
|
||||
if (scwt_ctx.result <= 0 || !SSL_is_init_finished(conn))
|
||||
goto error;
|
||||
if (ssl_connect_with_timeout(fd, conn, opt.read_timeout) <= 0
|
||||
|| !SSL_is_init_finished(conn))
|
||||
goto timedout;
|
||||
|
||||
ctx = xnew0 (struct openssl_transport_context);
|
||||
ctx->conn = conn;
|
||||
@ -694,12 +870,17 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
fd_register_transport (fd, &openssl_transport, ctx);
|
||||
DEBUGP (("Handshake successful; connected socket %d to SSL handle 0x%0*lx\n",
|
||||
fd, PTR_FORMAT (conn)));
|
||||
|
||||
ERR_clear_error ();
|
||||
return true;
|
||||
|
||||
timedout:
|
||||
if (errno == ETIMEDOUT)
|
||||
DEBUGP (("SSL handshake timed out.\n"));
|
||||
else
|
||||
error:
|
||||
DEBUGP (("SSL handshake failed.\n"));
|
||||
DEBUGP (("SSL handshake failed.\n"));
|
||||
print_errors ();
|
||||
timeout:
|
||||
if (conn)
|
||||
SSL_free (conn);
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user