cfg/cfg_struct.h
a903fdab
 /*
  * Copyright (C) 2007 iptelorg GmbH
  *
1fff03a2
  * This file is part of Kamailio, a free SIP server.
a903fdab
  *
1fff03a2
  * Kamailio is free software; you can redistribute it and/or modify
a903fdab
  * 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
  *
1fff03a2
  * Kamailio is distributed in the hope that it will be useful,
a903fdab
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
a903fdab
  *
  */
 
 #ifndef _CFG_STRUCT_H
 #define _CFG_STRUCT_H
 
 #include "../str.h"
 #include "../atomic_ops.h"
 #include "../mem/shm_mem.h"
 #include "../locking.h"
 #include "../compiler_opt.h"
6a44d0bd
 #include "../bit_test.h"
a903fdab
 #include "cfg.h"
 
b2efa6a1
 /*! \brief Maximum number of variables within a configuration group. */
 #define CFG_MAX_VAR_NUM	256
 
86e99f5a
 /*! \brief indicates that the variable has been already shmized */
a903fdab
 #define cfg_var_shmized	1U
 
6a44d0bd
 /*! \brief Structure for storing additional values of a variable.
  * When the config is shmzied, these variables are combined in
  * an array.
  */
 typedef struct _cfg_add_var {
fd958ea0
 	struct _cfg_add_var	*next;
 	unsigned int	type;	/*!< type == 0 is also valid, it indicates that the group
 				must be created with the default values */
6a44d0bd
 	union {
eddc94d7
 		char	*ch;
6a44d0bd
 		str	s;
 		int	i;
 	} val;
 	unsigned int	group_id; /*!< Id of the group instance */
fd958ea0
 	int		name_len;	/*!< Name of the variable. The variable may not be known,
 					for example the additional group value is set in the script
 					before the cfg group is declared. Hence, the pointer cannot
 					be stored here. */
 	char		name[1];
6a44d0bd
 } cfg_add_var_t;
 
86e99f5a
 /*! \brief structure used for variable - pointer mapping */
a903fdab
 typedef struct _cfg_mapping {
86e99f5a
 	cfg_def_t	*def;		/*!< one item of the cfg structure definition */
 	int		name_len;	/*!< length of def->name */
a903fdab
 
 	/* additional information about the cfg variable */
6a44d0bd
 	int		pos;	/*!< position of the variable within the group starting from 0 */
86e99f5a
 	int		offset; /*!< offest within the memory block */
 	unsigned int	flag;	/*!< flag indicating the state of the variable */
a903fdab
 } cfg_mapping_t;
 
fd958ea0
 /*! \brief type of the group */
 enum { CFG_GROUP_UNKNOWN = 0, CFG_GROUP_DYNAMIC, CFG_GROUP_STATIC };
 
86e99f5a
 /*! \brief linked list of registered groups */
a903fdab
 typedef struct _cfg_group {
86e99f5a
 	int		num;		/*!< number of variables within the group */
 	cfg_mapping_t	*mapping;	/*!< describes the mapping betweeen
a903fdab
 					the cfg variable definition and the memory block */
86e99f5a
 	char		*vars;		/*!< pointer to the memory block where the values
a903fdab
 					are stored -- used only before the config is
 					shmized. */
6a44d0bd
 	cfg_add_var_t	*add_var;	/*!< Additional instances of the variables.
 					This linked list is used only before the config is
 					shmized. */
86e99f5a
 	int		size;		/*!< size of the memory block that has to be
a903fdab
 					allocated to store the values */
b2efa6a1
 	int		meta_offset;	/*!< offset of the group within the
 					shmized memory block for the meta_data */
 	int		var_offset;	/*!< offset of the group within the
 					shmized memory block for the variables */
86e99f5a
 	void		**handle;	/*!< per-process handle that can be used
a903fdab
 					by the modules to access the variables.
 					It is registered when the group is created,
 					and updated every time the block is replaced */
5d3449a0
 	void		*orig_handle;	/*!< Original value that the handle points to
 					when the config group is registered. This is needed
 					to temporary set the handle in the main process and
 					restore it later to its original value. */
a903fdab
 
86e99f5a
 	unsigned char	dynamic;	/*!< indicates whether the variables within the group
140137c9
 					are dynamically	allocated or not */
a903fdab
 	struct _cfg_group	*next;
fd958ea0
 	int		name_len;
a903fdab
 	char		name[1];
 } cfg_group_t;
 
