uid_gflags.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*$Id$
  2. *
  3. * gflags module: global flags; it keeps a bitmap of flags
  4. * in shared memory and may be used to change behaviour
  5. * of server based on value of the flags. E.g.,
  6. * if (is_gflag("1")) { t_relay_to_udp("10.0.0.1","5060"); }
  7. * else { t_relay_to_udp("10.0.0.2","5060"); }
  8. * The benefit of this module is the value of the switch flags
  9. * can be manipulated by external applications such as web interface
  10. * or command line tools.
  11. *
  12. *
  13. * Copyright (C) 2004 FhG FOKUS
  14. *
  15. * This file is part of ser, a free SIP server.
  16. *
  17. * ser is free software; you can redistribute it and/or modify
  18. * it under the terms of the GNU General Public License as published by
  19. * the Free Software Foundation; either version 2 of the License, or
  20. * (at your option) any later version
  21. *
  22. * For a license to use the ser software under conditions
  23. * other than those described here, or to purchase support for this
  24. * software, please contact iptel.org by e-mail at the following addresses:
  25. * [email protected]
  26. *
  27. * ser is distributed in the hope that it will be useful,
  28. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  29. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  30. * GNU General Public License for more details.
  31. *
  32. * You should have received a copy of the GNU General Public License
  33. * along with this program; if not, write to the Free Software
  34. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  35. */
  36. /*
  37. * History:
  38. * --------
  39. * 2004-09-09 initial module created (jiri)
  40. * 2006-12-04 added xmlrpc command global.reload for reloading of global_attrs
  41. * db table (vlada)
  42. *
  43. * TODO
  44. * - flag range checking
  45. * - named flags (takes a protected name list)
  46. */
  47. #include <stdio.h>
  48. #include "../../sr_module.h"
  49. #include "../../error.h"
  50. #include "../../ut.h"
  51. #include "../../lib/srdb2/db.h"
  52. #include "../../mem/mem.h"
  53. #include "../../mem/shm_mem.h"
  54. #include "../../usr_avp.h"
  55. #include "../../rpc.h"
  56. #include "../../config.h"
  57. MODULE_VERSION
  58. static int set_gflag(struct sip_msg*, char *, char *);
  59. static int reset_gflag(struct sip_msg*, char *, char *);
  60. static int is_gflag(struct sip_msg*, char *, char *);
  61. static int flush_gflags(struct sip_msg*, char*, char*);
  62. static int mod_init(void);
  63. static void mod_destroy(void);
  64. static int child_init(int rank);
  65. static int reload_global_attributes(void);
  66. static int initial = 0;
  67. static unsigned int *gflags;
  68. static char* db_url = DEFAULT_DB_URL;
  69. static int load_global_attrs = 0;
  70. static char* attr_table = "uid_global_attrs";
  71. static char* attr_name = "name";
  72. static char* attr_type = "type";
  73. static char* attr_value = "value";
  74. static char* attr_flags = "flags";
  75. static db_ctx_t* db = NULL;
  76. static db_cmd_t* load_attrs_cmd = NULL, *save_gflags_cmd = NULL;
  77. static avp_list_t** active_global_avps;
  78. static avp_list_t *avps_1;
  79. static avp_list_t *avps_2;
  80. static rpc_export_t rpc_methods[];
  81. static cmd_export_t cmds[]={
  82. {"set_ugflag", set_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
  83. {"reset_ugflag", reset_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
  84. {"is_ugflag", is_gflag, 1, fixup_int_1, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
  85. {"flush_ugflags", flush_gflags, 0, 0, REQUEST_ROUTE|FAILURE_ROUTE|ONREPLY_ROUTE},
  86. {0, 0, 0, 0, 0}
  87. };
  88. static param_export_t params[]={
  89. {"initial", PARAM_INT, &initial },
  90. {"db_url", PARAM_STRING, &db_url },
  91. {"load_global_attrs", PARAM_INT, &load_global_attrs},
  92. {"global_attrs_table", PARAM_STRING, &attr_table },
  93. {"global_attrs_name", PARAM_STRING, &attr_name },
  94. {"global_attrs_type", PARAM_STRING, &attr_type },
  95. {"global_attrs_value", PARAM_STRING, &attr_value },
  96. {"global_attrs_flags", PARAM_STRING, &attr_flags },
  97. {0, 0, 0}
  98. };
  99. struct module_exports exports = {
  100. "uid_gflags",
  101. cmds,
  102. rpc_methods, /* RPC methods */
  103. params,
  104. mod_init, /* module initialization function */
  105. 0, /* response function*/
  106. mod_destroy, /* destroy function */
  107. 0, /* oncancel function */
  108. child_init /* per-child init function */
  109. };
  110. static int init_db(void)
  111. {
  112. db_fld_t attr_res[] = {
  113. {.name = attr_name, DB_STR},
  114. {.name = attr_type, DB_INT},
  115. {.name = attr_value, DB_STR},
  116. {.name = attr_flags, DB_BITMAP},
  117. {.name = NULL}
  118. };
  119. db_fld_t values[] = {
  120. {.name = attr_name, DB_CSTR},
  121. {.name = attr_type, DB_INT},
  122. {.name = attr_value, DB_STR},
  123. {.name = attr_flags, DB_BITMAP},
  124. {.name = NULL}
  125. };
  126. db = db_ctx("gflags");
  127. if (db == NULL) {
  128. ERR("Error while initializing database layer\n");
  129. return -1;
  130. }
  131. if (db_add_db(db, db_url) < 0) return -1;
  132. if (db_connect(db) < 0) return -1;
  133. /* SELECT name, type, value, flags FROM global_attrs */
  134. load_attrs_cmd = db_cmd(DB_GET, db, attr_table, attr_res, NULL, NULL);
  135. if (load_attrs_cmd == NULL) {
  136. ERR("Error while building db query to load global attributes\n");
  137. return -1;
  138. }
  139. save_gflags_cmd = db_cmd(DB_PUT, db, attr_table, NULL, NULL, values);
  140. if (save_gflags_cmd == NULL) {
  141. ERR("Error while building db query to save global flags\n");
  142. return -1;
  143. }
  144. return 0;
  145. }
  146. static int set_gflag(struct sip_msg *bar, char *flag_par, char *foo)
  147. {
  148. unsigned long int flag;
  149. if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
  150. LOG(L_ERR, "gflags:set_gflag: Invalid parameter\n");
  151. return -1;
  152. }
  153. flag=((fparam_t*)flag_par)->v.i;
  154. (*gflags) |= 1 << flag;
  155. return 1;
  156. }
  157. static int reset_gflag(struct sip_msg *bar, char *flag_par, char *foo)
  158. {
  159. unsigned long int flag;
  160. if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
  161. LOG(L_ERR, "gflags:reset_gflag: Invalid parameter\n");
  162. return -1;
  163. }
  164. flag=((fparam_t*)flag_par)->v.i;
  165. (*gflags) &= ~ (1 << flag);
  166. return 1;
  167. }
  168. static int is_gflag(struct sip_msg *bar, char *flag_par, char *foo)
  169. {
  170. unsigned long int flag;
  171. if (!flag_par || ((fparam_t*)flag_par)->type != FPARAM_INT) {
  172. LOG(L_ERR, "gflags:is_gflag: Invalid parameter\n");
  173. return -1;
  174. }
  175. flag=((fparam_t*)flag_par)->v.i;
  176. return ( (*gflags) & (1<<flag)) ? 1 : -1;
  177. }
  178. /*
  179. * Load attributes from global_attrs table
  180. */
  181. static int load_attrs(avp_list_t* global_avps)
  182. {
  183. int_str name, v;
  184. db_res_t* res;
  185. db_rec_t* rec;
  186. str avp_val;
  187. unsigned short flags;
  188. if (db_exec(&res, load_attrs_cmd) < 0) return -1;
  189. rec = db_first(res);
  190. while(rec) {
  191. if (rec->fld[0].flags & DB_NULL ||
  192. rec->fld[1].flags & DB_NULL ||
  193. rec->fld[3].flags & DB_NULL) {
  194. LOG(L_ERR, "gflags:load_attrs: Skipping row containing NULL entries\n");
  195. goto skip;
  196. }
  197. if ((rec->fld[3].v.int4 & SRDB_LOAD_SER) == 0) goto skip;
  198. name.s = rec->fld[0].v.lstr;
  199. /* Test for NULL value */
  200. if (rec->fld[2].flags & DB_NULL) {
  201. avp_val.s = 0;
  202. avp_val.len = 0;
  203. } else {
  204. avp_val = rec->fld[2].v.lstr;
  205. }
  206. flags = AVP_CLASS_GLOBAL | AVP_NAME_STR;
  207. if (rec->fld[1].v.int4 == AVP_VAL_STR) {
  208. /* String AVP */
  209. v.s = avp_val;
  210. flags |= AVP_VAL_STR;
  211. } else {
  212. /* Integer AVP */
  213. str2int(&avp_val, (unsigned*)&v.n);
  214. if (rec->fld[0].v.lstr.len == (sizeof(AVP_GFLAGS) - 1) &&
  215. !strncmp(rec->fld[0].v.lstr.s, AVP_GFLAGS, sizeof(AVP_GFLAGS) - 1)) {
  216. /* Restore gflags */
  217. *gflags = v.n;
  218. }
  219. }
  220. if (add_avp_list(global_avps, flags, name, v) < 0) {
  221. LOG(L_ERR, "gflags:load_attrs: Error while adding global attribute %.*s, skipping\n",
  222. rec->fld[0].v.lstr.len, ZSW(rec->fld[0].v.lstr.s));
  223. goto skip;
  224. }
  225. skip:
  226. rec = db_next(res);
  227. }
  228. db_res_free(res);
  229. return 0;
  230. }
  231. static int mod_init(void)
  232. {
  233. gflags=(unsigned int *) shm_malloc(sizeof(unsigned int));
  234. if (!gflags) {
  235. LOG(L_ERR, "Error: gflags/mod_init: no shmem\n");
  236. return -1;
  237. }
  238. *gflags=initial;
  239. avps_1 = shm_malloc(sizeof(*avps_1));
  240. if (!avps_1) {
  241. ERR("can't allocate memory\n");
  242. return -1;
  243. }
  244. *avps_1 = NULL;
  245. avps_2 = shm_malloc(sizeof(*avps_2));
  246. if (!avps_2) {
  247. ERR("can't allocate memory\n");
  248. return -1;
  249. }
  250. *avps_2 = NULL;
  251. active_global_avps = &avps_1;
  252. if (load_global_attrs) {
  253. if (init_db() < 0) {
  254. shm_free(gflags);
  255. return -1;
  256. }
  257. if (load_attrs(*active_global_avps) < 0) {
  258. db_cmd_free(load_attrs_cmd);
  259. db_cmd_free(save_gflags_cmd);
  260. db_ctx_free(db);
  261. return -1;
  262. }
  263. set_avp_list(AVP_CLASS_GLOBAL, *active_global_avps);
  264. db_cmd_free(load_attrs_cmd);
  265. db_cmd_free(save_gflags_cmd);
  266. db_ctx_free(db);
  267. load_attrs_cmd = NULL;
  268. save_gflags_cmd = NULL;
  269. db = NULL;
  270. }
  271. return 0;
  272. }
  273. static int child_init(int rank)
  274. {
  275. if (load_global_attrs) {
  276. if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
  277. return 0; /* do nothing for the main or tcp_main processes */
  278. if (init_db() < 0) return -1;
  279. }
  280. return 0;
  281. }
  282. static void mod_destroy(void)
  283. {
  284. if (avps_1 != 0) {
  285. destroy_avp_list(avps_1);
  286. }
  287. if (avps_2 != 0) {
  288. destroy_avp_list(avps_2);
  289. }
  290. active_global_avps = 0;
  291. if (load_attrs_cmd) db_cmd_free(load_attrs_cmd);
  292. if (save_gflags_cmd) db_cmd_free(save_gflags_cmd);
  293. if (db) db_ctx_free(db);
  294. }
  295. int save_gflags(unsigned int flags)
  296. {
  297. str fl;
  298. if (!load_global_attrs) {
  299. LOG(L_ERR, "gflags:save_gflags: You must enable load_global_attrs to make flush_gflag work\n");
  300. return -1;
  301. }
  302. fl.s = int2str(flags, &fl.len);
  303. save_gflags_cmd->vals[0].v.cstr = AVP_GFLAGS;
  304. save_gflags_cmd->vals[1].v.int4 = 0;
  305. save_gflags_cmd->vals[2].v.lstr = fl;
  306. save_gflags_cmd->vals[3].v.bitmap = SRDB_LOAD_SER;
  307. if (db_exec(NULL, save_gflags_cmd) < 0) {
  308. LOG(L_ERR, "gflags:save_gflag: Unable to store new value\n");
  309. return -1;
  310. }
  311. DBG("gflags:save_gflags: Successfuly stored in database\n");
  312. return 0;
  313. }
  314. static int reload_global_attributes(void)
  315. {
  316. avp_list_t** new_global_avps;
  317. /* Choose new global AVP list and free its old contents */
  318. if (active_global_avps == &avps_1) {
  319. destroy_avp_list(avps_2);
  320. new_global_avps = &avps_2;
  321. }
  322. else {
  323. destroy_avp_list(avps_1);
  324. new_global_avps = &avps_1;
  325. }
  326. if (load_attrs(*new_global_avps) < 0) {
  327. goto error;
  328. }
  329. active_global_avps = new_global_avps;
  330. set_avp_list(AVP_CLASS_GLOBAL, *active_global_avps);
  331. return 0;
  332. error:
  333. destroy_avp_list(*new_global_avps);
  334. return -1;
  335. }
  336. /*
  337. * Flush the state of global flags into database
  338. */
  339. static int flush_gflags(struct sip_msg* msg, char* s1, char* s2)
  340. {
  341. if (save_gflags(*gflags) < 0) return -1;
  342. else return 1;
  343. }
  344. static const char* rpc_set_doc[] = {
  345. "Load a CPL script to the server.", /* Documentation string */
  346. 0 /* Method signature(s) */
  347. };
  348. static void rpc_set(rpc_t* rpc, void* c)
  349. {
  350. int flag;
  351. if (rpc->scan(c, "d", &flag) < 1) {
  352. rpc->fault(c, 400, "Flag number expected");
  353. return;
  354. }
  355. if (flag < 0 || flag > 31) {
  356. rpc->fault(c, 400, "Flag number %d out of range", &flag);
  357. }
  358. (*gflags) |= 1 << flag;
  359. }
  360. static const char* rpc_is_set_doc[] = {
  361. "Load a CPL script to the server.", /* Documentation string */
  362. 0 /* Method signature(s) */
  363. };
  364. static void rpc_is_set(rpc_t* rpc, void* c)
  365. {
  366. int flag;
  367. if (rpc->scan(c, "d", &flag) < 1) {
  368. rpc->fault(c, 400, "Flag number expected");
  369. return;
  370. }
  371. if (flag < 0 || flag > 31) {
  372. rpc->fault(c, 400, "Flag number %d out of range", &flag);
  373. }
  374. rpc->add(c, "b", (*gflags) & (1 << flag));
  375. }
  376. static const char* rpc_reset_doc[] = {
  377. "Load a CPL script to the server.", /* Documentation string */
  378. 0 /* Method signature(s) */
  379. };
  380. static void rpc_reset(rpc_t* rpc, void* c)
  381. {
  382. int flag;
  383. if (rpc->scan(c, "d", &flag) < 1) {
  384. rpc->fault(c, 400, "Flag number expected");
  385. return;
  386. }
  387. if (flag < 0 || flag > 31) {
  388. rpc->fault(c, 400, "Flag number %d out of range", &flag);
  389. }
  390. (*gflags) &= ~ (1 << flag);
  391. }
  392. static const char* rpc_flush_doc[] = {
  393. "Load a CPL script to the server.", /* Documentation string */
  394. 0 /* Method signature(s) */
  395. };
  396. static void rpc_flush(rpc_t* rpc, void* c)
  397. {
  398. if (flush_gflags(0, 0, 0) < 0) {
  399. rpc->fault(c, 400, "Error while saving flags to database");
  400. }
  401. }
  402. static const char* rpc_dump_doc[] = {
  403. "Load a CPL script to the server.", /* Documentation string */
  404. 0 /* Method signature(s) */
  405. };
  406. static void rpc_dump(rpc_t* rpc, void* c)
  407. {
  408. int i;
  409. for(i = 0; i < 32; i++) {
  410. rpc->add(c, "b", (*gflags >> i) & 1);
  411. }
  412. }
  413. static const char* rpc_reload_doc[2] = {
  414. "Reload global attributes from database",
  415. 0
  416. };
  417. /*
  418. * Fifo function to reload domain table
  419. */
  420. static void rpc_reload(rpc_t* rpc, void* ctx)
  421. {
  422. if (reload_global_attributes() < 0) {
  423. LOG(L_ERR, "ERROR: Reloading of global_attrs table has failed\n");
  424. rpc->fault(ctx, 400, "Reloading of global attributes failed");
  425. }
  426. else {
  427. /* reload is successful */
  428. LOG(L_INFO, "INFO: global_attrs table reloaded\n");
  429. }
  430. }
  431. /*
  432. * RPC Methods exported by this module
  433. */
  434. static rpc_export_t rpc_methods[] = {
  435. {"gflags.set", rpc_set, rpc_set_doc, 0},
  436. {"gflags.is_set", rpc_is_set, rpc_is_set_doc, 0},
  437. {"gflags.reset", rpc_reset, rpc_reset_doc, 0},
  438. {"gflags.flush", rpc_flush, rpc_flush_doc, 0},
  439. {"gflags.dump", rpc_dump, rpc_dump_doc, 0},
  440. {"global.reload", rpc_reload, rpc_reload_doc, 0},
  441. {0, 0, 0, 0}
  442. };