/* * $Id: gflags.c 1808 2007-03-10 17:36:19Z bogdan_iancu $ * * Copyright (C) 2004 FhG * Copyright (C) 2005-2006 Voice Sistem S.R.L. * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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 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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * -------- * 2004-09-09 initial module created (jiri) * 2006-05-31 flag range checked ; proper cleanup at module destroy ; * got rid of memory allocation in fixup function ; * optimized fixup function -> compute directly the bitmap ; * allowed functions from BRANCH_ROUTE (bogdan) * * TODO: * ----- * - named flags (takes a protected name list) * * * gflags module: global flags; it keeps a bitmap of flags * in shared memory and may be used to change behaviour * of server based on value of the flags. E.g., * if (is_gflag("1")) { t_relay_to_udp("10.0.0.1","5060"); } * else { t_relay_to_udp("10.0.0.2","5060"); } * The benefit of this module is the value of the switch flags * can be manipulated by external applications such as web interface * or command line tools. * * */ /* flag buffer size for FIFO protocool */ #define MAX_FLAG_LEN 12 /* FIFO action protocol names */ #define FIFO_SET_GFLAG "set_gflag" #define FIFO_IS_GFLAG "is_gflag" #define FIFO_RESET_GFLAG "reset_gflag" #define FIFO_GET_GFLAGS "get_gflags" #include #include "../../sr_module.h" #include "../../ut.h" #include "../../mem/mem.h" #include "../../mem/shm_mem.h" #include "../../mi/mi.h" MODULE_VERSION static int set_gflag(struct sip_msg*, char *, char *); static int reset_gflag(struct sip_msg*, char *, char *); static int is_gflag(struct sip_msg*, char *, char *); static struct mi_root* mi_set_gflag(struct mi_root* cmd, void* param ); static struct mi_root* mi_reset_gflag(struct mi_root* cmd, void* param ); static struct mi_root* mi_is_gflag(struct mi_root* cmd, void* param ); static struct mi_root* mi_get_gflags(struct mi_root* cmd, void* param ); static int fixup_str2int( void** param, int param_no); static int mod_init(void); static void mod_destroy(void); static int initial=0; static unsigned int *gflags=0; static cmd_export_t cmds[]={ {"set_gflag", set_gflag, 1, fixup_str2int, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE}, {"reset_gflag", reset_gflag, 1, fixup_str2int, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE}, {"is_gflag", is_gflag, 1, fixup_str2int, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE|BRANCH_ROUTE}, {0, 0, 0, 0, 0} }; static param_export_t params[]={ {"initial", INT_PARAM, &initial}, {0,0,0} }; static mi_export_t mi_cmds[] = { { FIFO_SET_GFLAG, mi_set_gflag, 0, 0, 0 }, { FIFO_RESET_GFLAG, mi_reset_gflag, 0, 0, 0 }, { FIFO_IS_GFLAG, mi_is_gflag, 0, 0, 0 }, { FIFO_GET_GFLAGS, mi_get_gflags, MI_NO_INPUT_FLAG, 0, 0 }, { 0, 0, 0, 0, 0} }; struct module_exports exports = { "gflags", DEFAULT_DLFLAGS, /* dlopen flags */ cmds, /* exported functions */ params, /* exported parameters */ 0, /* exported statistics */ mi_cmds, /* exported MI functions */ 0, /* exported pseudo-variables */ mod_init, /* module initialization function */ 0, /* response function*/ mod_destroy, /* destroy function */ 0 /* per-child init function */ }; /**************************** fixup functions ******************************/ static int fixup_str2int( void** param, int param_no) { unsigned int myint; str param_str; /* we only fix the parameter #1 */ if (param_no!=1) return 0; param_str.s=(char*) *param; param_str.len=strlen(param_str.s); if (str2int(¶m_str, &myint )<0) { LOG(L_ERR, "ERROR:gflags:fixup_str2int: bad number <%s>\n", (char *)(*param)); return E_CFG; } if ( myint >= 8*sizeof(*gflags) ) { LOG(L_ERR, "ERROR:gflags:fixup_str2int: flag <%d> out of " "range [0..%lu]\n", myint, (unsigned long)8*sizeof(*gflags) ); return E_CFG; } /* convert from flag index to flag bitmap */ myint = 1 << myint; /* success -- change to int */ pkg_free(*param); *param=(void *)(long)myint; return 0; } /**************************** module functions ******************************/ static int set_gflag(struct sip_msg *bar, char *flag, char *foo) { (*gflags) |= (unsigned int)(long)flag; return 1; } static int reset_gflag(struct sip_msg *bar, char *flag, char *foo) { (*gflags) &= ~ ((unsigned int)(long)flag); return 1; } static int is_gflag(struct sip_msg *bar, char *flag, char *foo) { return ( (*gflags) & ((unsigned int)(long)flag)) ? 1 : -1; } /************************* MI functions *******************************/ static struct mi_root* mi_set_gflag(struct mi_root* cmd_tree, void* param ) { unsigned int flag; struct mi_node* node; node = cmd_tree->node.kids; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); if( strno2int( &node->value, &flag) <0) goto error; if (!flag) { LOG(L_ERR, "ERROR:gflags:mi_set_gflag: incorrect flag\n"); goto error; } (*gflags) |= flag; return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); } static struct mi_root* mi_reset_gflag(struct mi_root* cmd_tree, void* param ) { unsigned int flag; struct mi_node* node = NULL; node = cmd_tree->node.kids; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); if( strno2int( &node->value, &flag) <0) goto error; if (!flag) { LOG(L_ERR, "ERROR:gflags:mi_set_gflag: incorrect flag\n"); goto error; } (*gflags) &= ~ flag; return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); error: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); } static struct mi_root* mi_is_gflag(struct mi_root* cmd_tree, void* param ) { unsigned int flag; struct mi_root* rpl_tree = NULL; struct mi_node* node = NULL; node = cmd_tree->node.kids; if(node == NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); if( strno2int( &node->value, &flag) <0) goto error_param; if (!flag) { LOG(L_ERR, "ERROR:gflags:mi_set_gflag: incorrect flag\n"); goto error_param; } rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if(rpl_tree ==0) return 0; if((*gflags) & flag) node = add_mi_node_child( &rpl_tree->node, 0, 0, 0, "TRUE", 4); else node = add_mi_node_child( &rpl_tree->node, 0, 0, 0, "FALSE", 5); if(node == NULL) { LOG(L_ERR, "gflags:mi_set_gflag:ERROR while adding node\n"); free_mi_tree(rpl_tree); return 0; } return rpl_tree; error_param: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); } static struct mi_root* mi_get_gflags(struct mi_root* cmd_tree, void* param ) { struct mi_root* rpl_tree= NULL; struct mi_node* node= NULL; rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN ); if(rpl_tree == NULL) return 0; node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "0x%X",(*gflags)); if(node == NULL) goto error; node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%u",(*gflags)); if(node == NULL) goto error; return rpl_tree; error: free_mi_tree(rpl_tree); return 0; } static int mod_init(void) { gflags=(unsigned int *) shm_malloc(sizeof(unsigned int)); if (!gflags) { LOG(L_ERR, "Error: gflags/mod_init: no shmem\n"); return -1; } *gflags=initial; return 0; } static void mod_destroy(void) { if (gflags) shm_free(gflags); }