improved ssl_connect timeout handling

This commit is contained in:
hyung-hwan 2016-04-21 15:07:58 +00:00
parent 87fcec25bc
commit a0d68ad079
5 changed files with 154 additions and 78 deletions

View File

@ -372,14 +372,14 @@ int main ()
stio_sckaddr_initforip4 (&tcp_conn.remoteaddr, 9999, (stio_ip4addr_t*)&ia); stio_sckaddr_initforip4 (&tcp_conn.remoteaddr, 9999, (stio_ip4addr_t*)&ia);
} }
stio_inittime (&tcp_conn.tmout, 5, 0); stio_inittime (&tcp_conn.connect_tmout, 5, 0);
tcp_conn.on_connect = tcp_sck_on_connect; tcp_conn.on_connect = tcp_sck_on_connect;
tcp_conn.on_disconnect = tcp_sck_on_disconnect; tcp_conn.on_disconnect = tcp_sck_on_disconnect;
tcp_conn.options = STIO_DEV_SCK_CONNECT_SSL; tcp_conn.options = STIO_DEV_SCK_CONNECT_SSL;
if (stio_dev_sck_connect (tcp[0], &tcp_conn) <= -1) if (stio_dev_sck_connect (tcp[0], &tcp_conn) <= -1)
{ {
printf ("stio_dev_sck_connect() failed....\n"); printf ("stio_dev_sck_connect() failed....\n");
goto oops; /* carry on regardless of failure */
} }
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
@ -418,7 +418,6 @@ int main ()
goto oops; goto oops;
} }
/* -------------------------------------------------------------- */ /* -------------------------------------------------------------- */
memset (&tcp_make, 0, STIO_SIZEOF(&tcp_make)); memset (&tcp_make, 0, STIO_SIZEOF(&tcp_make));
tcp_make.type = STIO_DEV_SCK_TCP4; tcp_make.type = STIO_DEV_SCK_TCP4;
@ -439,7 +438,7 @@ int main ()
tcp_bind.options = STIO_DEV_SCK_BIND_REUSEADDR | /*STIO_DEV_SCK_BIND_REUSEPORT |*/ STIO_DEV_SCK_BIND_SSL; tcp_bind.options = STIO_DEV_SCK_BIND_REUSEADDR | /*STIO_DEV_SCK_BIND_REUSEPORT |*/ STIO_DEV_SCK_BIND_SSL;
tcp_bind.ssl_certfile = STIO_MT("localhost.crt"); tcp_bind.ssl_certfile = STIO_MT("localhost.crt");
tcp_bind.ssl_keyfile = STIO_MT("localhost.key"); tcp_bind.ssl_keyfile = STIO_MT("localhost.key");
stio_inittime (&tcp_bind.ssl_accept_tmout, 5, 1); stio_inittime (&tcp_bind.accept_tmout, 5, 1);
if (stio_dev_sck_bind (tcp[2],&tcp_bind) <= -1) if (stio_dev_sck_bind (tcp[2],&tcp_bind) <= -1)
{ {

View File

@ -75,13 +75,6 @@ void stio_closeasyncsck (stio_t* stio, stio_sckhnd_t sck)
#endif #endif
} }
#if 0
int stio_shutasyncsck (stio_t* stio, stio_sckhnd_t sck, int how)
{
shutdown (sck, how);
}
#endif
int stio_makesckasync (stio_t* stio, stio_sckhnd_t sck) int stio_makesckasync (stio_t* stio, stio_sckhnd_t sck)
{ {
return stio_makesyshndasync (stio, (stio_syshnd_t)sck); return stio_makesyshndasync (stio, (stio_syshnd_t)sck);
@ -298,6 +291,36 @@ static void ssl_accept_timedout (stio_t* stio, const stio_ntime_t* now, stio_tmr
} }
} }
static void ssl_connect_timedout (stio_t* stio, const stio_ntime_t* now, stio_tmrjob_t* job)
{
stio_dev_sck_t* rdev = (stio_dev_sck_t*)job->ctx;
STIO_ASSERT (IS_STATEFUL(rdev));
if (rdev->state & STIO_DEV_SCK_CONNECTING_SSL)
{
stio_dev_sck_halt(rdev);
}
}
static int schedule_timer_job (stio_dev_sck_t* dev, const stio_ntime_t* tmout, stio_tmrjob_handler_t handler)
{
stio_tmrjob_t tmrjob;
STIO_ASSERT (stio_ispostime(tmout));
STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob));
tmrjob.ctx = dev;
stio_gettime (&tmrjob.when);
stio_addtime (&tmrjob.when, tmout, &tmrjob.when);
tmrjob.handler = handler;
tmrjob.idxptr = &dev->tmrjob_index;
STIO_ASSERT (dev->tmrjob_index == STIO_TMRIDX_INVALID);
dev->tmrjob_index = stio_instmrjob (dev->stio, &tmrjob);
return dev->tmrjob_index == STIO_TMRIDX_INVALID? -1: 0;
}
/* ======================================================================== */ /* ======================================================================== */
static int dev_sck_make (stio_dev_t* dev, void* ctx) static int dev_sck_make (stio_dev_t* dev, void* ctx)
@ -671,6 +694,12 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
#if defined(USE_SSL) #if defined(USE_SSL)
SSL_CTX* ssl_ctx = STIO_NULL; SSL_CTX* ssl_ctx = STIO_NULL;
#endif #endif
if (STIO_DEV_SCK_GET_PROGRESS(rdev))
{
/* can't bind again */
rdev->stio->errnum = STIO_EPERM;
return -1;
}
if (bnd->options & STIO_DEV_SCK_BIND_BROADCAST) if (bnd->options & STIO_DEV_SCK_BIND_BROADCAST)
{ {
@ -727,6 +756,18 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
#endif #endif
} }
if (rdev->ssl_ctx)
{
SSL_CTX_free (rdev->ssl_ctx);
rdev->ssl_ctx = STIO_NULL;
if (rdev->ssl)
{
SSL_free (rdev->ssl);
rdev->ssl = STIO_NULL;
}
}
if (bnd->options & STIO_DEV_SCK_BIND_SSL) if (bnd->options & STIO_DEV_SCK_BIND_SSL)
{ {
#if defined(USE_SSL) #if defined(USE_SSL)
@ -753,10 +794,10 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
return -1; return -1;
} }
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); /* no outdated SSLv2 by default */
SSL_CTX_set_read_ahead (ssl_ctx, 0); SSL_CTX_set_read_ahead (ssl_ctx, 0);
rdev->ssl_accept_tmout = bnd->ssl_accept_tmout; rdev->tmout = bnd->accept_tmout;
#else #else
rdev->stio->errnum = STIO_ENOIMPL; rdev->stio->errnum = STIO_ENOIMPL;
return -1; return -1;
@ -794,6 +835,14 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
#if defined(USE_SSL) #if defined(USE_SSL)
SSL_CTX* ssl_ctx = STIO_NULL; SSL_CTX* ssl_ctx = STIO_NULL;
#endif #endif
if (STIO_DEV_SCK_GET_PROGRESS(rdev))
{
/* can't connect again */
rdev->stio->errnum = STIO_EPERM;
return -1;
}
if (!IS_STATEFUL(rdev)) if (!IS_STATEFUL(rdev))
{ {
dev->stio->errnum = STIO_ENOCAPA; dev->stio->errnum = STIO_ENOCAPA;
@ -809,6 +858,18 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
} }
#if defined(USE_SSL) #if defined(USE_SSL)
if (rdev->ssl_ctx)
{
if (rdev->ssl)
{
SSL_free (rdev->ssl);
rdev->ssl = STIO_NULL;
}
SSL_CTX_free (rdev->ssl_ctx);
rdev->ssl_ctx = STIO_NULL;
}
if (conn->options & STIO_DEV_SCK_CONNECT_SSL) if (conn->options & STIO_DEV_SCK_CONNECT_SSL)
{ {
ssl_ctx = SSL_CTX_new(SSLv23_client_method()); ssl_ctx = SSL_CTX_new(SSLv23_client_method());
@ -819,7 +880,6 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg)
} }
} }
#endif #endif
/*{ /*{
int flags = fcntl (rdev->sck, F_GETFL); int flags = fcntl (rdev->sck, F_GETFL);
fcntl (rdev->sck, F_SETFL, flags & ~O_NONBLOCK); fcntl (rdev->sck, F_SETFL, flags & ~O_NONBLOCK);
@ -831,7 +891,6 @@ fcntl (rdev->sck, F_SETFL, flags & ~O_NONBLOCK);
int flags = fcntl (rdev->sck, F_GETFL); int flags = fcntl (rdev->sck, F_GETFL);
fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK); fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
}*/ }*/
if (x == -1) if (x == -1)
{ {
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN)
@ -844,22 +903,13 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
} }
else else
{ {
stio_tmrjob_t tmrjob; if (stio_ispostime(&conn->connect_tmout) &&
schedule_timer_job (rdev, &conn->connect_tmout, tmr_connect_handle) <= -1)
if (stio_ispostime(&conn->tmout))
{ {
STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob)); goto oops_connect;
tmrjob.ctx = rdev;
stio_gettime (&tmrjob.when);
stio_addtime (&tmrjob.when, &conn->tmout, &tmrjob.when);
tmrjob.handler = tmr_connect_handle;
tmrjob.idxptr = &rdev->tmrjob_index;
STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
rdev->tmrjob_index = stio_instmrjob (rdev->stio, &tmrjob);
if (rdev->tmrjob_index == STIO_TMRIDX_INVALID) goto oops_connect;
} }
rdev->tmout = conn->connect_tmout;
rdev->remoteaddr = conn->remoteaddr; rdev->remoteaddr = conn->remoteaddr;
rdev->on_connect = conn->on_connect; rdev->on_connect = conn->on_connect;
rdev->on_disconnect = conn->on_disconnect; rdev->on_disconnect = conn->on_disconnect;
@ -888,13 +938,9 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
else else
{ {
/* connected immediately */ /* connected immediately */
rdev->remoteaddr = conn->remoteaddr; rdev->remoteaddr = conn->remoteaddr;
rdev->on_connect = conn->on_connect; rdev->on_connect = conn->on_connect;
rdev->on_disconnect = conn->on_disconnect; rdev->on_disconnect = conn->on_disconnect;
#if defined(USE_SSL)
rdev->ssl_ctx = ssl_ctx;
#endif
sl = STIO_SIZEOF(localaddr); sl = STIO_SIZEOF(localaddr);
if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &sl) == 0) rdev->localaddr = localaddr; if (getsockname (rdev->sck, (struct sockaddr*)&localaddr, &sl) == 0) rdev->localaddr = localaddr;
@ -903,18 +949,44 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
if (ssl_ctx) if (ssl_ctx)
{ {
int x; int x;
rdev->ssl_ctx = ssl_ctx;
x = connect_ssl (rdev); x = connect_ssl (rdev);
if (x <= -1) return -1; if (x <= -1)
{
SSL_CTX_free (rdev->ssl_ctx);
rdev->ssl_ctx = STIO_NULL;
STIO_ASSERT (rdev->ssl == STIO_NULL);
return -1;
}
if (x == 0) if (x == 0)
{ {
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL); STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
/* TODO: schedule a ssl-connecting timeout job */ if (stio_ispostime(&conn->connect_tmout) &&
schedule_timer_job (rdev, &conn->connect_tmout, ssl_connect_timedout) <= -1)
{
/* no device halting in spite of failure.
* let the caller handle this after having
* checked the return code as it is an IOCTL call. */
SSL_CTX_free (rdev->ssl_ctx);
rdev->ssl_ctx = STIO_NULL;
STIO_ASSERT (rdev->ssl == STIO_NULL);
return -1;
} }
else goto connect_ok;
rdev->tmout = conn->connect_tmout;
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL);
} }
else else
{ {
connect_ok: goto ssl_connected;
}
}
else
{
ssl_connected:
#endif #endif
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED); STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED);
if (rdev->on_connect (rdev) <= -1) return -1; if (rdev->on_connect (rdev) <= -1) return -1;
@ -930,6 +1002,13 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK);
stio_dev_sck_listen_t* lstn = (stio_dev_sck_listen_t*)arg; stio_dev_sck_listen_t* lstn = (stio_dev_sck_listen_t*)arg;
int x; int x;
if (STIO_DEV_SCK_GET_PROGRESS(rdev))
{
/* can't listen again */
rdev->stio->errnum = STIO_EPERM;
return -1;
}
if (!IS_STATEFUL(rdev)) if (!IS_STATEFUL(rdev))
{ {
dev->stio->errnum = STIO_ENOCAPA; dev->stio->errnum = STIO_ENOCAPA;
@ -1035,9 +1114,19 @@ static int harvest_outgoing_connection (stio_dev_sck_t* rdev)
if (x <= -1) return -1; if (x <= -1) return -1;
if (x == 0) if (x == 0)
{ {
/* not SSL-connected */ /* underlying socket connected but not SSL-connected */
STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL); STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL);
/* TODO: schedule ssl_connect timeout job */
STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID);
/* TODO: calculate the timeout again... it should be (rdev->tmout - (now - socket-creation-time))
* without the fix, timeout gets doubled. it's used for connect() once and for ssl-connect().*/
if (stio_ispostime(&rdev->tmout) &&
schedule_timer_job (rdev, &rdev->tmout, ssl_connect_timedout) <= -1)
{
stio_dev_halt ((stio_dev_t*)rdev);
}
return 0; return 0;
} }
else else
@ -1163,27 +1252,14 @@ static int accept_incoming_connection (stio_dev_sck_t* rdev)
/* let the client device know the SSL context to use */ /* let the client device know the SSL context to use */
clidev->ssl_ctx = rdev->ssl_ctx; clidev->ssl_ctx = rdev->ssl_ctx;
if (stio_ispostime(&rdev->ssl_accept_tmout)) if (stio_ispostime(&rdev->tmout) &&
{ schedule_timer_job (clidev, &rdev->tmout, ssl_accept_timedout) <= -1)
stio_tmrjob_t tmrjob;
STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob));
tmrjob.ctx = clidev;
stio_gettime (&tmrjob.when);
stio_addtime (&tmrjob.when, &rdev->ssl_accept_tmout, &tmrjob.when);
tmrjob.handler = ssl_accept_timedout;
tmrjob.idxptr = &clidev->tmrjob_index;
clidev->tmrjob_index = stio_instmrjob (clidev->stio, &tmrjob);
if (clidev->tmrjob_index == STIO_TMRIDX_INVALID)
{ {
/* TODO: call a warning/error callback */ /* TODO: call a warning/error callback */
/* timer job scheduling failed. halt the device */ /* timer job scheduling failed. halt the device */
stio_dev_halt ((stio_dev_t*)clidev); stio_dev_halt ((stio_dev_t*)clidev);
} }
} }
}
else else
{ {
STIO_DEV_SCK_SET_PROGRESS (clidev, STIO_DEV_SCK_ACCEPTED); STIO_DEV_SCK_SET_PROGRESS (clidev, STIO_DEV_SCK_ACCEPTED);

View File

@ -186,7 +186,7 @@ struct stio_dev_sck_bind_t
const stio_mchar_t* ssl_certfile; const stio_mchar_t* ssl_certfile;
const stio_mchar_t* ssl_keyfile; const stio_mchar_t* ssl_keyfile;
stio_ntime_t ssl_accept_tmout; stio_ntime_t accept_tmout;
}; };
enum stio_def_sck_connect_option_t enum stio_def_sck_connect_option_t
@ -201,7 +201,7 @@ struct stio_dev_sck_connect_t
{ {
int options; int options;
stio_sckaddr_t remoteaddr; stio_sckaddr_t remoteaddr;
stio_ntime_t tmout; /* connect timeout */ stio_ntime_t connect_tmout;
stio_dev_sck_on_connect_t on_connect; stio_dev_sck_on_connect_t on_connect;
stio_dev_sck_on_disconnect_t on_disconnect; stio_dev_sck_on_disconnect_t on_disconnect;
}; };
@ -229,9 +229,11 @@ struct stio_dev_sck_t
stio_dev_sck_type_t type; stio_dev_sck_type_t type;
stio_sckhnd_t sck; stio_sckhnd_t sck;
/* connect timeout, ssl-connect timeout, ssl-accept timeout */
stio_ntime_t tmout;
void* ssl_ctx; void* ssl_ctx;
void* ssl; void* ssl;
stio_ntime_t ssl_accept_tmout;
int state; int state;

