ul_mod.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * $Id$
  3. *
  4. * Usrloc module interface
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * History:
  25. * ---------
  26. * 2003-01-27 timer activity printing #ifdef-ed to EXTRA_DEBUG (jiri)
  27. * 2003-03-11 New module interface (janakj)
  28. * 2003-03-12 added replication and state columns (nils)
  29. * 2003-03-16 flags export parameter added (janakj)
  30. * 2003-04-05: default_uri #define used (jiri)
  31. * 2003-04-21 failed fifo init stops init process (jiri)
  32. * 2004-03-17 generic callbacks added (bogdan)
  33. * 2004-06-07 updated to the new DB api (andrei)
  34. */
  35. /*! \file
  36. * \brief USRLOC - Usrloc module interface
  37. * \ingroup usrloc
  38. *
  39. * - Module \ref usrloc
  40. */
  41. /*!
  42. * \defgroup usrloc Usrloc :: User location module
  43. * \brief User location module
  44. *
  45. * The module keeps a user location table and provides access
  46. * to the table to other modules. The module exports no functions
  47. * that could be used directly from scripts, all access is done
  48. * over a API. A main user of this API is the registrar module.
  49. * \see registrar
  50. */
  51. #include <stdio.h>
  52. #include "ul_mod.h"
  53. #include "../../sr_module.h"
  54. #include "../../dprint.h"
  55. #include "../../rpc_lookup.h"
  56. #include "../../timer.h" /* register_timer */
  57. #include "../../timer_proc.h" /* register_sync_timer */
  58. #include "../../globals.h" /* is_main */
  59. #include "../../ut.h" /* str_init */
  60. #include "../../lib/srutils/sruid.h"
  61. #include "dlist.h" /* register_udomain */
  62. #include "udomain.h" /* {insert,delete,get,release}_urecord */
  63. #include "urecord.h" /* {insert,delete,get}_ucontact */
  64. #include "ucontact.h" /* update_ucontact */
  65. #include "ul_mi.h"
  66. #include "ul_rpc.h"
  67. #include "ul_callback.h"
  68. #include "usrloc.h"
  69. MODULE_VERSION
  70. #define RUID_COL "ruid"
  71. #define USER_COL "username"
  72. #define DOMAIN_COL "domain"
  73. #define CONTACT_COL "contact"
  74. #define EXPIRES_COL "expires"
  75. #define Q_COL "q"
  76. #define CALLID_COL "callid"
  77. #define CSEQ_COL "cseq"
  78. #define FLAGS_COL "flags"
  79. #define CFLAGS_COL "cflags"
  80. #define USER_AGENT_COL "user_agent"
  81. #define RECEIVED_COL "received"
  82. #define PATH_COL "path"
  83. #define SOCK_COL "socket"
  84. #define METHODS_COL "methods"
  85. #define INSTANCE_COL "instance"
  86. #define REG_ID_COL "reg_id"
  87. #define LAST_MOD_COL "last_modified"
  88. #define ULATTRS_USER_COL "username"
  89. #define ULATTRS_DOMAIN_COL "domain"
  90. #define ULATTRS_RUID_COL "ruid"
  91. #define ULATTRS_ANAME_COL "aname"
  92. #define ULATTRS_ATYPE_COL "atype"
  93. #define ULATTRS_AVALUE_COL "avalue"
  94. #define ULATTRS_LAST_MOD_COL "last_modified"
  95. static int mod_init(void); /*!< Module initialization function */
  96. static void destroy(void); /*!< Module destroy function */
  97. static void ul_core_timer(unsigned int ticks, void* param); /*!< Core timer handler */
  98. static void ul_local_timer(unsigned int ticks, void* param); /*!< Local timer handler */
  99. static int child_init(int rank); /*!< Per-child init function */
  100. static int mi_child_init(void);
  101. #define UL_PRELOAD_SIZE 8
  102. static char* ul_preload_list[UL_PRELOAD_SIZE];
  103. static int ul_preload_index = 0;
  104. static int ul_preload_param(modparam_t type, void* val);
  105. extern int bind_usrloc(usrloc_api_t* api);
  106. extern int ul_locks_no;
  107. int ul_db_update_as_insert = 0;
  108. int ul_timer_procs = 0;
  109. int ul_db_check_update = 0;
  110. int ul_keepalive_timeout = 0;
  111. int ul_db_ops_ruid = 1;
  112. int ul_expires_type = 0;
  113. int ul_db_raw_fetch_type = 0;
  114. str ul_xavp_contact_name = {0};
  115. /* sruid to get internal uid for mi/rpc commands */
  116. sruid_t _ul_sruid;
  117. /*
  118. * Module parameters and their default values
  119. */
  120. str ruid_col = str_init(RUID_COL); /*!< Name of column containing record unique id */
  121. str user_col = str_init(USER_COL); /*!< Name of column containing usernames */
  122. str domain_col = str_init(DOMAIN_COL); /*!< Name of column containing domains */
  123. str contact_col = str_init(CONTACT_COL); /*!< Name of column containing contact addresses */
  124. str expires_col = str_init(EXPIRES_COL); /*!< Name of column containing expires values */
  125. str q_col = str_init(Q_COL); /*!< Name of column containing q values */
  126. str callid_col = str_init(CALLID_COL); /*!< Name of column containing callid string */
  127. str cseq_col = str_init(CSEQ_COL); /*!< Name of column containing cseq values */
  128. str flags_col = str_init(FLAGS_COL); /*!< Name of column containing internal flags */
  129. str cflags_col = str_init(CFLAGS_COL); /*!< Name of column containing contact flags */
  130. str user_agent_col = str_init(USER_AGENT_COL); /*!< Name of column containing user agent string */
  131. str received_col = str_init(RECEIVED_COL); /*!< Name of column containing transport info of REGISTER */
  132. str path_col = str_init(PATH_COL); /*!< Name of column containing the Path header */
  133. str sock_col = str_init(SOCK_COL); /*!< Name of column containing the received socket */
  134. str methods_col = str_init(METHODS_COL); /*!< Name of column containing the supported methods */
  135. str instance_col = str_init(INSTANCE_COL); /*!< Name of column containing the SIP instance value */
  136. str reg_id_col = str_init(REG_ID_COL); /*!< Name of column containing the reg-id value */
  137. str last_mod_col = str_init(LAST_MOD_COL); /*!< Name of column containing the last modified date */
  138. str ulattrs_user_col = str_init(ULATTRS_USER_COL); /*!< Name of column containing username */
  139. str ulattrs_domain_col = str_init(ULATTRS_DOMAIN_COL); /*!< Name of column containing domain */
  140. str ulattrs_ruid_col = str_init(ULATTRS_RUID_COL); /*!< Name of column containing record unique id */
  141. str ulattrs_aname_col = str_init(ULATTRS_ANAME_COL); /*!< Name of column containing attribute name */
  142. str ulattrs_atype_col = str_init(ULATTRS_ATYPE_COL); /*!< Name of column containing attribute type */
  143. str ulattrs_avalue_col = str_init(ULATTRS_AVALUE_COL); /*!< Name of column containing attribute value */
  144. str ulattrs_last_mod_col = str_init(ULATTRS_LAST_MOD_COL); /*!< Name of column containing the last modified date */
  145. str db_url = str_init(DEFAULT_DB_URL); /*!< Database URL */
  146. int timer_interval = 60; /*!< Timer interval in seconds */
  147. int db_mode = 0; /*!< Database sync scheme: 0-no db, 1-write through, 2-write back, 3-only db */
  148. int use_domain = 0; /*!< Whether usrloc should use domain part of aor */
  149. int desc_time_order = 0; /*!< By default do not enable timestamp ordering */
  150. int handle_lost_tcp = 0; /*!< By default do not remove contacts before expiration time */
  151. int ul_fetch_rows = 2000; /*!< number of rows to fetch from result */
  152. int ul_hash_size = 10;
  153. int ul_db_insert_null = 0;
  154. /* flags */
  155. unsigned int nat_bflag = (unsigned int)-1;
  156. unsigned int init_flag = 0;
  157. db1_con_t* ul_dbh = 0; /* Database connection handle */
  158. db_func_t ul_dbf;
  159. /*! \brief
  160. * Exported functions
  161. */
  162. static cmd_export_t cmds[] = {
  163. {"ul_bind_usrloc", (cmd_function)bind_usrloc, 1, 0, 0, 0},
  164. {0, 0, 0, 0, 0, 0}
  165. };
  166. /*! \brief
  167. * Exported parameters
  168. */
  169. static param_export_t params[] = {
  170. {"ruid_column", PARAM_STR, &ruid_col },
  171. {"user_column", PARAM_STR, &user_col },
  172. {"domain_column", PARAM_STR, &domain_col },
  173. {"contact_column", PARAM_STR, &contact_col },
  174. {"expires_column", PARAM_STR, &expires_col },
  175. {"q_column", PARAM_STR, &q_col },
  176. {"callid_column", PARAM_STR, &callid_col },
  177. {"cseq_column", PARAM_STR, &cseq_col },
  178. {"flags_column", PARAM_STR, &flags_col },
  179. {"cflags_column", PARAM_STR, &cflags_col },
  180. {"db_url", PARAM_STR, &db_url },
  181. {"timer_interval", INT_PARAM, &timer_interval },
  182. {"db_mode", INT_PARAM, &db_mode },
  183. {"use_domain", INT_PARAM, &use_domain },
  184. {"desc_time_order", INT_PARAM, &desc_time_order },
  185. {"user_agent_column", PARAM_STR, &user_agent_col},
  186. {"received_column", PARAM_STR, &received_col },
  187. {"path_column", PARAM_STR, &path_col },
  188. {"socket_column", PARAM_STR, &sock_col },
  189. {"methods_column", PARAM_STR, &methods_col },
  190. {"instance_column", PARAM_STR, &instance_col },
  191. {"reg_id_column", PARAM_STR, &reg_id_col },
  192. {"matching_mode", INT_PARAM, &matching_mode },
  193. {"cseq_delay", INT_PARAM, &cseq_delay },
  194. {"fetch_rows", INT_PARAM, &ul_fetch_rows },
  195. {"hash_size", INT_PARAM, &ul_hash_size },
  196. {"nat_bflag", INT_PARAM, &nat_bflag },
  197. {"handle_lost_tcp", INT_PARAM, &handle_lost_tcp },
  198. {"preload", PARAM_STRING|USE_FUNC_PARAM, (void*)ul_preload_param},
  199. {"db_update_as_insert", INT_PARAM, &ul_db_update_as_insert},
  200. {"timer_procs", INT_PARAM, &ul_timer_procs},
  201. {"db_check_update", INT_PARAM, &ul_db_check_update},
  202. {"xavp_contact", PARAM_STR, &ul_xavp_contact_name},
  203. {"db_ops_ruid", INT_PARAM, &ul_db_ops_ruid},
  204. {"expires_type", PARAM_INT, &ul_expires_type},
  205. {"db_raw_fetch_type", PARAM_INT, &ul_db_raw_fetch_type},
  206. {"db_insert_null", PARAM_INT, &ul_db_insert_null},
  207. {0, 0, 0}
  208. };
  209. stat_export_t mod_stats[] = {
  210. {"registered_users" , STAT_IS_FUNC, (stat_var**)get_number_of_users },
  211. {0,0,0}
  212. };
  213. static mi_export_t mi_cmds[] = {
  214. { MI_USRLOC_RM, mi_usrloc_rm_aor, 0, 0,
  215. mi_child_init },
  216. { MI_USRLOC_RM_CONTACT, mi_usrloc_rm_contact, 0, 0,
  217. mi_child_init },
  218. { MI_USRLOC_DUMP, mi_usrloc_dump, 0, 0,
  219. 0 },
  220. { MI_USRLOC_FLUSH, mi_usrloc_flush, MI_NO_INPUT_FLAG, 0,
  221. mi_child_init },
  222. { MI_USRLOC_ADD, mi_usrloc_add, 0, 0,
  223. mi_child_init },
  224. { MI_USRLOC_SHOW_CONTACT, mi_usrloc_show_contact, 0, 0,
  225. mi_child_init },
  226. { 0, 0, 0, 0, 0}
  227. };
  228. struct module_exports exports = {
  229. "usrloc",
  230. DEFAULT_DLFLAGS, /*!< dlopen flags */
  231. cmds, /*!< Exported functions */
  232. params, /*!< Export parameters */
  233. mod_stats, /*!< exported statistics */
  234. mi_cmds, /*!< exported MI functions */
  235. 0, /*!< exported pseudo-variables */
  236. 0, /*!< extra processes */
  237. mod_init, /*!< Module initialization function */
  238. 0, /*!< Response function */
  239. destroy, /*!< Destroy function */
  240. child_init /*!< Child initialization function */
  241. };
  242. /*! \brief
  243. * Module initialization function
  244. */
  245. static int mod_init(void)
  246. {
  247. int i;
  248. udomain_t* d;
  249. if(sruid_init(&_ul_sruid, '-', "ulcx", SRUID_INC)<0)
  250. return -1;
  251. #ifdef STATISTICS
  252. /* register statistics */
  253. if (register_module_stats( exports.name, mod_stats)!=0 ) {
  254. LM_ERR("failed to register core statistics\n");
  255. return -1;
  256. }
  257. #endif
  258. if(register_mi_mod(exports.name, mi_cmds)!=0)
  259. {
  260. LM_ERR("failed to register MI commands\n");
  261. return -1;
  262. }
  263. if (rpc_register_array(ul_rpc)!=0)
  264. {
  265. LM_ERR("failed to register RPC commands\n");
  266. return -1;
  267. }
  268. if(ul_hash_size<=1)
  269. ul_hash_size = 512;
  270. else
  271. ul_hash_size = 1<<ul_hash_size;
  272. ul_locks_no = ul_hash_size;
  273. /* check matching mode */
  274. switch (matching_mode) {
  275. case CONTACT_ONLY:
  276. case CONTACT_CALLID:
  277. case CONTACT_PATH:
  278. break;
  279. default:
  280. LM_ERR("invalid matching mode %d\n", matching_mode);
  281. }
  282. if(ul_init_locks()!=0)
  283. {
  284. LM_ERR("locks array initialization failed\n");
  285. return -1;
  286. }
  287. /* Register cache timer */
  288. if(ul_timer_procs<=0)
  289. {
  290. if (timer_interval > 0)
  291. register_timer(ul_core_timer, 0, timer_interval);
  292. }
  293. else
  294. register_sync_timers(ul_timer_procs);
  295. /* init the callbacks list */
  296. if ( init_ulcb_list() < 0) {
  297. LM_ERR("usrloc/callbacks initialization failed\n");
  298. return -1;
  299. }
  300. /* Shall we use database ? */
  301. if (db_mode != NO_DB) { /* Yes */
  302. if (db_bind_mod(&db_url, &ul_dbf) < 0) { /* Find database module */
  303. LM_ERR("failed to bind database module\n");
  304. return -1;
  305. }
  306. if (!DB_CAPABILITY(ul_dbf, DB_CAP_ALL)) {
  307. LM_ERR("database module does not implement all functions"
  308. " needed by the module\n");
  309. return -1;
  310. }
  311. if(ul_fetch_rows<=0) {
  312. LM_ERR("invalid fetch_rows number '%d'\n", ul_fetch_rows);
  313. return -1;
  314. }
  315. }
  316. if (nat_bflag==(unsigned int)-1) {
  317. nat_bflag = 0;
  318. } else if ( nat_bflag>=8*sizeof(nat_bflag) ) {
  319. LM_ERR("bflag index (%d) too big!\n", nat_bflag);
  320. return -1;
  321. } else {
  322. nat_bflag = 1<<nat_bflag;
  323. }
  324. for(i=0; i<ul_preload_index; i++) {
  325. if(register_udomain((const char*)ul_preload_list[i], &d)<0) {
  326. LM_ERR("cannot register preloaded table %s\n", ul_preload_list[i]);
  327. return -1;
  328. }
  329. }
  330. if (handle_lost_tcp && db_mode == DB_ONLY)
  331. LM_WARN("handle_lost_tcp option makes nothing in DB_ONLY mode\n");
  332. init_flag = 1;
  333. return 0;
  334. }
  335. static int child_init(int _rank)
  336. {
  337. dlist_t* ptr;
  338. int i;
  339. if(sruid_init(&_ul_sruid, '-', "ulcx", SRUID_INC)<0)
  340. return -1;
  341. if(_rank==PROC_MAIN && ul_timer_procs>0)
  342. {
  343. for(i=0; i<ul_timer_procs; i++)
  344. {
  345. if(fork_sync_timer(PROC_TIMER, "USRLOC Timer", 1 /*socks flag*/,
  346. ul_local_timer, (void*)(long)i, timer_interval /*sec*/)<0) {
  347. LM_ERR("failed to start timer routine as process\n");
  348. return -1; /* error */
  349. }
  350. }
  351. }
  352. /* connecting to DB ? */
  353. switch (db_mode) {
  354. case NO_DB:
  355. return 0;
  356. case DB_ONLY:
  357. case WRITE_THROUGH:
  358. /* connect to db only from SIP workers, TIMER and MAIN processes */
  359. if (_rank<=0 && _rank!=PROC_TIMER && _rank!=PROC_MAIN)
  360. return 0;
  361. break;
  362. case WRITE_BACK:
  363. /* connect to db only from TIMER (for flush), from MAIN (for
  364. * final flush() and from child 1 for preload */
  365. if (_rank!=PROC_TIMER && _rank!=PROC_MAIN && _rank!=PROC_SIPINIT)
  366. return 0;
  367. break;
  368. case DB_READONLY:
  369. /* connect to db only from child 1 for preload */
  370. if(_rank!=PROC_SIPINIT)
  371. return 0;
  372. break;
  373. }
  374. ul_dbh = ul_dbf.init(&db_url); /* Get a database connection per child */
  375. if (!ul_dbh) {
  376. LM_ERR("child(%d): failed to connect to database\n", _rank);
  377. return -1;
  378. }
  379. /* _rank==PROC_SIPINIT is used even when fork is disabled */
  380. if (_rank==PROC_SIPINIT && db_mode!=DB_ONLY) {
  381. /* if cache is used, populate domains from DB */
  382. for( ptr=root ; ptr ; ptr=ptr->next) {
  383. if (preload_udomain(ul_dbh, ptr->d) < 0) {
  384. LM_ERR("child(%d): failed to preload domain '%.*s'\n",
  385. _rank, ptr->name.len, ZSW(ptr->name.s));
  386. return -1;
  387. }
  388. uldb_preload_attrs(ptr->d);
  389. }
  390. }
  391. return 0;
  392. }
  393. /* */
  394. static int mi_child_init(void)
  395. {
  396. static int done = 0;
  397. if (done)
  398. return 0;
  399. if (db_mode != NO_DB) {
  400. ul_dbh = ul_dbf.init(&db_url);
  401. if (!ul_dbh) {
  402. LM_ERR("failed to connect to database\n");
  403. return -1;
  404. }
  405. }
  406. if(sruid_init(&_ul_sruid, '-', "ulcx", SRUID_INC)<0)
  407. return -1;
  408. done = 1;
  409. return 0;
  410. }
  411. /*! \brief
  412. * Module destroy function
  413. */
  414. static void destroy(void)
  415. {
  416. /* we need to sync DB in order to flush the cache */
  417. if (ul_dbh) {
  418. ul_unlock_locks();
  419. if (synchronize_all_udomains(0, 1) != 0) {
  420. LM_ERR("flushing cache failed\n");
  421. }
  422. ul_dbf.close(ul_dbh);
  423. }
  424. free_all_udomains();
  425. ul_destroy_locks();
  426. /* free callbacks list */
  427. destroy_ulcb_list();
  428. }
  429. /*! \brief
  430. * Core timer handler
  431. */
  432. static void ul_core_timer(unsigned int ticks, void* param)
  433. {
  434. if (synchronize_all_udomains(0, 1) != 0) {
  435. LM_ERR("synchronizing cache failed\n");
  436. }
  437. }
  438. /*! \brief
  439. * Local timer handler
  440. */
  441. static void ul_local_timer(unsigned int ticks, void* param)
  442. {
  443. if (synchronize_all_udomains((int)(long)param, ul_timer_procs) != 0) {
  444. LM_ERR("synchronizing cache failed\n");
  445. }
  446. }
  447. /*! \brief
  448. * preload module parameter handler
  449. */
  450. static int ul_preload_param(modparam_t type, void* val)
  451. {
  452. if(val==NULL)
  453. {
  454. LM_ERR("invalid parameter\n");
  455. goto error;
  456. }
  457. if(ul_preload_index>=UL_PRELOAD_SIZE)
  458. {
  459. LM_ERR("too many preloaded tables\n");
  460. goto error;
  461. }
  462. ul_preload_list[ul_preload_index] = (char*)val;
  463. ul_preload_index++;
  464. return 0;
  465. error:
  466. return -1;
  467. }