From a0d68ad07969cfaf2aba01989c33e6447166dd09 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Thu, 21 Apr 2016 15:07:58 +0000 Subject: [PATCH] improved ssl_connect timeout handling --- stio/lib/main.c | 7 +- stio/lib/stio-sck.c | 180 +++++++++++++++++++++++++++++++------------- stio/lib/stio-sck.h | 32 ++++---- stio/lib/stio.c | 5 ++ stio/lib/stio.h | 8 +- 5 files changed, 154 insertions(+), 78 deletions(-) diff --git a/stio/lib/main.c b/stio/lib/main.c index 2bd0e59..1555cdb 100644 --- a/stio/lib/main.c +++ b/stio/lib/main.c @@ -372,14 +372,14 @@ int main () 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_disconnect = tcp_sck_on_disconnect; tcp_conn.options = STIO_DEV_SCK_CONNECT_SSL; if (stio_dev_sck_connect (tcp[0], &tcp_conn) <= -1) { printf ("stio_dev_sck_connect() failed....\n"); - goto oops; + /* carry on regardless of failure */ } /* -------------------------------------------------------------- */ @@ -418,7 +418,6 @@ int main () goto oops; } - /* -------------------------------------------------------------- */ memset (&tcp_make, 0, STIO_SIZEOF(&tcp_make)); 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.ssl_certfile = STIO_MT("localhost.crt"); 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) { diff --git a/stio/lib/stio-sck.c b/stio/lib/stio-sck.c index f34276a..8dbbf04 100644 --- a/stio/lib/stio-sck.c +++ b/stio/lib/stio-sck.c @@ -75,13 +75,6 @@ void stio_closeasyncsck (stio_t* stio, stio_sckhnd_t sck) #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) { 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) @@ -671,6 +694,12 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg) #if defined(USE_SSL) SSL_CTX* ssl_ctx = STIO_NULL; #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) { @@ -727,6 +756,18 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg) #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 defined(USE_SSL) @@ -753,10 +794,10 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg) 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); - rdev->ssl_accept_tmout = bnd->ssl_accept_tmout; + rdev->tmout = bnd->accept_tmout; #else rdev->stio->errnum = STIO_ENOIMPL; return -1; @@ -794,6 +835,14 @@ static int dev_sck_ioctl (stio_dev_t* dev, int cmd, void* arg) #if defined(USE_SSL) SSL_CTX* ssl_ctx = STIO_NULL; #endif + + if (STIO_DEV_SCK_GET_PROGRESS(rdev)) + { + /* can't connect again */ + rdev->stio->errnum = STIO_EPERM; + return -1; + } + if (!IS_STATEFUL(rdev)) { 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 (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) { 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 - /*{ int flags = fcntl (rdev->sck, F_GETFL); 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); fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK); }*/ - if (x == -1) { if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) @@ -844,22 +903,13 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK); } else { - stio_tmrjob_t tmrjob; - - if (stio_ispostime(&conn->tmout)) + if (stio_ispostime(&conn->connect_tmout) && + schedule_timer_job (rdev, &conn->connect_tmout, tmr_connect_handle) <= -1) { - STIO_MEMSET (&tmrjob, 0, STIO_SIZEOF(tmrjob)); - 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; + goto oops_connect; } + rdev->tmout = conn->connect_tmout; rdev->remoteaddr = conn->remoteaddr; rdev->on_connect = conn->on_connect; rdev->on_disconnect = conn->on_disconnect; @@ -888,13 +938,9 @@ fcntl (rdev->sck, F_SETFL, flags | O_NONBLOCK); else { /* connected immediately */ - rdev->remoteaddr = conn->remoteaddr; rdev->on_connect = conn->on_connect; rdev->on_disconnect = conn->on_disconnect; - #if defined(USE_SSL) - rdev->ssl_ctx = ssl_ctx; - #endif sl = STIO_SIZEOF(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) { int x; + rdev->ssl_ctx = ssl_ctx; + 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) { + STIO_ASSERT (rdev->tmrjob_index == STIO_TMRIDX_INVALID); + 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; + } + + rdev->tmout = conn->connect_tmout; STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTING_SSL); -/* TODO: schedule a ssl-connecting timeout job */ } - else goto connect_ok; + else + { + goto ssl_connected; + } } else { - connect_ok: + ssl_connected: #endif STIO_DEV_SCK_SET_PROGRESS (rdev, STIO_DEV_SCK_CONNECTED); 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; int x; + if (STIO_DEV_SCK_GET_PROGRESS(rdev)) + { + /* can't listen again */ + rdev->stio->errnum = STIO_EPERM; + return -1; + } + if (!IS_STATEFUL(rdev)) { 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 == 0) { - /* not SSL-connected */ + /* underlying socket connected but not SSL-connected */ 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; } else @@ -1163,25 +1252,12 @@ static int accept_incoming_connection (stio_dev_sck_t* rdev) /* let the client device know the SSL context to use */ 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 */ - /* timer job scheduling failed. halt the device */ - stio_dev_halt ((stio_dev_t*)clidev); - } + /* TODO: call a warning/error callback */ + /* timer job scheduling failed. halt the device */ + stio_dev_halt ((stio_dev_t*)clidev); } } else diff --git a/stio/lib/stio-sck.h b/stio/lib/stio-sck.h index 2e34200..7bf8eca 100644 --- a/stio/lib/stio-sck.h +++ b/stio/lib/stio-sck.h @@ -186,7 +186,7 @@ struct stio_dev_sck_bind_t const stio_mchar_t* ssl_certfile; const stio_mchar_t* ssl_keyfile; - stio_ntime_t ssl_accept_tmout; + stio_ntime_t accept_tmout; }; enum stio_def_sck_connect_option_t @@ -201,7 +201,7 @@ struct stio_dev_sck_connect_t { int options; 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_disconnect_t on_disconnect; }; @@ -229,9 +229,11 @@ struct stio_dev_sck_t stio_dev_sck_type_t type; stio_sckhnd_t sck; + /* connect timeout, ssl-connect timeout, ssl-accept timeout */ + stio_ntime_t tmout; + void* ssl_ctx; void* ssl; - stio_ntime_t ssl_accept_tmout; int state; @@ -289,10 +291,10 @@ STIO_EXPORT int stio_makesckasync ( ); STIO_EXPORT int stio_getsckaddrinfo ( - stio_t* stio, - const stio_sckaddr_t* addr, - stio_scklen_t* len, - stio_sckfam_t* family + stio_t* stio, + const stio_sckaddr_t* addr, + stio_scklen_t* len, + stio_sckfam_t* family ); /* @@ -306,19 +308,19 @@ STIO_EXPORT stio_uint16_t stio_getsckaddrport ( STIO_EXPORT void stio_sckaddr_initforip4 ( stio_sckaddr_t* sckaddr, - stio_uint16_t port, + stio_uint16_t port, stio_ip4addr_t* ip4addr ); STIO_EXPORT void stio_sckaddr_initforip6 ( stio_sckaddr_t* sckaddr, - stio_uint16_t port, + stio_uint16_t port, stio_ip6addr_t* ip6addr ); STIO_EXPORT void stio_sckaddr_initforeth ( stio_sckaddr_t* sckaddr, - int ifindex, + int ifindex, stio_ethaddr_t* ethaddr ); @@ -354,11 +356,11 @@ STIO_EXPORT int stio_dev_sck_write ( ); STIO_EXPORT int stio_dev_sck_timedwrite ( - stio_dev_sck_t* dev, - const void* data, - stio_iolen_t len, - const stio_ntime_t* tmout, - void* wrctx, + stio_dev_sck_t* dev, + const void* data, + stio_iolen_t len, + const stio_ntime_t* tmout, + void* wrctx, const stio_sckaddr_t* dstaddr ); diff --git a/stio/lib/stio.c b/stio/lib/stio.c index 2812aa9..b3be147 100644 --- a/stio/lib/stio.c +++ b/stio/lib/stio.c @@ -1155,6 +1155,11 @@ stio_errnum_t stio_syserrtoerrnum (int no) return STIO_ECONRS; #endif + #if defined(EPERM) + case EPERM: + return STIO_EPERM; + #endif + default: return STIO_ESYSERR; } diff --git a/stio/lib/stio.h b/stio/lib/stio.h index 1d31a42..a65faa7 100644 --- a/stio/lib/stio.h +++ b/stio/lib/stio.h @@ -107,6 +107,7 @@ enum stio_errnum_t STIO_ECONRS, /* connection reset */ STIO_ENOCAPA, /* no capability */ STIO_ETMOUT, /* timed out */ + STIO_EPERM, /* operation not permitted */ STIO_EDEVMAKE, STIO_EDEVERR, @@ -133,13 +134,6 @@ typedef void (*stio_tmrjob_handler_t) ( 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 { /* ------------------------------------------------------------------ */