2020-05-25 08:04:30 +00:00
/*
Copyright ( c ) 2016 - 2020 Chung , Hyung - Hwan . All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
2022-06-11 05:32:01 +00:00
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
2020-05-25 08:04:30 +00:00
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "http-prv.h"
2021-07-22 07:30:20 +00:00
# include <hio-path.h>
2021-08-10 10:32:36 +00:00
# include <errno.h>
2020-05-05 15:12:08 +00:00
2021-08-09 08:24:21 +00:00
# define INVALID_LIDX HIO_TYPE_MAX(hio_oow_t)
2020-05-05 15:12:08 +00:00
/* ------------------------------------------------------------------------ */
2021-07-22 07:30:20 +00:00
static int client_htrd_peek_request ( hio_htrd_t * htrd , hio_htre_t * req )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_htrd_xtn_t * htrdxtn = ( hio_svc_htts_cli_htrd_xtn_t * ) hio_htrd_getxtn ( htrd ) ;
hio_svc_htts_cli_t * sckxtn = ( hio_svc_htts_cli_t * ) hio_dev_sck_getxtn ( htrdxtn - > sck ) ;
2020-05-20 16:14:36 +00:00
return sckxtn - > htts - > proc_req ( sckxtn - > htts , htrdxtn - > sck , req ) ;
2020-05-06 09:28:36 +00:00
}
2021-07-22 07:30:20 +00:00
static hio_htrd_recbs_t client_htrd_recbs =
2020-05-06 09:28:36 +00:00
{
client_htrd_peek_request ,
2021-07-22 07:30:20 +00:00
HIO_NULL ,
HIO_NULL
2020-05-06 09:28:36 +00:00
} ;
2021-07-22 07:30:20 +00:00
static int init_client ( hio_svc_htts_cli_t * cli , hio_dev_sck_t * sck )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_htrd_xtn_t * htrdxtn ;
2020-05-06 09:28:36 +00:00
2020-05-12 11:46:00 +00:00
/* the htts field must be filled with the same field in the listening socket upon accept() */
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( sck - > hio , cli - > htts ! = HIO_NULL ) ;
2021-08-09 08:24:21 +00:00
HIO_ASSERT ( sck - > hio , cli - > l_idx < cli - > htts - > l . count ) ; /* at this point, it's still the listener's index as it's cloned */
2021-07-22 07:30:20 +00:00
HIO_ASSERT ( sck - > hio , sck - > hio = = cli - > htts - > hio ) ;
2020-05-06 09:28:36 +00:00
2020-07-16 10:46:17 +00:00
cli - > sck = sck ;
2022-10-08 07:47:55 +00:00
if ( hio_dev_sck_getpeeraddr ( sck , & cli - > cli_addr ) > = 0 )
hio_skadtobcstr ( sck - > hio , & cli - > cli_addr , cli - > cli_addr_bcstr , HIO_COUNTOF ( cli - > cli_addr_bcstr ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-09 08:24:21 +00:00
cli - > l_idx = INVALID_LIDX ; /* not a listening socket anymore */
2021-07-22 07:30:20 +00:00
cli - > htrd = HIO_NULL ;
cli - > sbuf = HIO_NULL ;
cli - > rsrc = HIO_NULL ;
2020-07-16 10:46:17 +00:00
/* keep this linked regardless of success or failure because the disconnect() callback
* will call fini_client ( ) . the error handler code after ' oops : ' doesn ' t get this unlinked */
2021-07-22 07:30:20 +00:00
HIO_SVC_HTTS_CLIL_APPEND_CLI ( & cli - > htts - > cli , cli ) ;
2020-07-16 10:46:17 +00:00
2021-07-22 07:30:20 +00:00
cli - > htrd = hio_htrd_open ( sck - > hio , HIO_SIZEOF ( * htrdxtn ) ) ;
if ( HIO_UNLIKELY ( ! cli - > htrd ) ) goto oops ;
2020-05-06 09:28:36 +00:00
2021-07-22 07:30:20 +00:00
/* With HIO_HTRD_TRAILERS, htrd stores trailers in a separate place.
2020-05-19 09:11:39 +00:00
* Otherwise , it is merged to the headers . */
2021-07-22 07:30:20 +00:00
/*hio_htrd_setoption (cli->htrd, HIO_HTRD_REQUEST | HIO_HTRD_TRAILERS);*/
2020-05-19 09:11:39 +00:00
2021-07-22 07:30:20 +00:00
cli - > sbuf = hio_becs_open ( sck - > hio , 0 , 2048 ) ;
if ( HIO_UNLIKELY ( ! cli - > sbuf ) ) goto oops ;
2020-05-16 19:12:10 +00:00
2021-07-22 07:30:20 +00:00
htrdxtn = hio_htrd_getxtn ( cli - > htrd ) ;
2020-05-12 11:46:00 +00:00
htrdxtn - > sck = sck ; /* TODO: remember cli instead? */
2020-05-06 09:28:36 +00:00
2021-07-22 07:30:20 +00:00
hio_htrd_setrecbs ( cli - > htrd , & client_htrd_recbs ) ;
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
hio_gettime ( sck - > hio , & cli - > last_active ) ;
2022-10-08 07:47:55 +00:00
HIO_DEBUG4 ( sck - > hio , " HTTS(%p) - initialized client(%p,%p,%d) \n " , cli - > htts , cli , sck , ( int ) sck - > hnd ) ;
2020-05-06 09:28:36 +00:00
return 0 ;
oops :
2020-07-16 10:46:17 +00:00
/* since this function is called in the on_connect() callback,
* fini_client ( ) is eventually called by on_disconnect ( ) . i don ' t do clean - up here .
2020-05-12 11:46:00 +00:00
if ( cli - > sbuf )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_becs_close ( cli - > sbuf ) ;
cli - > sbuf = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-12 11:46:00 +00:00
if ( cli - > htrd )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_htrd_close ( cli - > htrd ) ;
cli - > htrd = HIO_NULL ;
2020-07-16 10:46:17 +00:00
} */
2020-05-06 09:28:36 +00:00
return - 1 ;
}
2021-07-22 07:30:20 +00:00
static void fini_client ( hio_svc_htts_cli_t * cli )
2020-05-06 09:28:36 +00:00
{
2022-10-08 07:47:55 +00:00
HIO_DEBUG4 ( cli - > sck - > hio , " HTTS(%p) - finalizing client(%p,%p,%d) \n " , cli - > htts , cli , cli - > sck , ( int ) cli - > sck - > hnd ) ;
2020-05-12 17:53:19 +00:00
2020-05-18 16:40:00 +00:00
if ( cli - > rsrc )
{
2022-10-08 07:47:55 +00:00
#if 0
2021-07-22 07:30:20 +00:00
hio_svc_htts_rsrc_kill ( cli - > rsrc ) ;
cli - > rsrc = HIO_NULL ;
2022-10-08 07:47:55 +00:00
# else
HIO_SVC_HTTS_RSRC_DETACH ( cli - > rsrc ) ;
# endif
2020-05-18 16:40:00 +00:00
}
2020-05-12 11:46:00 +00:00
if ( cli - > sbuf )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_becs_close ( cli - > sbuf ) ;
cli - > sbuf = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-18 16:40:00 +00:00
2020-05-12 11:46:00 +00:00
if ( cli - > htrd )
2020-05-06 09:28:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_htrd_close ( cli - > htrd ) ;
cli - > htrd = HIO_NULL ;
2020-05-06 09:28:36 +00:00
}
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
HIO_SVC_HTTS_CLIL_UNLINK_CLI_CLEAN ( cli ) ;
2020-05-12 17:53:19 +00:00
/* are these needed? not symmetrical if done here.
* these fields are copied from the listener socket upon accept .
* init_client ( ) doesn ' t fill in these fields . let ' s comment out these lines
2021-07-22 07:30:20 +00:00
cli - > sck = HIO_NULL ;
cli - > htts = HIO_NULL ;
2020-05-12 17:53:19 +00:00
*/
2020-05-06 09:28:36 +00:00
}
/* ------------------------------------------------------------------------ */
2021-07-22 07:30:20 +00:00
static int listener_on_read ( hio_dev_sck_t * sck , const void * buf , hio_iolen_t len , const hio_skad_t * srcaddr )
2020-05-05 15:12:08 +00:00
{
2020-05-15 06:18:49 +00:00
/* unlike the function name, this callback is set on both the listener and the client.
* however , it must never be triggered for the listener */
2021-07-22 07:30:20 +00:00
hio_t * hio = sck - > hio ;
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
hio_oow_t rem ;
2020-05-15 06:18:49 +00:00
int x ;
2021-08-09 08:24:21 +00:00
HIO_ASSERT ( hio , cli - > l_idx = = INVALID_LIDX ) ;
/* if a resource has been set(cli->rsrc not NULL), the resource must take over
* this handler . this handler is never called unless the the overriding handler
* call this . */
HIO_ASSERT ( hio , cli - > rsrc = = HIO_NULL ) ;
2020-05-15 06:18:49 +00:00
2020-05-16 19:12:10 +00:00
if ( len < = - 1 )
{
2021-07-22 07:30:20 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - unable to read client %p(%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-16 19:12:10 +00:00
goto oops ;
}
2020-05-20 10:25:12 +00:00
if ( len = = 0 )
{
2021-07-22 07:30:20 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - EOF on client %p(%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-20 10:25:12 +00:00
goto oops ;
}
2020-05-16 19:12:10 +00:00
2021-07-22 07:30:20 +00:00
hio_gettime ( hio , & cli - > last_active ) ;
if ( ( x = hio_htrd_feed ( cli - > htrd , buf , len , & rem ) ) < = - 1 )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - feed error onto client htrd %p(%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-18 16:40:00 +00:00
goto oops ;
2020-05-15 06:18:49 +00:00
}
2020-05-05 15:12:08 +00:00
2020-05-19 18:00:49 +00:00
if ( rem > 0 )
{
if ( cli - > rsrc )
{
/* TODO store this to client buffer. once the current resource is completed, arrange to call on_read() with it */
}
else
{
/* TODO: no resource in action. so feed one more time */
}
}
2020-05-05 15:12:08 +00:00
return 0 ;
2020-05-16 19:12:10 +00:00
oops :
2021-07-22 07:30:20 +00:00
hio_dev_sck_halt ( sck ) ;
2020-07-28 10:21:10 +00:00
return 0 ; /* still return success here. instead call halt() */
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
static int listener_on_write ( hio_dev_sck_t * sck , hio_iolen_t wrlen , void * wrctx , const hio_skad_t * dstaddr )
2020-05-05 15:12:08 +00:00
{
2021-08-09 08:24:21 +00:00
/* don't get deluded by the name. it's set on both the listener and the client.
* it is not supposed to be triggered on the listener , however */
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ;
2021-08-09 08:24:21 +00:00
HIO_ASSERT ( sck - > hio , cli - > l_idx = = INVALID_LIDX ) ;
/* if a resource has been set(cli->rsrc not NULL), the resource must take over
* this handler . this handler is never called unless the the overriding handler
* call this . */
HIO_ASSERT ( sck - > hio , cli - > rsrc = = HIO_NULL ) ;
/* anyways, nothing to do upon write completion */
2020-05-10 16:20:39 +00:00
return 0 ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
static void listener_on_connect ( hio_dev_sck_t * sck )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = hio_dev_sck_getxtn ( sck ) ; /* the contents came from the listening socket */
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
if ( sck - > state & HIO_DEV_SCK_ACCEPTED )
2020-05-05 15:12:08 +00:00
{
/* accepted a new client */
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( sck - > hio , " HTTS(%p) - accepted client(%p,%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
2020-05-12 11:46:00 +00:00
if ( init_client ( cli , sck ) < = - 1 )
2020-05-05 15:12:08 +00:00
{
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( cli - > htts - > hio , " HTTS(%p) - halting client(%p,%d) for client intiaialization failure \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2021-07-22 07:30:20 +00:00
hio_dev_sck_halt ( sck ) ;
2020-05-05 15:12:08 +00:00
}
}
2021-07-22 07:30:20 +00:00
else if ( sck - > state & HIO_DEV_SCK_CONNECTED )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
/* this will never be triggered as the listing socket never call hio_dev_sck_connect() */
2022-10-08 07:47:55 +00:00
HIO_DEBUG3 ( sck - > hio , " HTTS(%p) - connected (%p,%d) \n " , cli - > htts , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
/* HIO_DEV_SCK_CONNECTED must not be seen here as this is only for the listener socket */
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
static void listener_on_disconnect ( hio_dev_sck_t * sck )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = sck - > hio ;
2021-08-06 03:23:48 +00:00
hio_svc_htts_cli_t * xtn = hio_dev_sck_getxtn ( sck ) ;
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
switch ( HIO_DEV_SCK_GET_PROGRESS ( sck ) )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTING :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2021-07-22 07:30:20 +00:00
HIO_DEBUG1 ( hio , " OUTGOING SESSION DISCONNECTED - FAILED TO CONNECT (%d) TO REMOTE SERVER \n " , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTING_SSL :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2021-07-22 07:30:20 +00:00
HIO_DEBUG1 ( hio , " OUTGOING SESSION DISCONNECTED - FAILED TO SSL-CONNECT (%d) TO REMOTE SERVER \n " , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_CONNECTED :
2020-05-07 10:10:33 +00:00
/* only for connecting sockets */
2021-07-22 07:30:20 +00:00
HIO_DEBUG1 ( hio , " OUTGOING CLIENT CONNECTION GOT TORN DOWN %p(%d)....... \n " , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_LISTENING :
HIO_DEBUG2 ( hio , " LISTNER SOCKET %p(%d) - SHUTTUING DOWN \n " , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_ACCEPTING_SSL : /* special case. */
2020-05-12 17:53:19 +00:00
/* this progress code indicates that the ssl-level accept failed.
* on_disconnected ( ) with this code is called without corresponding on_connect ( ) .
* the cli extension are is not initialized yet */
2021-08-06 03:23:48 +00:00
HIO_ASSERT ( hio , sck ! = xtn - > sck ) ;
//HIO_ASSERT (hio, cli->sck == cli->htts->lsck); /* the field is a copy of the extension are of the listener socket. so it should point to the listner socket */
2021-07-22 07:30:20 +00:00
HIO_DEBUG2 ( hio , " LISTENER UNABLE TO SSL-ACCEPT CLIENT %p(%d) ....%p \n " , sck , ( int ) sck - > hnd ) ;
2020-05-12 17:53:19 +00:00
return ;
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
case HIO_DEV_SCK_ACCEPTED :
2020-05-07 10:10:33 +00:00
/* only for sockets accepted by the listeners. will never come here because
* the disconnect call for such sockets have been changed in listener_on_connect ( ) */
2021-07-22 07:30:20 +00:00
HIO_DEBUG2 ( hio , " ACCEPTED CLIENT SOCKET %p(%d) GOT DISCONNECTED....... \n " , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
default :
2021-07-22 07:30:20 +00:00
HIO_DEBUG2 ( hio , " SOCKET %p(%d) DISCONNECTED AFTER ALL....... \n " , sck , ( int ) sck - > hnd ) ;
2020-05-05 15:12:08 +00:00
break ;
}
2021-08-06 03:23:48 +00:00
if ( xtn - > l_idx < xtn - > htts - > l . count )
2020-05-12 17:53:19 +00:00
{
/* the listener socket has these fields set to NULL */
2021-08-06 03:23:48 +00:00
HIO_ASSERT ( hio , xtn - > htrd = = HIO_NULL ) ;
HIO_ASSERT ( hio , xtn - > sbuf = = HIO_NULL ) ;
2020-05-07 04:32:32 +00:00
2021-08-06 03:23:48 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - listener socket disconnect %p \n " , xtn - > htts , sck ) ;
xtn - > htts - > l . sck [ xtn - > l_idx ] = HIO_NULL ; /* let the htts service forget about this listening socket */
2020-05-12 17:53:19 +00:00
}
else
{
/* client socket */
2021-08-06 03:23:48 +00:00
HIO_DEBUG2 ( hio , " HTTS(%p) - client socket disconnect %p \n " , xtn - > htts , sck ) ;
HIO_ASSERT ( hio , xtn - > sck = = sck ) ;
fini_client ( xtn ) ;
2020-05-12 17:53:19 +00:00
}
2020-05-05 15:12:08 +00:00
}
2020-08-01 15:56:53 +00:00
/* ------------------------------------------------------------------------ */
2020-08-02 16:07:42 +00:00
# define MAX_CLIENT_IDLE 10
2021-07-22 07:30:20 +00:00
static void halt_idle_clients ( hio_t * hio , const hio_ntime_t * now , hio_tmrjob_t * job )
2020-08-02 16:07:42 +00:00
{
/* 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 */
2021-07-22 07:30:20 +00:00
hio_svc_htts_t * htts = ( hio_svc_htts_t * ) job - > ctx ;
hio_svc_htts_cli_t * cli ;
hio_ntime_t t ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
static hio_ntime_t max_client_idle = { MAX_CLIENT_IDLE , 0 } ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
for ( cli = HIO_SVC_HTTS_CLIL_FIRST_CLI ( & htts - > cli ) ; ! HIO_SVC_HTTS_CLIL_IS_NIL_CLI ( & htts - > cli , cli ) ; cli = cli - > cli_next )
2020-08-02 16:07:42 +00:00
{
if ( ! cli - > rsrc )
{
2021-07-22 07:30:20 +00:00
hio_ntime_t t ;
HIO_SUB_NTIME ( & t , now , & cli - > last_active ) ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
if ( HIO_CMP_NTIME ( & t , & max_client_idle ) > = 0 )
2020-08-02 16:07:42 +00:00
{
2022-10-08 07:47:55 +00:00
HIO_DEBUG4 ( hio , " HTTS(%p) - Halting idle client(%p,%p,%d) \n " , htts , cli , cli - > sck , ( int ) cli - > sck - > hnd ) ;
2021-07-22 07:30:20 +00:00
hio_dev_sck_halt ( cli - > sck ) ;
2020-08-02 16:07:42 +00:00
}
}
}
2021-07-22 07:30:20 +00:00
HIO_INIT_NTIME ( & t , MAX_CLIENT_IDLE , 0 ) ;
HIO_ADD_NTIME ( & t , & t , now ) ;
if ( hio_schedtmrjobat ( hio , & t , halt_idle_clients , & htts - > idle_tmridx , htts ) < = - 1 )
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
HIO_INFO1 ( hio , " HTTS(%p) - unable to reschedule idle client detector. continuting \n " , htts ) ;
2020-08-02 16:07:42 +00:00
}
}
2020-05-05 15:12:08 +00:00
/* ------------------------------------------------------------------------ */
2022-10-07 05:08:40 +00:00
hio_svc_htts_t * hio_svc_htts_start ( hio_t * hio , hio_oow_t xtnsize , hio_dev_sck_bind_t * binds , hio_oow_t nbinds , hio_svc_htts_proc_req_t proc_req )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_t * htts = HIO_NULL ;
2020-05-05 15:12:08 +00:00
union
{
2021-07-22 07:30:20 +00:00
hio_dev_sck_make_t m ;
hio_dev_sck_listen_t l ;
2020-05-05 15:12:08 +00:00
} info ;
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli ;
2021-08-06 03:23:48 +00:00
hio_oow_t i , noks ;
if ( HIO_UNLIKELY ( nbinds < = 0 ) )
{
hio_seterrnum ( hio , HIO_EINVAL ) ;
goto oops ;
}
2020-05-05 15:12:08 +00:00
2022-10-07 05:08:40 +00:00
htts = ( hio_svc_htts_t * ) hio_callocmem ( hio , HIO_SIZEOF ( * htts ) + xtnsize ) ;
2021-07-22 07:30:20 +00:00
if ( HIO_UNLIKELY ( ! htts ) ) goto oops ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STARTING SERVICE %p \n " , htts ) ;
2021-07-22 07:30:20 +00:00
htts - > hio = hio ;
htts - > svc_stop = hio_svc_htts_stop ;
2020-05-20 16:14:36 +00:00
htts - > proc_req = proc_req ;
2021-07-22 07:30:20 +00:00
htts - > idle_tmridx = HIO_TMRIDX_INVALID ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
htts - > l . sck = ( hio_dev_sck_t * * ) hio_callocmem ( hio , HIO_SIZEOF ( * htts - > l . sck ) * nbinds ) ;
if ( HIO_UNLIKELY ( ! htts - > l . sck ) ) goto oops ;
htts - > l . count = nbinds ;
for ( i = 0 , noks = 0 ; i < nbinds ; i + + )
2020-05-05 15:12:08 +00:00
{
2021-08-06 03:23:48 +00:00
hio_dev_sck_t * sck ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_MEMSET ( & info , 0 , HIO_SIZEOF ( info ) ) ;
2021-08-17 07:00:22 +00:00
switch ( hio_skad_get_family ( & binds [ i ] . localaddr ) )
2021-08-06 03:23:48 +00:00
{
case HIO_AF_INET :
info . m . type = HIO_DEV_SCK_TCP4 ;
break ;
case HIO_AF_INET6 :
info . m . type = HIO_DEV_SCK_TCP6 ;
break ;
# if defined(HIO_AF_UNIX)
case HIO_AF_UNIX :
info . m . type = HIO_DEV_SCK_UNIX ;
break ;
# endif
case HIO_AF_QX :
info . m . type = HIO_DEV_SCK_QX ;
break ;
default :
/* ignore this */
2021-08-17 07:00:22 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unsupported bind address type %d \n " , htts , i , ( int ) hio_skad_get_family ( & binds [ i ] . localaddr ) ) ;
2021-08-06 03:23:48 +00:00
continue ;
}
info . m . options = HIO_DEV_SCK_MAKE_LENIENT ;
info . m . on_write = listener_on_write ;
info . m . on_read = listener_on_read ;
info . m . on_connect = listener_on_connect ;
info . m . on_disconnect = listener_on_disconnect ;
sck = hio_dev_sck_make ( hio , HIO_SIZEOF ( * cli ) , & info . m ) ;
if ( HIO_UNLIKELY ( ! sck ) ) continue ;
/* the name 'cli' for the listening socket is awkward.
* the listening socket will use the htts , sck , and listening fields for tracking only .
* each accepted client socket gets the extension size for this size as well .
* most of other fields are used for client management . init_client ( ) will set
* the sck field to the client socket and the listening field to 0. */
cli = ( hio_svc_htts_cli_t * ) hio_dev_sck_getxtn ( sck ) ;
2022-10-08 07:47:55 +00:00
cli - > htts = htts ;
2021-08-06 03:23:48 +00:00
cli - > sck = sck ;
cli - > l_idx = i ;
if ( sck - > type ! = HIO_DEV_SCK_QX )
{
if ( hio_dev_sck_bind ( sck , & binds [ i ] ) < = - 1 )
{
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_skadtobcstr ( hio , & binds [ i ] . localaddr , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unable to bind to %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
hio_dev_sck_kill ( sck ) ;
continue ;
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_MEMSET ( & info , 0 , HIO_SIZEOF ( info ) ) ;
info . l . backlogs = 4096 ; /* TODO: use configuration? */
HIO_INIT_NTIME ( & info . l . accept_tmout , 5 , 1 ) ; /* usedd for ssl accept */
if ( hio_dev_sck_listen ( sck , & info . l ) < = - 1 )
{
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_skadtobcstr ( hio , & binds [ i ] . localaddr , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] unable to bind to %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
hio_dev_sck_kill ( sck ) ;
goto oops ;
}
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
if ( HIO_LOG_ENABLED ( hio , HIO_LOG_DEBUG ) )
{
hio_skad_t tmpad ;
hio_bch_t tmpbuf [ HIO_SKAD_IP_STRLEN + 1 ] ;
hio_dev_sck_getsockaddr ( sck , & tmpad ) ;
hio_skadtobcstr ( hio , & tmpad , tmpbuf , HIO_COUNTOF ( tmpbuf ) , HIO_SKAD_TO_BCSTR_ADDR | HIO_SKAD_TO_BCSTR_PORT ) ;
2021-08-10 10:32:36 +00:00
HIO_DEBUG3 ( hio , " HTTS(%p) - [%zu] listening on %hs \n " , htts , i , tmpbuf ) ;
2021-08-06 03:23:48 +00:00
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
htts - > l . sck [ i ] = sck ;
noks + + ;
2020-07-26 09:21:05 +00:00
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
if ( noks < = 0 ) goto oops ;
2021-07-22 07:30:20 +00:00
hio_fmttobcstr ( htts - > hio , htts - > server_name_buf , HIO_COUNTOF ( htts - > server_name_buf ) , " %s-%d.%d.%d " ,
HIO_PACKAGE_NAME , ( int ) HIO_PACKAGE_VERSION_MAJOR , ( int ) HIO_PACKAGE_VERSION_MINOR , ( int ) HIO_PACKAGE_VERSION_PATCH ) ;
2020-05-07 10:10:33 +00:00
htts - > server_name = htts - > server_name_buf ;
2021-07-22 07:30:20 +00:00
HIO_SVCL_APPEND_SVC ( & hio - > actsvc , ( hio_svc_t * ) htts ) ;
HIO_SVC_HTTS_CLIL_INIT ( & htts - > cli ) ;
2020-05-07 10:10:33 +00:00
2022-09-12 14:43:29 +00:00
htts - > fcgic = hio_svc_fcgic_start ( hio , HIO_NULL ) ; /* TODO: set timeout properly */
if ( HIO_UNLIKELY ( ! htts - > fcgic ) )
{
/* TODO: only warning ... */
}
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STARTED SERVICE %p \n " , htts ) ;
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
hio_ntime_t t ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
HIO_INIT_NTIME ( & t , MAX_CLIENT_IDLE , 0 ) ;
if ( hio_schedtmrjobafter ( hio , & t , halt_idle_clients , & htts - > idle_tmridx , htts ) < = - 1 )
2020-08-02 16:07:42 +00:00
{
2021-07-22 07:30:20 +00:00
HIO_INFO1 ( hio , " HTTS(%p) - unable to schedule idle client detector. continuting \n " , htts ) ;
2020-08-02 16:07:42 +00:00
/* don't care about failure */
}
}
2020-05-05 15:12:08 +00:00
return htts ;
oops :
if ( htts )
{
2022-09-12 14:43:29 +00:00
if ( htts - > fcgic )
{
hio_svc_fcgic_stop ( htts - > fcgic ) ;
htts - > fcgic = HIO_NULL ;
}
2021-08-06 03:23:48 +00:00
if ( htts - > l . sck )
{
for ( i = 0 ; i < htts - > l . count ; i + + )
2021-08-10 11:31:21 +00:00
{
if ( htts - > l . sck [ i ] ) hio_dev_sck_kill ( htts - > l . sck [ i ] ) ;
}
2021-08-06 03:23:48 +00:00
hio_freemem ( hio , htts - > l . sck ) ;
}
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , htts ) ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
return HIO_NULL ;
2020-05-05 15:12:08 +00:00
}
2021-07-22 07:30:20 +00:00
void hio_svc_htts_stop ( hio_svc_htts_t * htts )
2020-05-05 15:12:08 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
2021-08-06 03:23:48 +00:00
hio_oow_t i ;
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
HIO_DEBUG1 ( hio , " HTTS - STOPPING SERVICE %p \n " , htts ) ;
2020-05-07 10:10:33 +00:00
2022-09-12 14:43:29 +00:00
if ( htts - > fcgic )
{
hio_svc_fcgic_stop ( htts - > fcgic ) ;
htts - > fcgic = HIO_NULL ;
}
2021-08-06 03:23:48 +00:00
for ( i = 0 ; i < htts - > l . count ; i + + )
{
/* the socket may be null:
* if it has been destroyed for operation errors and forgotten in the disconnect callback thereafter
* if it has never been created successfully */
if ( htts - > l . sck [ i ] ) hio_dev_sck_kill ( htts - > l . sck [ i ] ) ;
}
2020-05-07 10:10:33 +00:00
2021-07-22 07:30:20 +00:00
while ( ! HIO_SVC_HTTS_CLIL_IS_EMPTY ( & htts - > cli ) )
2020-05-12 11:46:00 +00:00
{
2021-07-22 07:30:20 +00:00
hio_svc_htts_cli_t * cli = HIO_SVC_HTTS_CLIL_FIRST_CLI ( & htts - > cli ) ;
hio_dev_sck_kill ( cli - > sck ) ;
2020-05-12 11:46:00 +00:00
}
2020-05-05 15:12:08 +00:00
2021-07-22 07:30:20 +00:00
HIO_SVCL_UNLINK_SVC ( htts ) ;
if ( htts - > server_name & & htts - > server_name ! = htts - > server_name_buf ) hio_freemem ( hio , htts - > server_name ) ;
2020-08-02 16:07:42 +00:00
2021-07-22 07:30:20 +00:00
if ( htts - > idle_tmridx ! = HIO_TMRIDX_INVALID ) hio_deltmrjob ( hio , htts - > idle_tmridx ) ;
2020-08-02 16:07:42 +00:00
2021-08-06 03:23:48 +00:00
if ( htts - > l . sck ) hio_freemem ( hio , htts - > l . sck ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , htts ) ;
2020-05-05 15:12:08 +00:00
}
2022-10-07 05:08:40 +00:00
void * hio_svc_htts_getxtn ( hio_svc_htts_t * htts )
{
return ( void * ) ( htts + 1 ) ;
}
2021-07-22 07:30:20 +00:00
int hio_svc_htts_setservernamewithbcstr ( hio_svc_htts_t * htts , const hio_bch_t * name )
2020-05-07 10:10:33 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
hio_bch_t * tmp ;
2020-05-07 10:10:33 +00:00
2021-07-22 07:30:20 +00:00
if ( hio_copy_bcstr ( htts - > server_name_buf , HIO_COUNTOF ( htts - > server_name_buf ) , name ) = = hio_count_bcstr ( name ) )
2020-05-07 10:10:33 +00:00
{
tmp = htts - > server_name_buf ;
}
else
{
2021-07-22 07:30:20 +00:00
tmp = hio_dupbcstr ( hio , name , HIO_NULL ) ;
2020-05-07 10:10:33 +00:00
if ( ! tmp ) return - 1 ;
}
2021-07-22 07:30:20 +00:00
if ( htts - > server_name & & htts - > server_name ! = htts - > server_name_buf ) hio_freemem ( hio , htts - > server_name ) ;
2020-05-07 10:10:33 +00:00
htts - > server_name = tmp ;
return 0 ;
}
2020-05-05 15:12:08 +00:00
2021-08-06 03:23:48 +00:00
hio_dev_sck_t * hio_svc_htts_getlistendev ( hio_svc_htts_t * htts , hio_oow_t idx )
{
if ( idx > = htts - > l . count )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ;
return HIO_NULL ;
}
if ( ! htts - > l . sck [ idx ] )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ;
return HIO_NULL ;
}
return htts - > l . sck [ idx ] ;
}
hio_oow_t hio_svc_htts_getnlistendevs ( hio_svc_htts_t * htts )
{
/* return the total number of listening socket devices.
* not all devices may be up and working */
return htts - > l . count ;
}
int hio_svc_htts_getsockaddr ( hio_svc_htts_t * htts , hio_oow_t idx , hio_skad_t * skad )
2021-07-16 02:30:25 +00:00
{
/* return the socket address of the listening socket. */
2021-08-06 03:23:48 +00:00
if ( idx > = htts - > l . count )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ;
return - 1 ;
}
if ( ! htts - > l . sck [ idx ] )
{
hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ;
return - 1 ;
}
return hio_dev_sck_getsockaddr ( htts - > l . sck [ idx ] , skad ) ;
2021-07-16 02:30:25 +00:00
}
2020-05-08 09:48:26 +00:00
/* ----------------------------------------------------------------- */
2022-10-07 05:08:40 +00:00
/* rsrc_size must be the total size to allocate including the header.
*
* For instance , if you define a resource like below ,
*
* struct my_rsrc_t
* {
* HIO_SVC_HTTS_RSRC_HEADER ;
* int a ;
* int b ;
* } ;
*
* you can pass sizeof ( my_rsrc_t ) to hio_svc_htts_rsrc_make ( )
*/
2021-07-22 07:30:20 +00:00
hio_svc_htts_rsrc_t * hio_svc_htts_rsrc_make ( hio_svc_htts_t * htts , hio_oow_t rsrc_size , hio_svc_htts_rsrc_on_kill_t on_kill )
2020-05-07 15:47:33 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = htts - > hio ;
hio_svc_htts_rsrc_t * rsrc ;
2020-05-08 09:48:26 +00:00
2021-07-22 07:30:20 +00:00
rsrc = hio_callocmem ( hio , rsrc_size ) ;
if ( HIO_UNLIKELY ( ! rsrc ) ) return HIO_NULL ;
2020-05-08 09:48:26 +00:00
rsrc - > htts = htts ;
2020-05-18 16:40:00 +00:00
rsrc - > rsrc_size = rsrc_size ;
rsrc - > rsrc_refcnt = 0 ;
rsrc - > rsrc_on_kill = on_kill ;
2020-05-08 09:48:26 +00:00
return rsrc ;
}
2021-07-22 07:30:20 +00:00
void hio_svc_htts_rsrc_kill ( hio_svc_htts_rsrc_t * rsrc )
2020-05-08 09:48:26 +00:00
{
2021-07-22 07:30:20 +00:00
hio_t * hio = rsrc - > htts - > hio ;
2020-05-18 16:40:00 +00:00
if ( rsrc - > rsrc_on_kill ) rsrc - > rsrc_on_kill ( rsrc ) ;
2021-07-22 07:30:20 +00:00
hio_freemem ( hio , rsrc ) ;
2020-05-08 09:48:26 +00:00
}
2020-05-12 11:46:00 +00:00
/* ----------------------------------------------------------------- */
2020-05-20 16:14:36 +00:00
2020-05-16 19:12:10 +00:00
/* ----------------------------------------------------------------- */
2020-05-12 11:46:00 +00:00
2021-07-22 07:30:20 +00:00
int hio_svc_htts_doproxy ( hio_svc_htts_t * htts , hio_dev_sck_t * csck , hio_htre_t * req , const hio_bch_t * upstream )
2020-05-06 09:28:36 +00:00
{
2020-05-12 11:46:00 +00:00
#if 0
2020-05-08 09:48:26 +00:00
1. attempt to connect to the proxy target . . .
2. in the mean time ,
2021-07-22 07:30:20 +00:00
hio_dev_watch ( csck , HIO_DEV_WATCH_UPDATE , 0 ) ; /* no input, no output watching */
2020-05-08 09:48:26 +00:00
3. once connected ,
2021-07-22 07:30:20 +00:00
hio_dev_watch ( csck , HIO_DEV_WATCH_RENEW , HIO_DEV_EVENT_IN ) ; /* enable input watching. if needed, enable output watching */
2020-05-08 09:48:26 +00:00
4. start proxying
2020-05-10 16:20:39 +00:00
5. if one side is stalled , donot read from another side . . . let the kernel slow the connection . . .
2020-05-08 09:48:26 +00:00
i need to know how may bytes are pending for this .
2021-07-22 07:30:20 +00:00
if pending too high , disable read watching . . . hio_dev_watch ( csck , HIO_DEV_WATCH_RENEW , 0 ) ;
2020-05-08 09:48:26 +00:00
# endif
2020-05-12 11:46:00 +00:00
return 0 ;
}
2020-05-18 16:40:00 +00:00
/* ----------------------------------------------------------------- */
2021-07-22 07:30:20 +00:00
void hio_svc_htts_fmtgmtime ( hio_svc_htts_t * htts , const hio_ntime_t * nt , hio_bch_t * buf , hio_oow_t len )
2020-05-18 16:40:00 +00:00
{
2021-07-22 07:30:20 +00:00
hio_ntime_t now ;
2020-05-18 16:40:00 +00:00
if ( ! nt )
{
2021-07-22 07:30:20 +00:00
hio_sys_getrealtime ( htts - > hio , & now ) ;
2020-05-18 16:40:00 +00:00
nt = & now ;
}
2021-07-22 07:30:20 +00:00
hio_fmt_http_time_to_bcstr ( nt , buf , len ) ;
2020-05-18 16:40:00 +00:00
}
2020-05-08 09:48:26 +00:00
2021-07-22 07:30:20 +00:00
hio_bch_t * hio_svc_htts_dupmergepaths ( hio_svc_htts_t * htts , const hio_bch_t * base , const hio_bch_t * path )
2020-05-20 16:14:36 +00:00
{
2021-07-22 07:30:20 +00:00
hio_bch_t * xpath ;
const hio_bch_t * ta [ 4 ] ;
hio_oow_t idx = 0 ;
2020-05-20 16:14:36 +00:00
ta [ idx + + ] = base ;
if ( path [ 0 ] ! = ' \0 ' )
{
2023-01-02 07:01:50 +00:00
if ( base [ hio_count_bcstr ( base ) - 1 ] ! = ' / ' ) ta [ idx + + ] = " / " ;
2020-05-20 16:14:36 +00:00
ta [ idx + + ] = path ;
}
2021-07-22 07:30:20 +00:00
ta [ idx + + ] = HIO_NULL ;
xpath = hio_dupbcstrs ( htts - > hio , ta , HIO_NULL ) ;
if ( HIO_UNLIKELY ( ! xpath ) ) return HIO_NULL ;
2020-05-20 16:14:36 +00:00
2021-07-22 07:30:20 +00:00
hio_canon_bcstr_path ( xpath , xpath , 0 ) ;
2020-05-20 16:14:36 +00:00
return xpath ;
}
2021-08-06 03:23:48 +00:00
int hio_svc_htts_writetosidechan ( hio_svc_htts_t * htts , hio_oow_t idx , const void * dptr , hio_oow_t dlen )
2020-07-24 17:29:52 +00:00
{
2021-08-06 03:23:48 +00:00
if ( idx > = htts - > l . count )
{
2021-08-10 10:32:36 +00:00
/* don't set the error information - TODO: change hio_seterrbfmt thread-safe?
* hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " index out of range " ) ; */
errno = EINVAL ;
2021-08-06 03:23:48 +00:00
return - 1 ;
}
if ( ! htts - > l . sck [ idx ] )
{
2021-08-10 10:32:36 +00:00
/* don't set the error information
* hio_seterrbfmt ( htts - > hio , HIO_EINVAL , " no listener at the given index " ) ; */
errno = EINVAL ;
2021-08-06 03:23:48 +00:00
return - 1 ;
}
return hio_dev_sck_writetosidechan ( htts - > l . sck [ idx ] , dptr , dlen ) ;
2020-07-24 17:29:52 +00:00
}