123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- /*$Id$
- *
- * 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.
- *
- *
- * Copyright (C) 2004 FhG FOKUS
- *
- * This file is part of ser, a free SIP server.
- *
- * ser 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
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /*
- * History:
- * --------
- * 2004-09-09 initial module created (jiri)
- * 2006-12-04 added xmlrpc command global.reload for reloading of global_attrs
- * db table (vlada)
- *
- * TODO
- * - flag range checking
- * - named flags (takes a protected name list)
- */
- #include <stdio.h>
- #include "../../sr_module.h"
- #include "../../error.h"
- #include "../../ut.h"
- #include "../../lib/srdb2/db.h"
- #include "../../mem/mem.h"
- #include "../../mem/shm_mem.h"
- #include "../../usr_avp.h"
- #include "../../rpc.h"
- #include "../../config.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 int flush_gflags(struct sip_msg*, char*, char*);
- static int mod_init(void);
- static void mod_destroy(void);
- static int child_init(int rank);
- static int reload_global_attributes(void);
- static int initial = 0;
- static unsigned int *gflags;
- static char* db_url = DEFAULT_DB_URL;
- static int load_global_attrs = 0;
- static char* attr_table = "uid_global_attrs";
- static char* attr_name = "name";
- static char* attr_type = "type";
- static char* attr_value = "value";
- static char* attr_flags = "flags";
- static db_ctx_t* db = NULL;
- static db_cmd_t* load_attrs_cmd = NULL, *save_gflags_cmd = NULL;
- static avp_list_t** active_global_avps;
- static avp_list_t *avps_1;
- static avp_list_t *avps_2;
- static rpc_export_t rpc_methods[];
- static cmd_export_t cmds[]={
- {"set_ugflag", set_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
- {"reset_ugflag", reset_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
- {"is_ugflag", is_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
- {"flush_ugflags", flush_gflags, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
- {0, 0, 0, 0, 0}
- };
- static param_export_t params[]={
- {"initial", PARAM_INT, &initial },
- {"db_url", PARAM_STRING, &db_url },
- {"load_global_attrs", PARAM_INT, &load_global_attrs},
- {"global_attrs_table", PARAM_STRING, &attr_table },
- {"global_attrs_name", PARAM_STRING, &attr_name },
- {"global_attrs_type", PARAM_STRING, &attr_type },
- {"global_attrs_value", PARAM_STRING, &attr_value },
- {"global_attrs_flags", PARAM_STRING, &attr_flags },
- {0, 0, 0}
- };
- struct module_exports exports = {
- "uid_gflags",
- cmds,
- rpc_methods, /* RPC methods */
- params,
- mod_init, /* module initialization function */
- 0, /* response function*/
- mod_destroy, /* destroy function */
- 0, /* oncancel function */
- child_init /* per-child init function */
- };
- static int init_db(void)
- {
- db_fld_t attr_res[] = {
- {.name = attr_name, DB_STR},
- {.name = attr_type, DB_INT},
- {.name = attr_value, DB_STR},
- {.name = attr_flags, DB_BITMAP},
- {.name = NULL}
- };
- db_fld_t values[] = {
- {.name = attr_name, DB_CSTR},
- {.name = attr_type, DB_INT},
- {.name = attr_value, DB_STR},
- {.name = attr_flags, DB_BITMAP},
- {.name = NULL}
- };
- db = db_ctx("gflags");
- if (db == NULL) {
- ERR("Error while initializing database layer\n");
- return -1;
- }
- if (db_add_db(db, db_url) < 0) return -1;
- if (db_connect(db) < 0) return -1;
-
- /* SELECT name, type, value, flags FROM global_attrs */
- load_attrs_cmd = db_cmd(DB_GET, db, attr_table, attr_res, NULL, NULL);
- if (load_attrs_cmd == NULL) {
- ERR("Error while building db query to load global attributes\n");
- return -1;
- }
- save_gflags_cmd = db_cmd(DB_PUT, db, attr_table, NULL, NULL, values);
- if (save_gflags_cmd == NULL) {
- ERR("Error while building db query to save global flags\n");
- return -1;
- }
- return 0;
- }
- static int set_gflag(struct sip_msg *bar, char *flag_par, char *foo)
- {
- unsigned long int flag;
- if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
- LOG(L_ERR, "gflags:set_gflag: Invalid parameter\n");
- return -1;
- }
-
- flag=((fparam_t*)flag_par)->v.i;
- (*gflags) |= 1 << flag;
- return 1;
- }
- static int reset_gflag(struct sip_msg *bar, char *flag_par, char *foo)
- {
- unsigned long int flag;
- if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
- LOG(L_ERR, "gflags:reset_gflag: Invalid parameter\n");
- return -1;
- }
-
- flag=((fparam_t*)flag_par)->v.i;
- (*gflags) &= ~ (1 << flag);
- return 1;
- }
- static int is_gflag(struct sip_msg *bar, char *flag_par, char *foo)
- {
- unsigned long int flag;
- if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
- LOG(L_ERR, "gflags:is_gflag: Invalid parameter\n");
- return -1;
- }
-
- flag=((fparam_t*)flag_par)->v.i;
- return ( (*gflags) & (1<<flag)) ? 1 : -1;
- }
- /*
- * Load attributes from global_attrs table
- */
- static int load_attrs(avp_list_t* global_avps)
- {
- int_str name, v;
- db_res_t* res;
- db_rec_t* rec;
- str avp_val;
- unsigned short flags;
- if (db_exec(&res, load_attrs_cmd) < 0) return -1;
- rec = db_first(res);
- while(rec) {
- if (rec->fld[0].flags & DB_NULL ||
- rec->fld[1].flags & DB_NULL ||
- rec->fld[3].flags & DB_NULL) {
- LOG(L_ERR, "gflags:load_attrs: Skipping row containing NULL entries\n");
- goto skip;
- }
- if ((rec->fld[3].v.int4 & SRDB_LOAD_SER) == 0) goto skip;
- name.s = rec->fld[0].v.lstr;
- /* Test for NULL value */
- if (rec->fld[2].flags & DB_NULL) {
- avp_val.s = 0;
- avp_val.len = 0;
- } else {
- avp_val = rec->fld[2].v.lstr;
- }
- flags = AVP_CLASS_GLOBAL | AVP_NAME_STR;
- if (rec->fld[1].v.int4 == AVP_VAL_STR) {
- /* String AVP */
- v.s = avp_val;
- flags |= AVP_VAL_STR;
- } else {
- /* Integer AVP */
- str2int(&avp_val, (unsigned*)&v.n);
- if (rec->fld[0].v.lstr.len == (sizeof(AVP_GFLAGS) - 1) &&
- !strncmp(rec->fld[0].v.lstr.s, AVP_GFLAGS, sizeof(AVP_GFLAGS) - 1)) {
- /* Restore gflags */
- *gflags = v.n;
- }
- }
-
- if (add_avp_list(global_avps, flags, name, v) < 0) {
- LOG(L_ERR, "gflags:load_attrs: Error while adding global attribute %.*s, skipping\n",
- rec->fld[0].v.lstr.len, ZSW(rec->fld[0].v.lstr.s));
- goto skip;
- }
- skip:
- rec = db_next(res);
- }
- db_res_free(res);
- 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;
- avps_1 = shm_malloc(sizeof(*avps_1));
- if (!avps_1) {
- ERR("can't allocate memory\n");
- return -1;
- }
- *avps_1 = NULL;
- avps_2 = shm_malloc(sizeof(*avps_2));
- if (!avps_2) {
- ERR("can't allocate memory\n");
- return -1;
- }
- *avps_2 = NULL;
- active_global_avps = &avps_1;
- if (load_global_attrs) {
- if (init_db() < 0) {
- shm_free(gflags);
- return -1;
- }
-
- if (load_attrs(*active_global_avps) < 0) {
- db_cmd_free(load_attrs_cmd);
- db_cmd_free(save_gflags_cmd);
- db_ctx_free(db);
- return -1;
- }
-
- set_avp_list(AVP_CLASS_GLOBAL, *active_global_avps);
-
- db_cmd_free(load_attrs_cmd);
- db_cmd_free(save_gflags_cmd);
- db_ctx_free(db);
- load_attrs_cmd = NULL;
- save_gflags_cmd = NULL;
- db = NULL;
- }
- return 0;
- }
- static int child_init(int rank)
- {
- if (load_global_attrs) {
- if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
- return 0; /* do nothing for the main or tcp_main processes */
- if (init_db() < 0) return -1;
- }
- return 0;
- }
- static void mod_destroy(void)
- {
- if (avps_1 != 0) {
- destroy_avp_list(avps_1);
- }
- if (avps_2 != 0) {
- destroy_avp_list(avps_2);
- }
- active_global_avps = 0;
- if (load_attrs_cmd) db_cmd_free(load_attrs_cmd);
- if (save_gflags_cmd) db_cmd_free(save_gflags_cmd);
- if (db) db_ctx_free(db);
- }
- int save_gflags(unsigned int flags)
- {
- str fl;
- if (!load_global_attrs) {
- LOG(L_ERR, "gflags:save_gflags: You must enable load_global_attrs to make flush_gflag work\n");
- return -1;
- }
- fl.s = int2str(flags, &fl.len);
- save_gflags_cmd->vals[0].v.cstr = AVP_GFLAGS;
- save_gflags_cmd->vals[1].v.int4 = 0;
- save_gflags_cmd->vals[2].v.lstr = fl;
- save_gflags_cmd->vals[3].v.bitmap = SRDB_LOAD_SER;
- if (db_exec(NULL, save_gflags_cmd) < 0) {
- LOG(L_ERR, "gflags:save_gflag: Unable to store new value\n");
- return -1;
- }
- DBG("gflags:save_gflags: Successfuly stored in database\n");
- return 0;
- }
- static int reload_global_attributes(void)
- {
- avp_list_t** new_global_avps;
-
- /* Choose new global AVP list and free its old contents */
- if (active_global_avps == &avps_1) {
- destroy_avp_list(avps_2);
- new_global_avps = &avps_2;
- }
- else {
- destroy_avp_list(avps_1);
- new_global_avps = &avps_1;
- }
-
- if (load_attrs(*new_global_avps) < 0) {
- goto error;
- }
-
- active_global_avps = new_global_avps;
- set_avp_list(AVP_CLASS_GLOBAL, *active_global_avps);
- return 0;
-
- error:
- destroy_avp_list(*new_global_avps);
- return -1;
- }
- /*
- * Flush the state of global flags into database
- */
- static int flush_gflags(struct sip_msg* msg, char* s1, char* s2)
- {
- if (save_gflags(*gflags) < 0) return -1;
- else return 1;
- }
- static const char* rpc_set_doc[] = {
- "Load a CPL script to the server.", /* Documentation string */
- 0 /* Method signature(s) */
- };
- static void rpc_set(rpc_t* rpc, void* c)
- {
- int flag;
- if (rpc->scan(c, "d", &flag) < 1) {
- rpc->fault(c, 400, "Flag number expected");
- return;
- }
- if (flag < 0 || flag > 31) {
- rpc->fault(c, 400, "Flag number %d out of range", &flag);
- }
- (*gflags) |= 1 << flag;
- }
- static const char* rpc_is_set_doc[] = {
- "Load a CPL script to the server.", /* Documentation string */
- 0 /* Method signature(s) */
- };
- static void rpc_is_set(rpc_t* rpc, void* c)
- {
- int flag;
- if (rpc->scan(c, "d", &flag) < 1) {
- rpc->fault(c, 400, "Flag number expected");
- return;
- }
- if (flag < 0 || flag > 31) {
- rpc->fault(c, 400, "Flag number %d out of range", &flag);
- }
- rpc->add(c, "b", (*gflags) & (1 << flag));
- }
- static const char* rpc_reset_doc[] = {
- "Load a CPL script to the server.", /* Documentation string */
- 0 /* Method signature(s) */
- };
- static void rpc_reset(rpc_t* rpc, void* c)
- {
- int flag;
- if (rpc->scan(c, "d", &flag) < 1) {
- rpc->fault(c, 400, "Flag number expected");
- return;
- }
- if (flag < 0 || flag > 31) {
- rpc->fault(c, 400, "Flag number %d out of range", &flag);
- }
- (*gflags) &= ~ (1 << flag);
- }
- static const char* rpc_flush_doc[] = {
- "Load a CPL script to the server.", /* Documentation string */
- 0 /* Method signature(s) */
- };
- static void rpc_flush(rpc_t* rpc, void* c)
- {
- if (flush_gflags(0, 0, 0) < 0) {
- rpc->fault(c, 400, "Error while saving flags to database");
- }
- }
- static const char* rpc_dump_doc[] = {
- "Load a CPL script to the server.", /* Documentation string */
- 0 /* Method signature(s) */
- };
- static void rpc_dump(rpc_t* rpc, void* c)
- {
- int i;
- for(i = 0; i < 32; i++) {
- rpc->add(c, "b", (*gflags >> i) & 1);
- }
- }
- static const char* rpc_reload_doc[2] = {
- "Reload global attributes from database",
- 0
- };
- /*
- * Fifo function to reload domain table
- */
- static void rpc_reload(rpc_t* rpc, void* ctx)
- {
- if (reload_global_attributes() < 0) {
- LOG(L_ERR, "ERROR: Reloading of global_attrs table has failed\n");
- rpc->fault(ctx, 400, "Reloading of global attributes failed");
- }
- else {
- /* reload is successful */
- LOG(L_INFO, "INFO: global_attrs table reloaded\n");
- }
- }
- /*
- * RPC Methods exported by this module
- */
- static rpc_export_t rpc_methods[] = {
- {"gflags.set", rpc_set, rpc_set_doc, 0},
- {"gflags.is_set", rpc_is_set, rpc_is_set_doc, 0},
- {"gflags.reset", rpc_reset, rpc_reset_doc, 0},
- {"gflags.flush", rpc_flush, rpc_flush_doc, 0},
- {"gflags.dump", rpc_dump, rpc_dump_doc, 0},
- {"global.reload", rpc_reload, rpc_reload_doc, 0},
- {0, 0, 0, 0}
- };
|