b2efa6a1
 /*! \brief One instance of the cfg group variables which stores
  * the additional values. These values can overwrite the default values. */
 typedef struct _cfg_group_inst {
6a44d0bd
 	unsigned int	id;		/*!< identifier of the group instance */
b2efa6a1
 	unsigned int	set[CFG_MAX_VAR_NUM/(sizeof(int)*8)];
 					/*!< Bitmap indicating whether or not a value is explicitely set
 					within this instance. If the value is not set,
 					then the default value is used, and copied into this instance. */
 	unsigned char	vars[1];	/*!< block for the values */
 } cfg_group_inst_t;
 
09b8aec4
 /*! \brief Meta-data which is stored before each variable group
b2efa6a1
  * within the blob. This structure is used to handle the multivalue
  * instances of the variables, i.e. manages the array for the
  * additional values. */
 typedef struct _cfg_group_meta {
 	int			num;	/*!< Number of items in the array */
 	cfg_group_inst_t	*array;	/*!< Array of cfg groups with num number of items */
 } cfg_group_meta_t;
 
86e99f5a
 /*! \brief single memoy block that contains all the cfg values */
a903fdab
 typedef struct _cfg_block {
86e99f5a
 	atomic_t	refcnt;		/*!< reference counter,
a903fdab
 					the block is automatically deleted
 					when it reaches 0 */
86e99f5a
 	unsigned char	vars[1];	/*!< blob that contains the values */
a903fdab
 } cfg_block_t;
 
86e99f5a
 /*! \brief Linked list of per-child process callbacks.
a903fdab
  * Each child process has a local pointer, and executes the callbacks
  * when the pointer is not pointing to the end of the list.
  * Items from the begginning of the list are deleted when the starter
  * pointer is moved, and no more child process uses them.
  */
 typedef struct _cfg_child_cb {
86e99f5a
 	atomic_t		refcnt; /*!< number of child processes
a903fdab
 					referring to the element */
86e99f5a
 	atomic_t		cb_count;	/*!< This counter is used to track
ceef8440
 						 * how many times the callback needs
 						 * to be executed.
 						 * >0 the cb needs to be executed
 						 * <=0 the cb no longer needs to be executed
 						 */
86e99f5a
 	str			gname, name;	/*!< name of the variable that has changed */
67172188
 	cfg_on_set_child	cb;		/*!< callback function that has to be called */
 	void			**replaced;	/*!< set of strings and other memory segments
 						that must be freed together with this structure.
 						The content depends on the new config block.
 						This makes sure that the replaced strings are freed
 						after all the child processes release the old configuration. */
a903fdab
 
 	struct _cfg_child_cb	*next;
 } cfg_child_cb_t;
 
 extern cfg_group_t	*cfg_group;
 extern cfg_block_t	**cfg_global;
 extern cfg_block_t	*cfg_local;
b062f42f
 extern int		cfg_block_size;
a903fdab
 extern gen_lock_t	*cfg_global_lock;
 extern gen_lock_t	*cfg_writer_lock;
 extern int		cfg_shmized;
 extern cfg_child_cb_t	**cfg_child_cb_first;
 extern cfg_child_cb_t	**cfg_child_cb_last;
 extern cfg_child_cb_t	*cfg_child_cb;
b062f42f
 extern int		cfg_ginst_count;
a903fdab
 
4a9a969d
 /* magic value for cfg_child_cb for processes that do not want to
    execute per-child callbacks */
 #define CFG_NO_CHILD_CBS ((void*)(long)(-1))
 
a903fdab
 /* macros for easier variable access */
 #define CFG_VAR_TYPE(var)	CFG_VAR_MASK((var)->def->type)
 #define CFG_INPUT_TYPE(var)	CFG_INPUT_MASK((var)->def->type)
 
