From c5598970d7380417b10ea9bd6492ab59bf7af7be Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 2 Aug 2020 16:07:42 +0000 Subject: [PATCH] implemented primitive idle client detector in htts --- mio/bin/t06.c | 17 -------------- mio/lib/http-fil.c | 27 +++++++++++++++++----- mio/lib/http-prv.h | 2 ++ mio/lib/http-svr.c | 57 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/mio/bin/t06.c b/mio/bin/t06.c index ad02b1e..5de7541 100644 --- a/mio/bin/t06.c +++ b/mio/bin/t06.c @@ -342,22 +342,6 @@ struct xx_mq_t static xx_mq_t xx_mq; -#if 0 -static int schedule_timer_job_at (mio_dev_sck_t* dev, const mio_ntime_t* fire_at, mio_tmrjob_handler_t handler, mio_tmridx_t* tmridx) -{ - mio_tmrjob_t tmrjob; - - memset (&tmrjob, 0, MIO_SIZEOF(tmrjob)); - tmrjob.ctx = dev; - if (fire_at) tmrjob.when = *fire_at; - - tmrjob.handler = handler; - tmrjob.idxptr = tmridx; - - return mio_instmrjob(dev->mio, &tmrjob); -} -#endif - static void enable_accept (mio_t* mio, const mio_ntime_t* now, mio_tmrjob_t* job) { mio_dev_sck_t* rdev = (mio_dev_sck_t*)job->ctx; @@ -452,7 +436,6 @@ static void tcp_sck_on_raw_accept (mio_dev_sck_t* sck, mio_syshnd_t syshnd, mio_ qxmsg.syshnd = syshnd; qxmsg.remoteaddr = *remoteaddr; -//printf ("A %d\n", qxmsg.syshnd); try_to_accept (sck, &qxmsg, 0); } diff --git a/mio/lib/http-fil.c b/mio/lib/http-fil.c index 163326f..0013461 100644 --- a/mio/lib/http-fil.c +++ b/mio/lib/http-fil.c @@ -218,7 +218,6 @@ static void file_state_mark_over (file_state_t* file_state, int over_bits) /* how to arrange to delete this file_state object and put the socket back to the normal waiting state??? */ MIO_ASSERT (file_state->htts->mio, file_state->client->rsrc == (mio_svc_htts_rsrc_t*)file_state); - MIO_SVC_HTTS_RSRC_DETACH (file_state->client->rsrc); /* file_state must not be accessed from here down as it could have been destroyed */ } @@ -293,7 +292,6 @@ static void file_state_on_kill (file_state_t* file_state) } } - static void file_client_on_disconnect (mio_dev_sck_t* sck) { mio_svc_htts_cli_t* cli = mio_dev_sck_getxtn(sck); @@ -463,8 +461,6 @@ static int file_state_send_header_to_client (file_state_t* file_state, int statu cli->htts->server_name, dtbuf, (force_close? "close": "keep-alive"), mime_type) == (mio_oow_t)-1) return -1; -/* TODO: content_type */ - if (file_state->req_method == MIO_HTTP_GET && mio_becs_fcat(cli->sbuf, "ETag: %hs\r\n", file_state->peer_etag) == (mio_oow_t)-1) return -1; if (status_code == 206 && mio_becs_fcat(cli->sbuf, "Content-Ranges: bytes %ju-%ju/%ju\r\n", (mio_uintmax_t)file_state->start_offset, (mio_uintmax_t)file_state->end_offset, (mio_uintmax_t)file_state->total_size) == (mio_oow_t)-1) return -1; if (mio_becs_fcat(cli->sbuf, "Content-Length: %ju\r\n\r\n", (mio_uintmax_t)content_length) == (mio_oow_t)-1) return -1; @@ -552,6 +548,13 @@ static MIO_INLINE int process_range_header (file_state_t* file_state, mio_htre_t return -1; } + if ((st.st_mode & S_IFMT) == S_IFREG) + { + /* TODO: support directory listing if S_IFDIR? still disallow special files. */ + file_state_send_final_status_to_client (file_state, 403, 1); /* forbidden */ + return -1; + } + if (file_state->req_method == MIO_HTTP_GET) { etag_len = mio_fmt_uintmax_to_bcstr(&file_state->peer_etag[0], MIO_COUNTOF(file_state->peer_etag), st.st_mtim.tv_sec, 16, -1, '\0', MIO_NULL); @@ -631,13 +634,24 @@ static int open_peer (file_state_t* file_state, const mio_bch_t* actual_file) { case MIO_HTTP_GET: case MIO_HTTP_HEAD: + { + int flags; + if (access(actual_file, R_OK) == -1) { file_state_send_final_status_to_client (file_state, ERRNO_TO_STATUS_CODE(errno), 1); /* 404 not found 403 Forbidden */ return -1; } - file_state->peer = open(actual_file, O_RDONLY | O_NONBLOCK | O_CLOEXEC); + flags = O_RDONLY | O_NONBLOCK; + #if defined(O_CLOEXEC) + flags |= O_CLOEXEC; + #endif + #if defined(O_LARGEFILE) + flags |= O_LARGEFILE; + #endif + file_state->peer = open(actual_file, flags); + if (MIO_UNLIKELY(file_state->peer <= -1)) { file_state_send_final_status_to_client (file_state, ERRNO_TO_STATUS_CODE(errno), 1); @@ -645,6 +659,7 @@ static int open_peer (file_state_t* file_state, const mio_bch_t* actual_file) } return 0; + } #if 0 case MIO_HTTP_PUT: @@ -720,7 +735,7 @@ int mio_svc_htts_dofile (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* csck->on_write = file_client_on_write; csck->on_disconnect = file_client_on_disconnect; - MIO_ASSERT (mio, cli->rsrc == MIO_NULL); + MIO_ASSERT (mio, cli->rsrc == MIO_NULL); /* you must not call this function while cli->rsrc is not MIO_NULL */ MIO_SVC_HTTS_RSRC_ATTACH (file_state, cli->rsrc); file_state->peer_tmridx = MIO_TMRIDX_INVALID; diff --git a/mio/lib/http-prv.h b/mio/lib/http-prv.h index 7a2a7d2..768bd45 100644 --- a/mio/lib/http-prv.h +++ b/mio/lib/http-prv.h @@ -47,6 +47,7 @@ struct mio_svc_htts_cli_t mio_becs_t* sbuf; /* temporary buffer for status line formatting */ mio_svc_htts_rsrc_t* rsrc; + mio_ntime_t last_active; }; struct mio_svc_htts_cli_htrd_xtn_t @@ -63,6 +64,7 @@ struct mio_svc_htts_t mio_dev_sck_t* lsck; mio_svc_htts_cli_t cli; /* list head for client list */ + mio_tmridx_t idle_tmridx; mio_bch_t* server_name; mio_bch_t server_name_buf[64]; diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index 77f12ce..858c47a 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -74,7 +74,8 @@ static int init_client (mio_svc_htts_cli_t* cli, mio_dev_sck_t* sck) mio_htrd_setrecbs (cli->htrd, &client_htrd_recbs); -MIO_DEBUG3 (sck->mio, "HTTS(%p) - initialized client %p socket %p\n", cli->htts, cli, sck); + mio_gettime (sck->mio, &cli->last_active); + MIO_DEBUG3 (sck->mio, "HTTS(%p) - initialized client %p socket %p\n", cli->htts, cli, sck); return 0; oops: @@ -152,6 +153,7 @@ static int listener_on_read (mio_dev_sck_t* sck, const void* buf, mio_iolen_t le goto oops; } + mio_gettime (mio, &cli->last_active); if ((x = mio_htrd_feed(cli->htrd, buf, len, &rem)) <= -1) { MIO_DEBUG3 (mio, "HTTS(%p) - feed error onto client htrd %p(%d)\n", cli->htts, sck, (int)sck->hnd); @@ -275,6 +277,42 @@ printf ("listener socket disconnect..................sck %p %d\n", sck, sck->hnd } /* ------------------------------------------------------------------------ */ +#define MAX_CLIENT_IDLE 10 + + +static void halt_idle_clients (mio_t* mio, const mio_ntime_t* now, mio_tmrjob_t* job) +{ +/* TODO: this idle client detector is far away from being accurate. + * enhance htrd to specify timeout on feed() and utilize it... + * and remove this timer job */ + mio_svc_htts_t* htts = (mio_svc_htts_t*)job->ctx; + mio_svc_htts_cli_t* cli; + mio_ntime_t t; + + static mio_ntime_t max_client_idle = { MAX_CLIENT_IDLE, 0 }; + + for (cli = MIO_SVC_HTTS_CLIL_FIRST_CLI(&htts->cli); !MIO_SVC_HTTS_CLIL_IS_NIL_CLI(&htts->cli, cli); cli = cli->cli_next) + { + if (!cli->rsrc) + { + mio_ntime_t t; + MIO_SUB_NTIME(&t, now, &cli->last_active); + + if (MIO_CMP_NTIME(&t, &max_client_idle) >= 0) + { + MIO_DEBUG3 (mio, "HTTS(%p) - Halting idle client socket %p(client=%p)\n", htts, cli->sck, cli); + mio_dev_sck_halt (cli->sck); + } + } + } + + MIO_INIT_NTIME (&t, MAX_CLIENT_IDLE, 0); + MIO_ADD_NTIME (&t, &t, now); + if (mio_schedtmrjobat(mio, &t, halt_idle_clients, &htts->idle_tmridx, htts) <= -1) + { + MIO_INFO1 (mio, "HTTS(%p) - unable to reschedule idle client detector. continuting\n", htts); + } +} /* ------------------------------------------------------------------------ */ @@ -294,6 +332,7 @@ mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, mio_dev_sck_bind_t* sck_bind, mi htts->mio = mio; htts->svc_stop = mio_svc_htts_stop; htts->proc_req = proc_req; + htts->idle_tmridx = MIO_TMRIDX_INVALID; MIO_MEMSET (&info, 0, MIO_SIZEOF(info)); switch (mio_skad_family(&sck_bind->localaddr)) @@ -343,10 +382,23 @@ mio_svc_htts_t* mio_svc_htts_start (mio_t* mio, mio_dev_sck_bind_t* sck_bind, mi MIO_PACKAGE_NAME, (int)MIO_PACKAGE_VERSION_MAJOR, (int)MIO_PACKAGE_VERSION_MINOR, (int)MIO_PACKAGE_VERSION_PATCH); htts->server_name = htts->server_name_buf; + MIO_SVCL_APPEND_SVC (&mio->actsvc, (mio_svc_t*)htts); MIO_SVC_HTTS_CLIL_INIT (&htts->cli); MIO_DEBUG3 (mio, "HTTS - STARTED SERVICE %p - LISTENER SOCKET %p(%d)\n", htts, htts->lsck, (int)htts->lsck->hnd); + + { + mio_ntime_t t; + + MIO_INIT_NTIME (&t, MAX_CLIENT_IDLE, 0); + if (mio_schedtmrjobafter(mio, &t, halt_idle_clients, &htts->idle_tmridx, htts) <= -1) + { + MIO_INFO1 (mio, "HTTS(%p) - unable to schedule idle client detector. continuting\n", htts); + /* don't care about failure */ + } + } + return htts; oops: @@ -376,6 +428,9 @@ void mio_svc_htts_stop (mio_svc_htts_t* htts) MIO_SVCL_UNLINK_SVC (htts); if (htts->server_name && htts->server_name != htts->server_name_buf) mio_freemem (mio, htts->server_name); + + if (htts->idle_tmridx != MIO_TMRIDX_INVALID) mio_deltmrjob (mio, htts->idle_tmridx); + mio_freemem (mio, htts); }