View File

@ -1155,6 +1155,11 @@ stio_errnum_t stio_syserrtoerrnum (int no)
return STIO_ECONRS; return STIO_ECONRS;
#endif #endif
#if defined(EPERM)
case EPERM:
return STIO_EPERM;
#endif
default: default:
return STIO_ESYSERR; return STIO_ESYSERR;
} }

View File

@ -107,6 +107,7 @@ enum stio_errnum_t
STIO_ECONRS, /* connection reset */ STIO_ECONRS, /* connection reset */
STIO_ENOCAPA, /* no capability */ STIO_ENOCAPA, /* no capability */
STIO_ETMOUT, /* timed out */ STIO_ETMOUT, /* timed out */
STIO_EPERM, /* operation not permitted */
STIO_EDEVMAKE, STIO_EDEVMAKE,
STIO_EDEVERR, STIO_EDEVERR,
@ -133,13 +134,6 @@ typedef void (*stio_tmrjob_handler_t) (
stio_tmrjob_t* tmrjob stio_tmrjob_t* tmrjob
); );
typedef void (*stio_tmrjob_updater_t) (
stio_t* stio,
stio_tmridx_t old_index,
stio_tmridx_t new_index,
stio_tmrjob_t* tmrjob
);
struct stio_dev_mth_t struct stio_dev_mth_t
{ {
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */