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:
Вячеслав Петрищев 2020-03-17 13:56:52 +06:00 committed by Tim Rühsen
parent 9dacc2836a
commit fb5e2e628d
5 changed files with 313 additions and 92 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;