2015-04-13 17:11:11 +02:00
/*
* Functions managing applets
*
* Copyright 2000 - 2015 Willy Tarreau < w @ 1 wt . eu >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
# include <stdio.h>
# include <stdlib.h>
2020-05-27 12:58:42 +02:00
# include <haproxy/api.h>
2020-06-09 09:07:15 +02:00
# include <haproxy/applet.h>
2020-06-04 21:07:02 +02:00
# include <haproxy/channel.h>
2020-05-27 18:01:47 +02:00
# include <haproxy/list.h>
2022-05-27 09:25:10 +02:00
# include <haproxy/sc_strm.h>
2022-05-27 09:47:12 +02:00
# include <haproxy/stconn.h>
2020-06-04 23:46:14 +02:00
# include <haproxy/stream.h>
2020-06-04 17:25:40 +02:00
# include <haproxy/task.h>
2015-04-13 17:11:11 +02:00
2016-12-06 09:13:22 +01:00
unsigned int nb_applets = 0 ;
2017-06-19 12:38:55 +02:00
2019-07-18 10:41:36 +02:00
DECLARE_POOL ( pool_head_appctx , " appctx " , sizeof ( struct appctx ) ) ;
2022-05-05 19:55:03 +02:00
/* Tries to allocate a new appctx and initialize all of its fields. The appctx
2022-03-23 11:46:56 +01:00
* is returned on success , NULL on failure . The appctx must be released using
* appctx_free ( ) . < applet > is assigned as the applet , but it can be NULL . The
* applet ' s task is always created on the current thread .
*/
2022-05-17 18:05:31 +02:00
struct appctx * appctx_new ( struct applet * applet , struct sedesc * sedesc , unsigned long thread_mask )
2022-03-23 11:46:56 +01:00
{
struct appctx * appctx ;
2022-05-16 17:15:31 +02:00
/* Backend appctx cannot be started on another thread than the local one */
2022-05-17 18:05:31 +02:00
BUG_ON ( thread_mask ! = tid_bit & & sedesc ) ;
2022-05-16 17:09:48 +02:00
2022-05-05 19:55:03 +02:00
appctx = pool_zalloc ( pool_head_appctx ) ;
2022-03-23 15:15:29 +01:00
if ( unlikely ( ! appctx ) )
goto fail_appctx ;
2022-05-05 19:55:03 +02:00
LIST_INIT ( & appctx - > wait_entry ) ;
2022-03-23 15:15:29 +01:00
appctx - > obj_type = OBJ_TYPE_APPCTX ;
appctx - > applet = applet ;
2022-05-09 08:08:26 +02:00
appctx - > sess = NULL ;
2022-05-17 18:05:31 +02:00
if ( ! sedesc ) {
sedesc = sedesc_new ( ) ;
if ( ! sedesc )
2022-03-23 15:15:29 +01:00
goto fail_endp ;
2022-05-17 18:05:31 +02:00
sedesc - > se = appctx ;
se_fl_set ( sedesc , SE_FL_T_APPLET | SE_FL_ORPHAN ) ;
2022-03-23 11:46:56 +01:00
}
2022-05-17 18:05:31 +02:00
appctx - > sedesc = sedesc ;
2022-03-23 15:15:29 +01:00
2022-05-16 17:09:48 +02:00
appctx - > t = task_new ( thread_mask ) ;
2022-03-23 15:15:29 +01:00
if ( unlikely ( ! appctx - > t ) )
goto fail_task ;
appctx - > t - > process = task_run_applet ;
appctx - > t - > context = appctx ;
LIST_INIT ( & appctx - > buffer_wait . list ) ;
appctx - > buffer_wait . target = appctx ;
appctx - > buffer_wait . wakeup_cb = appctx_buf_available ;
_HA_ATOMIC_INC ( & nb_applets ) ;
2022-03-23 11:46:56 +01:00
return appctx ;
2022-03-23 15:15:29 +01:00
fail_task :
2022-05-17 18:05:31 +02:00
sedesc_free ( appctx - > sedesc ) ;
2022-03-23 15:15:29 +01:00
fail_endp :
pool_free ( pool_head_appctx , appctx ) ;
fail_appctx :
return NULL ;
2022-03-23 11:46:56 +01:00
}
2022-05-12 15:15:53 +02:00
/* Finalize the frontend appctx startup. It must not be called for a backend
* appctx . This function is responsible to create the appctx ' s session and the
2022-05-17 19:07:51 +02:00
* frontend stream connector . By transitivity , the stream is also created .
2022-05-12 15:15:53 +02:00
*
* It returns 0 on success and - 1 on error . In this case , it is the caller
* responsibility to release the appctx . However , the session is released if it
* was created . On success , if an error is encountered in the caller function ,
2022-05-12 15:18:48 +02:00
* the stream must be released instead of the appctx . To be sure ,
* appctx_free_on_early_error ( ) must be called in this case .
2022-05-12 15:15:53 +02:00
*/
int appctx_finalize_startup ( struct appctx * appctx , struct proxy * px , struct buffer * input )
{
struct session * sess ;
2022-05-16 17:15:31 +02:00
/* async startup is only possible for frontend appctx. Thus for orphan
* appctx . Because no backend appctx can be orphan .
*/
2022-05-17 18:05:31 +02:00
BUG_ON ( ! se_fl_test ( appctx - > sedesc , SE_FL_ORPHAN ) ) ;
2022-05-12 15:15:53 +02:00
sess = session_new ( px , NULL , & appctx - > obj_type ) ;
if ( ! sess )
return - 1 ;
2022-05-27 08:33:53 +02:00
if ( ! sc_new_from_endp ( appctx - > sedesc , sess , input ) ) {
2022-05-12 15:15:53 +02:00
session_free ( sess ) ;
return - 1 ;
}
appctx - > sess = sess ;
return 0 ;
}
2022-05-12 15:18:48 +02:00
/* Release function to call when an error occurred during init stage of a
* frontend appctx . For a backend appctx , it just calls appctx_free ( )
*/
void appctx_free_on_early_error ( struct appctx * appctx )
{
2022-05-17 19:07:51 +02:00
/* If a frontend appctx is attached to a stream connector, release the stream
2022-05-12 15:18:48 +02:00
* instead of the appctx .
*/
2022-05-27 11:08:15 +02:00
if ( ! se_fl_test ( appctx - > sedesc , SE_FL_ORPHAN ) & & ! ( appctx_sc ( appctx ) - > flags & SC_FL_ISBACK ) ) {
2022-05-12 15:18:48 +02:00
stream_free ( appctx_strm ( appctx ) ) ;
return ;
}
appctx_free ( appctx ) ;
}
2022-05-02 14:57:03 +02:00
/* reserves a command context of at least <size> bytes in the <appctx>, for
* use by a CLI command or any regular applet . The pointer to this context is
* stored in ctx . svcctx and is returned . The caller doesn ' t need to release
* it as it ' s allocated from reserved space . If the size is larger than
* APPLET_MAX_SVCCTX a crash will occur ( hence that will never happen outside
* of development ) .
*
* Note that the command does * not * initialize the area , so that it can easily
* be used upon each entry in a function . It ' s left to the initialization code
* to do it if needed . The CLI will always zero the whole area before calling
* a keyword ' s - > parse ( ) function .
*/
void * applet_reserve_svcctx ( struct appctx * appctx , size_t size )
{
BUG_ON ( size > APPLET_MAX_SVCCTX ) ;
appctx - > svcctx = & appctx - > svc . storage ;
return appctx - > svcctx ;
}
2022-05-17 18:05:31 +02:00
/* call the applet's release() function if any, and marks the sedesc as shut.
2022-05-10 19:42:22 +02:00
* Needs to be called upon close ( ) .
*/
void appctx_shut ( struct appctx * appctx )
{
2022-05-17 18:05:31 +02:00
if ( se_fl_test ( appctx - > sedesc , SE_FL_SHR | SE_FL_SHW ) )
2022-05-10 19:42:22 +02:00
return ;
if ( appctx - > applet - > release )
appctx - > applet - > release ( appctx ) ;
2022-05-17 18:05:31 +02:00
se_fl_set ( appctx - > sedesc , SE_FL_SHRR | SE_FL_SHWN ) ;
2022-05-10 19:42:22 +02:00
}
2018-11-06 17:32:37 +01:00
/* Callback used to wake up an applet when a buffer is available. The applet
* < appctx > is woken up if an input buffer was requested for the associated
2022-05-17 19:07:51 +02:00
* stream connector . In this case the buffer is immediately allocated and the
2018-11-06 17:32:37 +01:00
* function returns 1. Otherwise it returns 0. Note that this automatically
* covers multiple wake - up attempts by ensuring that the same buffer will not
* be accounted for multiple times .
*/
int appctx_buf_available ( void * arg )
{
struct appctx * appctx = arg ;
2022-05-27 11:08:15 +02:00
struct stconn * sc = appctx_sc ( appctx ) ;
2018-11-06 17:32:37 +01:00
/* allocation requested ? */
2022-05-27 10:32:34 +02:00
if ( ! ( sc - > flags & SC_FL_NEED_BUFF ) )
2018-11-14 15:12:08 +01:00
return 0 ;
2022-05-27 10:32:34 +02:00
sc_have_buff ( sc ) ;
2018-11-14 15:12:08 +01:00
/* was already allocated another way ? if so, don't take this one */
2022-05-27 10:32:34 +02:00
if ( c_size ( sc_ic ( sc ) ) | | sc_ic ( sc ) - > pipe )
2018-11-06 17:32:37 +01:00
return 0 ;
/* allocation possible now ? */
2022-05-27 10:32:34 +02:00
if ( ! b_alloc ( & sc_ic ( sc ) - > buf ) ) {
sc_need_buff ( sc ) ;
2018-11-06 17:32:37 +01:00
return 0 ;
2018-11-14 15:12:08 +01:00
}
2018-11-06 17:32:37 +01:00
task_wakeup ( appctx - > t , TASK_WOKEN_RES ) ;
return 1 ;
}
/* Default applet handler */
2021-03-02 16:09:26 +01:00
struct task * task_run_applet ( struct task * t , void * context , unsigned int state )
2015-04-19 09:59:31 +02:00
{
2018-05-25 16:58:52 +02:00
struct appctx * app = context ;
2022-05-27 10:32:34 +02:00
struct stconn * sc ;
2019-04-25 19:12:26 +02:00
unsigned int rate ;
2021-04-27 17:08:10 +02:00
size_t count ;
2015-04-19 09:59:31 +02:00
2018-05-25 16:58:52 +02:00
if ( app - > state & APPLET_WANT_DIE ) {
__appctx_free ( app ) ;
return NULL ;
2017-06-26 16:36:53 +02:00
}
2018-05-25 16:58:52 +02:00
2022-05-17 18:05:31 +02:00
if ( se_fl_test ( app - > sedesc , SE_FL_ORPHAN ) ) {
2022-05-16 17:15:31 +02:00
/* Finalize init of orphan appctx. .init callback function must
* be defined and it must finalize appctx startup .
*/
BUG_ON ( ! app - > applet - > init ) ;
if ( appctx_init ( app ) = = - 1 ) {
appctx_free_on_early_error ( app ) ;
return NULL ;
}
2022-05-27 11:08:15 +02:00
BUG_ON ( ! app - > sess | | ! appctx_sc ( app ) | | ! appctx_strm ( app ) ) ;
2022-05-16 17:15:31 +02:00
}
2022-05-27 11:08:15 +02:00
sc = appctx_sc ( app ) ;
2022-05-16 17:15:31 +02:00
2018-05-25 16:58:52 +02:00
/* We always pretend the applet can't get and doesn't want to
* put , it ' s up to it to change this if needed . This ensures
* that one applet which ignores any event will not spin .
2015-09-25 17:56:16 +02:00
*/
2022-05-25 18:21:43 +02:00
applet_need_more_data ( app ) ;
2022-05-25 15:42:03 +02:00
applet_have_no_more_data ( app ) ;
2015-04-19 09:59:31 +02:00
2018-11-14 15:12:08 +01:00
/* Now we'll try to allocate the input buffer. We wake up the applet in
* all cases . So this is the applet ' s responsibility to check if this
* buffer was allocated or not . This leaves a chance for applets to do
* some other processing if needed . The applet doesn ' t have anything to
* do if it needs the buffer , it will be called again upon readiness .
*/
2022-05-27 10:32:34 +02:00
if ( ! sc_alloc_ibuf ( sc , & app - > buffer_wait ) )
2022-05-25 15:42:03 +02:00
applet_have_more_data ( app ) ;
2018-11-14 15:12:08 +01:00
2022-05-27 10:32:34 +02:00
count = co_data ( sc_oc ( sc ) ) ;
2018-05-25 16:58:52 +02:00
app - > applet - > fct ( app ) ;
2019-10-11 14:15:47 +02:00
2021-04-27 17:08:10 +02:00
/* now check if the applet has released some room and forgot to
* notify the other side about it .
*/
2022-05-27 10:32:34 +02:00
if ( count ! = co_data ( sc_oc ( sc ) ) ) {
sc_oc ( sc ) - > flags | = CF_WRITE_PARTIAL | CF_WROTE_DATA ;
sc_have_room ( sc_opposite ( sc ) ) ;
2021-04-27 17:08:10 +02:00
}
2019-10-11 14:15:47 +02:00
/* measure the call rate and check for anomalies when too high */
rate = update_freq_ctr ( & app - > call_rate , 1 ) ;
if ( rate > = 100000 & & app - > call_rate . prev_ctr & & // looped more than 100k times over last second
2022-05-27 10:32:34 +02:00
( ( b_size ( sc_ib ( sc ) ) & & sc - > flags & SC_FL_NEED_ROOM ) | | // asks for a buffer which is present
( b_size ( sc_ib ( sc ) ) & & ! b_data ( sc_ib ( sc ) ) & & sc - > flags & SC_FL_NEED_ROOM ) | | // asks for room in an empty buffer
( b_data ( sc_ob ( sc ) ) & & sc_is_send_allowed ( sc ) ) | | // asks for data already present
( ! b_data ( sc_ib ( sc ) ) & & b_data ( sc_ob ( sc ) ) & & // didn't return anything ...
( sc_oc ( sc ) - > flags & ( CF_WRITE_PARTIAL | CF_SHUTW_NOW ) ) = = CF_SHUTW_NOW ) ) ) { // ... and left data pending after a shut
2019-10-11 14:15:47 +02:00
stream_dump_and_crash ( & app - > obj_type , read_freq_ctr ( & app - > call_rate ) ) ;
}
2022-05-27 10:32:34 +02:00
sc - > app_ops - > wake ( sc ) ;
channel_release_buffer ( sc_ic ( sc ) , & app - > buffer_wait ) ;
2018-05-25 16:58:52 +02:00
return t ;
2015-04-19 09:59:31 +02:00
}