6a44d0bd
 /* get the meta-data of a group from the block */
 #define CFG_GROUP_META(block, group) \
 	((cfg_group_meta_t *)((block)->vars + (group)->meta_offset))
 
 /* get the data block of a group from the block */
 #define CFG_GROUP_DATA(block, group) \
 	((unsigned char *)((block)->vars + (group)->var_offset))
 
 /* Test whether a variable is explicitely set in the group instance,
  * or it uses the default value */
 #define CFG_VAR_TEST(group_inst, var) \
 	bit_test((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
 
 /* Test whether a variable is explicitely set in the group instance,
  * or it uses the default value, and set the flag. */
 #define CFG_VAR_TEST_AND_SET(group_inst, var) \
 	bit_test_and_set((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
 
7d7264e2
 /* Test whether a variable is explicitely set in the group instance,
  * or it uses the default value, and reset the flag. */
 #define CFG_VAR_TEST_AND_RESET(group_inst, var) \
 	bit_test_and_reset((var)->pos % (sizeof(int)*8), (group_inst)->set + (var)->pos/(sizeof(int)*8))
 
b062f42f
 /* Return the group instance pointer from a handle,
  * or NULL if the handle points to the default configuration block */
 #define CFG_HANDLE_TO_GINST(h) \
 	( (((unsigned char*)(h) < cfg_local->vars) \
 		|| ((unsigned char*)(h) > cfg_local->vars + cfg_block_size) \
 	) ? \
 		(cfg_group_inst_t*)((char*)(h) - (unsigned long)&((cfg_group_inst_t *)0)->vars) \
 		: NULL )
 
a903fdab
 /* initiate the cfg framework */
50ca02e5
 int sr_cfg_init(void);
a903fdab
 
 /* destroy the memory allocated for the cfg framework */
 void cfg_destroy(void);
 
5322385b
 /* Register num number of child processes that will
  * keep updating their local configuration.
  * This function needs to be called from mod_init
  * before any child process is forked.
  */
 void cfg_register_child(int num);
 
 /* per-child process init function.
  * It needs to be called from the forked process.
  * cfg_register_child() must be called before this function!
  */
a903fdab
 int cfg_child_init(void);
 
5322385b
 /* Child process init function that can be called
  * without cfg_register_child().
  * Note that the child process may miss some configuration changes.
  */
 int cfg_late_child_init(void);
 
4a9a969d
 /* per-child init function for non-cb executing processes.
  * Mark this process as not wanting to execute any per-child config
  * callback (it will have only limited config functionality, but is useful
  * when a process needs only to watch some non-callback cfg. values,
  * e.g. the main attendant process, debug and memlog).
  * It needs to be called from the forked process.
  * cfg_register_child must _not_ be called.
  */
 int cfg_child_no_cb_init(void);
 
f20a809d
 /* per-child process destroy function
  * Should be called only when the child process exits,
  * but SER continues running.
  *
  * WARNING: this function call must be the very last action
  * before the child process exits, because the local config
  * is not available afterwards.
  */
 void cfg_child_destroy(void);
 
a903fdab
 /* creates a new cfg group, and adds it to the linked list */
140137c9
 cfg_group_t *cfg_new_group(char *name, int name_len,
 		int num, cfg_mapping_t *mapping,
a903fdab
 		char *vars, int size, void **handle);
 
fd958ea0
 /* Set the values of an existing cfg group. */
 void cfg_set_group(cfg_group_t *group,
 		int num, cfg_mapping_t *mapping,
 		char *vars, int size, void **handle);
 
a903fdab
 /* copy the variables to shm mem */
 int cfg_shmize(void);
 
67172188
 /* free the memory of a child cb structure */
 static inline void cfg_child_cb_free_item(cfg_child_cb_t *cb)
a903fdab
 {
 	int	i;
 
 	/* free the changed variables */
67172188
 	if (cb->replaced) {
 		for (i=0; cb->replaced[i]; i++)
 			shm_free(cb->replaced[i]);
 		shm_free(cb->replaced);
a903fdab
 	}
67172188
 	shm_free(cb);
a903fdab
 }
 
67172188
 #define cfg_block_free(block) \
 	shm_free(block)
 
b062f42f
 /* Move the group handle to the specified group instance pointed by dst_ginst.
  * src_ginst shall point to the active group instance.
  * Both parameters can be NULL meaning that the src/dst config is the default, 
  * not an additional group instance.
  * The function executes all the per-child process callbacks which are different
  * in the two instaces.
  */
 void cfg_move_handle(cfg_group_t *group, cfg_group_inst_t *src_ginst, cfg_group_inst_t *dst_ginst);
 
 
a903fdab
 /* lock and unlock the global cfg block -- used only at the
  * very last step when the block is replaced */
 #define CFG_LOCK()	lock_get(cfg_global_lock);
 #define CFG_UNLOCK()	lock_release(cfg_global_lock);
 
 /* lock and unlock used by the cfg drivers to make sure that
  * only one driver process is considering replacing the global
  * cfg block */
 #define CFG_WRITER_LOCK()	lock_get(cfg_writer_lock);
 #define CFG_WRITER_UNLOCK()	lock_release(cfg_writer_lock);
 
 /* increase and decrease the reference counter of a block */
 #define CFG_REF(block) \
 	atomic_inc(&(block)->refcnt)
 
 #define CFG_UNREF(block) \
 	do { \
 		if (atomic_dec_and_test(&(block)->refcnt)) \
 			cfg_block_free(block); \
 	} while(0)
 
 /* updates all the module handles and calls the
  * per-child process callbacks -- not intended to be used
  * directly, use cfg_update() instead!
5c323052
  * params:
  *   no_cbs - if 1, do not call per child callbacks
a903fdab
  */
5c323052
 static inline void cfg_update_local(int no_cbs)
a903fdab
 {
 	cfg_group_t	*group;
 	cfg_child_cb_t	*last_cb;
 	cfg_child_cb_t	*prev_cb;
 
 	if (cfg_local) CFG_UNREF(cfg_local);
 	CFG_LOCK();
 	CFG_REF(*cfg_global);
 	cfg_local = *cfg_global;
 	/* the value of the last callback must be read within the lock */
 	last_cb = *cfg_child_cb_last;
 
 	/* I unlock now, because the child process can update its own private
 	config without the lock held. In the worst case, the process will get the
 	lock once more to set cfg_child_cb_first, but only one of the child
 	processes will do so, and only if a value, that has per-child process
 	callback defined, was changed. */
 	CFG_UNLOCK();
 
 	/* update the handles */
 	for (	group = cfg_group;
 		group;
 		group = group->next
 	)
6a44d0bd
 		*(group->handle) = CFG_GROUP_DATA(cfg_local, group);
a903fdab
 
5c323052
 	if (unlikely(cfg_child_cb==CFG_NO_CHILD_CBS || no_cbs))
4a9a969d
 		return;
a903fdab
 	/* call the per-process callbacks */
 	while (cfg_child_cb != last_cb) {
 		prev_cb = cfg_child_cb;
 		cfg_child_cb = cfg_child_cb->next;
 		atomic_inc(&cfg_child_cb->refcnt);
 		if (atomic_dec_and_test(&prev_cb->refcnt)) {
 			/* No more pocess refers to this callback.
 			Did this process block the deletion,
 			or is there any other process that has not
 			reached	prev_cb yet? */
 			CFG_LOCK();
 			if (*cfg_child_cb_first == prev_cb) {
 				/* yes, this process was blocking the deletion */
 				*cfg_child_cb_first = cfg_child_cb;
 				CFG_UNLOCK();
67172188
 				cfg_child_cb_free_item(prev_cb);
a903fdab
 			} else {
 				CFG_UNLOCK();
 			}
 		}
67172188
 		if (cfg_child_cb->cb
 			&& (atomic_add(&cfg_child_cb->cb_count, -1) >= 0) /* the new value is returned
 									by atomic_add() */
 		)
ceef8440
 			/* execute the callback */
 			cfg_child_cb->cb(&cfg_child_cb->gname, &cfg_child_cb->name);
 		/* else the callback no longer needs to be executed */
a903fdab
 	}
 }
 
b062f42f
 /* Reset all the group handles to the default, local configuration */
 static inline void cfg_reset_handles(void)
 {
 	cfg_group_t	*group;
 
 	if (!cfg_local)
 		return;
 
 	for (	group = cfg_group;
 		group && cfg_ginst_count; /* cfg_ginst_count is decreased every time
 					a group handle is reset. When it reaches 0,
 					needless to continue the loop */
 		group = group->next
 	) {
 		if (((unsigned char*)*(group->handle) < cfg_local->vars)
 			|| ((unsigned char*)*(group->handle) > cfg_local->vars + cfg_block_size)
 		)
 			cfg_move_handle(group,
 					CFG_HANDLE_TO_GINST(*(group->handle)),
 					NULL);
 	}
 }
 
a903fdab
 /* sets the local cfg block to the active block
  * 
  * If your module forks a new process that implements
  * an infinite loop, put cfg_update() to the beginning of
  * the cycle to make sure, that subsequent function calls see the
  * up-to-date config set.
  */
 #define cfg_update() \
 	do { \
b062f42f
 		if (unlikely(cfg_ginst_count)) \
 			cfg_reset_handles(); \
a903fdab
 		if (unlikely(cfg_local != *cfg_global)) \
5c323052
 			cfg_update_local(0); \
 	} while(0)
 
 /* like cfg_update(), but does not execute callbacks
  * (it should be used sparingly only in special cases, since it
  *  breaks an important cfg framework feature)
  */
 #define cfg_update_no_cbs() \
 	do { \
 		if (unlikely(cfg_local != *cfg_global)) \
 			cfg_update_local(1); \
a903fdab
 	} while(0)
c092bd34
 
58829230
 /* Reset all the group handles in the child process,
  * i.e. move them back to the default local configuration.
  */
 #define cfg_reset_all() \
 	do { \
 		if (unlikely(cfg_ginst_count)) \
 			cfg_reset_handles(); \
 	} while(0)
 
 
c092bd34
 /* searches a group by name */
 cfg_group_t *cfg_lookup_group(char *name, int len);
a903fdab
 	
 /* searches a variable definition by group and variable name */
 int cfg_lookup_var(str *gname, str *vname,
 			cfg_group_t **group, cfg_mapping_t **var);
 
92f85d59
 /* searches a variable definition within a group by its name */
 cfg_mapping_t *cfg_lookup_var2(cfg_group_t *group, char *name, int len);
 
6a44d0bd
 /* clones the global config block
  * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
  */
a903fdab
 cfg_block_t *cfg_clone_global(void);
 
6a44d0bd
 /* Clone an array of configuration group instances. */
 cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group);
 
28d46c65
 /* Extend the array of configuration group instances with one more instance.
  * Only the ID of the new group is set, nothing else. */
 cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group,
 				unsigned int group_id,
 				cfg_group_inst_t **new_group);
 
8e1d174c
 /* Remove an instance from a group array.
  * inst must point to an instance within meta->array.
  * *_new_array is set to the newly allocated array. */
 int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group,
 				cfg_group_inst_t *inst,
 				cfg_group_inst_t **_new_array);
 
a903fdab
 /* clones a string to shared memory */
c55d3c7f
 int cfg_clone_str(str *src, str *dst);
a903fdab
 
6a44d0bd
 /* Find the group instance within the meta-data based on the group_id */
 cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id);
 
