diff options
Diffstat (limited to 'include/haproxy/event_hdl-t.h')
-rw-r--r-- | include/haproxy/event_hdl-t.h | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/include/haproxy/event_hdl-t.h b/include/haproxy/event_hdl-t.h new file mode 100644 index 0000000..d499852 --- /dev/null +++ b/include/haproxy/event_hdl-t.h @@ -0,0 +1,295 @@ +/* + * include/haproxy/event_hdl-t.h + * event handlers management definitions + * + * Copyright 2022 HAProxy Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _HAPROXY_EVENT_HDL_T_H +# define _HAPROXY_EVENT_HDL_T_H + +#include <stdint.h> +#include <sys/time.h> + +#include <haproxy/api-t.h> + +/* event data struct are defined as followed */ +struct event_hdl_cb_data_template { + struct { + /* safe data can be safely used from both + * sync and async handlers + * data consistency is guaranteed + */ + } safe; + struct { + /* unsafe data may only be used from sync handlers: + * in async mode, data consistency cannot be guaranteed + * and unsafe data may already be stale, thus using + * it is highly discouraged because it + * could lead to undefined behavior (UAF, null dereference...) + */ + } unsafe; +}; + +/* event_hdl tunables */ +struct event_hdl_tune { + unsigned int max_events_at_once; +}; + +/* FIXME: adjust if needed! Should be large enough + * to support every struct event_hdl_cb_data_x types + * BUG_ON check in publish/async_mode and static assert + * in EVENT_HDL_CB_DATA will ensure this + */ +#define EVENT_HDL_ASYNC_EVENT_DATA (768) +/* used internally to store a single copy of event data when dealing with + * async handlers. + * The same copy can be provided to multiple handlers to prevent memory waste: + * refcount is used to keep track of references so that + * data can be freed when not used anymore + */ +typedef void (*event_hdl_data_free)(const void *data); +struct event_hdl_async_event_data +{ + /* internal storage */ + char data[EVENT_HDL_ASYNC_EVENT_DATA]; + /* user-provided free function if event data relies on + * dynamic members that require specific cleanup + */ + event_hdl_data_free mfree; + uint32_t refcount; +}; + +/* type for storing event subscription type */ +struct event_hdl_sub_type +{ + /* up to 256 families, non cumulative, adjust if needed */ + uint8_t family; + /* up to 16 sub types using bitmasks, adjust if needed */ + uint16_t subtype; +}; + +struct event_hdl_sub_list_head { + struct mt_list head; + struct mt_list known; /* api uses this to track known subscription lists */ +}; + +/* event_hdl_sub_list is an alias (please use this for portability) */ +typedef struct event_hdl_sub_list_head event_hdl_sub_list; + +struct event_hdl_async_equeue_head { + struct mt_list head; + uint32_t size; /* near realtime size, not fully synced with head (to be used as a hint) */ +}; + +/* event_hdl_async_equeue is an alias to mt_list (please use this for portability) */ +typedef struct event_hdl_async_equeue_head event_hdl_async_equeue; + +/* subscription mgmt from event */ +struct event_hdl_sub_mgmt +{ + /* manage subscriptions from event + * this must not be used directly because locking might be required + */ + struct event_hdl_sub *this; + /* safe functions than can be used from event context (sync and async mode) */ + struct event_hdl_sub_type (*getsub)(const struct event_hdl_sub_mgmt *); + int (*resub)(const struct event_hdl_sub_mgmt *, struct event_hdl_sub_type); + void (*unsub)(const struct event_hdl_sub_mgmt *); +}; + +/* single event structure pushed into async event queue + * used by tasks async handlers + */ +struct event_hdl_async_event +{ + struct mt_list mt_list; + struct event_hdl_sub_type type; + /* data wrapper - should not be used directly */ + struct event_hdl_async_event_data *_data; + /* for easy data access, + * points to _data->data if data is available + */ + void *data; + void *private; + struct timeval when; + struct event_hdl_sub_mgmt sub_mgmt; +}; + +/* internal structure provided to function event_hdl_publish() + * It contains ptr to data relevant to the event + */ +struct event_hdl_cb_data { + /* internal use: ptr to struct event_hdl_cb_data_type */ + void *_ptr; + /* internal use: holds actual data size*/ + size_t _size; + /* user specified freeing function for event_hdl_cb_data_type + * struct members + */ + event_hdl_data_free _mfree; +}; + +/* struct provided to event_hdl_cb_* handlers + * contains data related to the event + * that triggered the handler + */ +struct event_hdl_cb +{ + /* event type */ + struct event_hdl_sub_type e_type; + /* event data */ + void *e_data; + /* manage the subscription responsible for handing the event to us */ + const struct event_hdl_sub_mgmt *sub_mgmt; + + /* may be used by sync event handler to ensure + * it runs in sync mode, and thus is eligible to access unsafe data. + * This could save the day when users are copy-pasting function + * logic from a sync handler to an async handler without + * taking appropriate precautions and unsafe accesses are performed. + * (See EVENT_HDL_ASSERT_SYNC macro API helper) + */ + uint8_t _sync; +}; + +/* prototype for event_hdl_cb_sync function pointer */ +typedef void (*event_hdl_cb_sync)(const struct event_hdl_cb *cb, void *private); +/* prototype for event_hdl_cb async function pointer */ +typedef void (*event_hdl_cb_async)(const struct event_hdl_cb *cb, void *private); +/* prototype for event_hdl_private_free function pointer */ +typedef void (*event_hdl_private_free)(void *private); + +/* tasklet forward declaration */ +struct tasklet; +/* enum for sync mode */ +enum event_hdl_async_mode +{ + EVENT_HDL_ASYNC_MODE_NORMAL = 1, + EVENT_HDL_ASYNC_MODE_ADVANCED = 2 +}; + +/* event hdl, used when subscribing (and then associated with a subscription) */ +struct event_hdl { + /* optional unique id (hash) for lookup */ + uint64_t id; + /* handler debug: origin (initial event subscription calling place) */ + const char *dorigin; + /* handler requires async mode: + * EVENT_HDL_ASYNC_MODE_NORMAL = normal + * EVENT_HDL_ASYNC_MODE_ADVANCED = advanced, single task wakeup + */ + uint8_t async; + + union { + event_hdl_cb_sync sync_ptr; /* if !async */ + event_hdl_cb_async async_ptr; /* only used if async==1 (normal) */ + }; + + /* ptr to async task responsible for consuming events */ + struct tasklet *async_task; + /* used by async tasks to consume pending events */ + event_hdl_async_equeue *async_equeue; + /* function ptr automatically called by: + * async task when hdl is unregistered and private is no longer referenced + * sync context when unregistering is performed + */ + event_hdl_private_free private_free; + /* it is not safe to assume that private will not + * be used anymore once hdl is unregistered: + * with async handlers, private could still be referenced + * in pending events to be consumed later by the task (by design). + * If freeing private is needed, you must provide async_private_free + * function pointer when registering. + * It will be called when private is no longer used + * after unregistering hdl to perform private cleanup. + * (please use this even in sync mode so that subscription + * can easily be turned into async mode later without breaking stuff) + */ + void *private; +}; + +/* flags for event_hdl_sub struct (32 bits) */ +#define EHDL_SUB_F_PAUSED 0x0001 /* subscription will temporarily ignore events */ + +/* list elem: subscription (handler subscribed to specific events) + */ +struct event_hdl_sub { + struct mt_list mt_list; + /* event type subscription */ + struct event_hdl_sub_type sub; + uint32_t flags; + /* event handler */ + struct event_hdl hdl; + /* used to guarantee that END event will be delivered + * (memory is allocated when registering, no memory failure can occur at runtime) + */ + struct event_hdl_async_event *async_end; + /* > 0 : subscription is referenced, don't free yet + * use atomic OPS to write and read from it + */ + uint32_t refcount; + /* TODO: atomic_call_counter for stats?! */ +}; + +#define ESUB_INDEX(n) (1 << (n - 1)) + +#define EVENT_HDL_SUB_TYPE(_family, _type) ((struct event_hdl_sub_type){ .family = _family, .subtype = ESUB_INDEX(_type) }) +#define EVENT_HDL_SUB_FAMILY(_family) ((struct event_hdl_sub_type){ .family = _family, .subtype = ~0 }) + +#define EVENT_HDL_SUB_NONE ((struct event_hdl_sub_type){ .family = 0, .subtype = 0}) +/* for async tasks: subscription is ending */ +#define EVENT_HDL_SUB_END ((struct event_hdl_sub_type){ .family = 0, .subtype = 1}) + +/* --------------------------------------- */ + +/* user defined event types are listed here + * please reflect any change in these macros in the subtype map + * defined below that is used to perform string to event type and + * event type to string conversions + */ + +/* TODO */ + +/* SERVER FAMILY, provides event_hdl_cb_data_server struct + * (will be defined in haproxy/server-t.h) + */ +#define EVENT_HDL_SUB_SERVER EVENT_HDL_SUB_FAMILY(1) +#define EVENT_HDL_SUB_SERVER_ADD EVENT_HDL_SUB_TYPE(1,1) +#define EVENT_HDL_SUB_SERVER_DEL EVENT_HDL_SUB_TYPE(1,2) +#define EVENT_HDL_SUB_SERVER_UP EVENT_HDL_SUB_TYPE(1,3) +#define EVENT_HDL_SUB_SERVER_DOWN EVENT_HDL_SUB_TYPE(1,4) +/* server state change */ +#define EVENT_HDL_SUB_SERVER_STATE EVENT_HDL_SUB_TYPE(1,5) +/* server admin change */ +#define EVENT_HDL_SUB_SERVER_ADMIN EVENT_HDL_SUB_TYPE(1,6) +/* server check-related (agent or health) event */ +#define EVENT_HDL_SUB_SERVER_CHECK EVENT_HDL_SUB_TYPE(1,7) +/* server inet addr (addr:svc_port tuple) change event */ +#define EVENT_HDL_SUB_SERVER_INETADDR EVENT_HDL_SUB_TYPE(1,8) + +/* --------------------------------------- */ + +/* Please reflect changes above in event_hdl_sub_type_map defined + * in event_hdl.c file + */ +struct event_hdl_sub_type_map { + const char *name; + struct event_hdl_sub_type type; +}; + +#endif /* _HAPROXY_EVENT_HDL_T_H */ |