a0b44e92
 /* append new callbacks to the end of the child callback list
  *
  * WARNING: the function is unsafe, either hold CFG_LOCK(),
  * or call the function before forking
  */
 void cfg_install_child_cb(cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last);
 
a903fdab
 /* installs a new global config
  *
  * replaced is an array of strings that must be freed together
  * with the previous global config.
  * cb_first and cb_last define a linked list of per-child process
  * callbacks. This list is added to the global linked list.
  */
27580846
 void cfg_install_global(cfg_block_t *block, void **replaced,
a903fdab
 			cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last);
 
 /* creates a structure for a per-child process callback */
ceef8440
 cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
 			cfg_on_set_child cb,
 			unsigned int type);
a903fdab
 
 /* free the memory allocated for a child cb list */
67172188
 void cfg_child_cb_free_list(cfg_child_cb_t *child_cb_first);
a903fdab
 
eddc94d7
 /* Allocate memory for a new additional variable
  * and link it to a configuration group.
  * type==0 results in creating a new group instance with the default values.
  * The group is created with CFG_GROUP_UNKNOWN type if it does not exist.
  * Note: this function is usable only before the configuration is shmized.
  */
 int new_add_var(str *group_name, unsigned int group_id, str *var_name,
 				void *val, unsigned int type);
 
b062f42f
 /* Move the group handle to the specified group instance. */
 int cfg_select(cfg_group_t *group, unsigned int id);
 
 /* Reset the group handle to the default, local configuration */
 int cfg_reset(cfg_group_t *group);
 
62ed44d1
 /* Move the group handle to the first group instance.
  * This function together with cfg_select_next() can be used
  * to iterate though the list of instances.
  *
  * Return value:
  *	-1: no group instance found
  *	 0: first group instance is successfully selected.
  */
 int cfg_select_first(cfg_group_t *group);
 
 /* Move the group handle to the next group instance.
  * This function together with cfg_select_first() can be used
  * to iterate though the list of instances.
  *
  * Return value:
  *	-1: no more group instance found. Note, that the active group
  *		instance is not changed in this case.
  *	 0: the next group instance is successfully selected.
  */
 int cfg_select_next(cfg_group_t *group);
 
5d3449a0
 /* Temporary set the local configuration in the main process before forking.
  * This makes the group instances usable in the main process after
  * the configuration is shmized, but before the children are forked.
  */
 void cfg_main_set_local(void);
 
 /* Reset the local configuration of the main process back to its original state
  * to make sure that the forked processes are not affected.
  */
 void cfg_main_reset_local(void);
 
a903fdab
 #endif /* _CFG_STRUCT_H */