2
0

dialog.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/time.h>
  5. #include "../../sr_module.h"
  6. #include "../../lib/srdb1/db.h"
  7. #include "../../dprint.h"
  8. #include "../../error.h"
  9. #include "../../ut.h"
  10. #include "../../pvar.h"
  11. #include "../../mod_fix.h"
  12. #include "../../script_cb.h"
  13. #include "../../lib/kcore/faked_msg.h"
  14. #include "../../lib/kcore/kstats_wrapper.h"
  15. #include "../../mem/mem.h"
  16. #include "../../lib/kmi/mi.h"
  17. #include "../../lvalue.h"
  18. #include "../../parser/parse_to.h"
  19. #include "../../modules/tm/tm_load.h"
  20. #include "../../rpc_lookup.h"
  21. #include "../../modules/rr/api.h"
  22. #include "dlg_hash.h"
  23. #include "dlg_timer.h"
  24. #include "dlg_handlers.h"
  25. #include "dlg_load.h"
  26. #include "dlg_cb.h"
  27. #include "dlg_profile.h"
  28. #include "dlg_var.h"
  29. #include "dlg_req_within.h"
  30. #include "dlg_db_handler.h"
  31. MODULE_VERSION
  32. static int mod_init(void);
  33. static int child_init(int rank);
  34. static void mod_destroy(void);
  35. /* module parameter */
  36. static int dlg_hash_size = 4096;
  37. static char* rr_param = "did";
  38. static int dlg_flag = -1;
  39. static str timeout_spec = {NULL, 0};
  40. static int default_timeout = 60 * 60 * 12; /* 12 hours */
  41. static int seq_match_mode = SEQ_MATCH_STRICT_ID;
  42. static char* profiles_wv_s = NULL;
  43. static char* profiles_nv_s = NULL;
  44. int detect_spirals = 1;
  45. str dlg_extra_hdrs = {NULL, 0};
  46. int initial_cbs_inscript = 1;
  47. str dlg_bridge_controller = str_init("sip:[email protected]");
  48. str ruri_pvar_param = str_init("$ru");
  49. pv_elem_t * ruri_param_model = NULL;
  50. struct tm_binds d_tmb;
  51. struct rr_binds d_rrb;
  52. pv_spec_t timeout_avp;
  53. int active_dlgs_cnt = 0;
  54. int early_dlgs_cnt = 0;
  55. /* db stuff */
  56. int dlg_db_mode_param = DB_MODE_NONE;
  57. static int db_fetch_rows = 200;
  58. static str db_url = str_init(DEFAULT_DB_URL);
  59. static unsigned int db_update_period = DB_DEFAULT_UPDATE_PERIOD;
  60. /* commands wrappers and fixups */
  61. static int fixup_profile(void** param, int param_no);
  62. static int fixup_get_profile2(void** param, int param_no);
  63. static int fixup_get_profile3(void** param, int param_no);
  64. static int fixup_dlg_bridge(void** param, int param_no);
  65. static int fixup_dlg_terminate(void** param, int param_no);
  66. static int w_set_dlg_profile(struct sip_msg*, char*, char*);
  67. static int w_unset_dlg_profile(struct sip_msg*, char*, char*);
  68. static int w_is_in_profile(struct sip_msg*, char*, char*);
  69. static int w_get_profile_size2(struct sip_msg*, char*, char*);
  70. static int w_get_profile_size3(struct sip_msg*, char*, char*, char*);
  71. static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2);
  72. static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2);
  73. static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2);
  74. static int w_dlg_terminate(struct sip_msg*, char*, char*);
  75. static int w_dlg_get(struct sip_msg*, char*, char*, char*);
  76. static int w_is_known_dlg(struct sip_msg *);
  77. static cmd_export_t cmds[] = {
  78. {"set_dlg_profile", (cmd_function) w_set_dlg_profile, 1, fixup_profile,
  79. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  80. {"set_dlg_profile", (cmd_function) w_set_dlg_profile, 2, fixup_profile,
  81. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  82. {"unset_dlg_profile", (cmd_function) w_unset_dlg_profile, 1, fixup_profile,
  83. 0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  84. {"unset_dlg_profile", (cmd_function) w_unset_dlg_profile, 2, fixup_profile,
  85. 0, FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  86. {"is_in_profile", (cmd_function) w_is_in_profile, 1, fixup_profile,
  87. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  88. {"is_in_profile", (cmd_function) w_is_in_profile, 2, fixup_profile,
  89. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  90. {"get_profile_size", (cmd_function) w_get_profile_size2, 2, fixup_get_profile2,
  91. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  92. {"get_profile_size", (cmd_function) w_get_profile_size3, 3, fixup_get_profile3,
  93. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  94. {"dlg_setflag", (cmd_function) w_dlg_setflag, 1, fixup_igp_null,
  95. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  96. {"dlg_resetflag", (cmd_function) w_dlg_resetflag, 1, fixup_igp_null,
  97. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  98. {"dlg_isflagset", (cmd_function) w_dlg_isflagset, 1, fixup_igp_null,
  99. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  100. {"dlg_terminate", (cmd_function) w_dlg_terminate, 1, fixup_dlg_terminate,
  101. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  102. {"dlg_terminate", (cmd_function) w_dlg_terminate, 2, fixup_dlg_terminate,
  103. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  104. {"dlg_get", (cmd_function)w_dlg_get, 3, fixup_dlg_bridge, 0, ANY_ROUTE },
  105. {"is_known_dlg", (cmd_function) w_is_known_dlg, 0, NULL,
  106. 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE | BRANCH_ROUTE},
  107. {"load_dlg", (cmd_function) load_dlg, 0, 0, 0, 0},
  108. {0, 0, 0, 0, 0, 0}
  109. };
  110. static param_export_t mod_params[] = {
  111. { "hash_size", INT_PARAM, &dlg_hash_size},
  112. { "rr_param", PARAM_STRING, &rr_param},
  113. { "dlg_flag", INT_PARAM, &dlg_flag},
  114. { "timeout_avp", PARAM_STR, &timeout_spec},
  115. { "default_timeout", INT_PARAM, &default_timeout},
  116. { "dlg_extra_hdrs", PARAM_STR, &dlg_extra_hdrs},
  117. //In this new dialog module we always match using DID
  118. //{ "dlg_match_mode", INT_PARAM, &seq_match_mode},
  119. { "db_url", PARAM_STRING, &db_url },
  120. { "db_mode", INT_PARAM, &dlg_db_mode_param },
  121. { "db_update_period", INT_PARAM, &db_update_period },
  122. { "db_fetch_rows", INT_PARAM, &db_fetch_rows }
  123. ,
  124. { "detect_spirals", INT_PARAM, &detect_spirals },
  125. { "profiles_with_value",PARAM_STRING, &profiles_wv_s },
  126. { "profiles_no_value", PARAM_STRING, &profiles_nv_s },
  127. { "bridge_controller", PARAM_STR, &dlg_bridge_controller },
  128. { "ruri_pvar", PARAM_STR, &ruri_pvar_param },
  129. { 0, 0, 0}
  130. };
  131. static mi_export_t mi_cmds[] = {
  132. { "dlg_list", mi_print_dlgs, 0, 0, 0},
  133. { "dlg_terminate_dlg", mi_terminate_dlg, 0, 0, 0},
  134. { 0, 0, 0, 0, 0}
  135. /* TODO: restore old dialog functionality later - also expose dialoig_out cmds, possibly*/
  136. };
  137. static rpc_export_t rpc_methods[];
  138. struct module_exports exports = {
  139. "dialog_ng", /* module's name */
  140. DEFAULT_DLFLAGS, /* dlopen flags */
  141. cmds, /* exported functions */
  142. mod_params, /* param exports */
  143. 0, /* exported statistics */
  144. mi_cmds, /* exported MI functions */
  145. 0, /* exported pseudo-variables */
  146. 0, /* extra processes */
  147. mod_init, /* module initialization function */
  148. 0, /* reply processing function */
  149. mod_destroy,
  150. child_init /* per-child init function */
  151. };
  152. static int fixup_profile(void** param, int param_no) {
  153. struct dlg_profile_table *profile;
  154. pv_elem_t *model = NULL;
  155. str s;
  156. s.s = (char*) (*param);
  157. s.len = strlen(s.s);
  158. if (s.len == 0) {
  159. LM_ERR("param %d is empty string!\n", param_no);
  160. return E_CFG;
  161. }
  162. if (param_no == 1) {
  163. profile = search_dlg_profile(&s);
  164. if (profile == NULL) {
  165. LM_CRIT("profile <%s> not definited\n", s.s);
  166. return E_CFG;
  167. }
  168. pkg_free(*param);
  169. *param = (void*) profile;
  170. return 0;
  171. } else if (param_no == 2) {
  172. if (pv_parse_format(&s, &model) || model == NULL) {
  173. LM_ERR("wrong format [%s] for value param!\n", s.s);
  174. return E_CFG;
  175. }
  176. *param = (void*) model;
  177. }
  178. return 0;
  179. }
  180. static int fixup_get_profile2(void** param, int param_no) {
  181. pv_spec_t *sp;
  182. int ret;
  183. if (param_no == 1) {
  184. return fixup_profile(param, 1);
  185. } else if (param_no == 2) {
  186. ret = fixup_pvar_null(param, 1);
  187. if (ret < 0) return ret;
  188. sp = (pv_spec_t*) (*param);
  189. if (sp->type != PVT_AVP && sp->type != PVT_SCRIPTVAR) {
  190. LM_ERR("return must be an AVP or SCRIPT VAR!\n");
  191. return E_SCRIPT;
  192. }
  193. }
  194. return 0;
  195. }
  196. static int fixup_get_profile3(void** param, int param_no) {
  197. if (param_no == 1) {
  198. return fixup_profile(param, 1);
  199. } else if (param_no == 2) {
  200. return fixup_profile(param, 2);
  201. } else if (param_no == 3) {
  202. return fixup_get_profile2(param, 2);
  203. }
  204. return 0;
  205. }
  206. static int fixup_dlg_terminate(void** param, int param_no) {
  207. char *val;
  208. int n = 0;
  209. if (param_no == 1) {
  210. val = (char*) *param;
  211. if (strcasecmp(val, "all") == 0) {
  212. n = 2;
  213. } else if (strcasecmp(val, "caller") == 0) {
  214. n = 0;
  215. } else if (strcasecmp(val, "callee") == 0) {
  216. n = 1;
  217. } else {
  218. LM_ERR("invalid param \"%s\"\n", val);
  219. return E_CFG;
  220. }
  221. pkg_free(*param);
  222. *param = (void*) (long) n;
  223. } else if (param_no == 2) {
  224. //fixup str
  225. return fixup_str_12(param, param_no);
  226. } else {
  227. LM_ERR("called with parameter != 1\n");
  228. return E_BUG;
  229. }
  230. return 0;
  231. }
  232. static int fixup_dlg_bridge(void** param, int param_no)
  233. {
  234. if (param_no>=1 && param_no<=3) {
  235. return fixup_spve_null(param, 1);
  236. } else {
  237. LM_ERR("called with parameter idx %d\n", param_no);
  238. return E_BUG;
  239. }
  240. return 0;
  241. }
  242. static int w_dlg_get(struct sip_msg *msg, char *ci, char *ft, char *tt)
  243. {
  244. struct dlg_cell *dlg = NULL;
  245. str sc = {0,0};
  246. str sf = {0,0};
  247. str st = {0,0};
  248. unsigned int dir = 0;
  249. if(ci==0 || ft==0 || tt==0)
  250. {
  251. LM_ERR("invalid parameters\n");
  252. return -1;
  253. }
  254. if(fixup_get_svalue(msg, (gparam_p)ci, &sc)!=0)
  255. {
  256. LM_ERR("unable to get Call-ID\n");
  257. return -1;
  258. }
  259. if(sc.s==NULL || sc.len == 0)
  260. {
  261. LM_ERR("invalid Call-ID parameter\n");
  262. return -1;
  263. }
  264. if(fixup_get_svalue(msg, (gparam_p)ft, &sf)!=0)
  265. {
  266. LM_ERR("unable to get From tag\n");
  267. return -1;
  268. }
  269. if(sf.s==NULL || sf.len == 0)
  270. {
  271. LM_ERR("invalid From tag parameter\n");
  272. return -1;
  273. }
  274. if(fixup_get_svalue(msg, (gparam_p)tt, &st)!=0)
  275. {
  276. LM_ERR("unable to get To Tag\n");
  277. return -1;
  278. }
  279. if(st.s==NULL || st.len == 0)
  280. {
  281. LM_ERR("invalid To tag parameter\n");
  282. return -1;
  283. }
  284. dlg = get_dlg(&sc, &sf, &st, &dir);
  285. if(dlg==NULL)
  286. return -1;
  287. /*
  288. note: we should unref the dlg here (from get_dlg). BUT, because we are setting the current dialog
  289. we can ignore the unref... instead of unreffing and reffing again for the set_current_dialog. NB.
  290. this function is generally called from the cfg file. If used via API, remember to unref the dlg
  291. afterwards
  292. */
  293. set_current_dialog(msg, dlg);
  294. _dlg_ctx.dlg = dlg;
  295. _dlg_ctx.dir = dir;
  296. return 1;
  297. }
  298. int load_dlg(struct dlg_binds *dlgb) {
  299. dlgb->register_dlgcb = register_dlgcb;
  300. dlgb->register_dlgcb_nodlg = register_dlgcb_nodlg;
  301. dlgb->set_dlg_var = api_set_dlg_variable;
  302. dlgb->get_dlg_var = api_get_dlg_variable;
  303. dlgb->terminate_dlg = w_api_terminate_dlg;
  304. dlgb->lookup_terminate_dlg = w_api_lookup_terminate_dlg;
  305. dlgb->get_dlg_expires = api_get_dlg_expires;
  306. dlgb->get_dlg = dlg_get_msg_dialog;
  307. return 1;
  308. }
  309. static int mod_init(void) {
  310. unsigned int n;
  311. if (register_mi_mod(exports.name, mi_cmds) != 0) {
  312. LM_ERR("failed to register MI commands\n");
  313. return -1;
  314. }
  315. if (rpc_register_array(rpc_methods) != 0) {
  316. LM_ERR("failed to register RPC commands\n");
  317. return -1;
  318. }
  319. if (faked_msg_init() < 0)
  320. return -1;
  321. if (timeout_spec.s)
  322. timeout_spec.len = strlen(timeout_spec.s);
  323. dlg_bridge_controller.len = strlen(dlg_bridge_controller.s);
  324. /* param checkings */
  325. if (dlg_flag == -1) {
  326. LM_ERR("no dlg flag set!!\n");
  327. return -1;
  328. } else if (dlg_flag > MAX_FLAG) {
  329. LM_ERR("invalid dlg flag %d!!\n", dlg_flag);
  330. return -1;
  331. }
  332. if (rr_param == 0 || rr_param[0] == 0) {
  333. LM_ERR("empty rr_param!!\n");
  334. return -1;
  335. } else if (strlen(rr_param) > MAX_DLG_RR_PARAM_NAME) {
  336. LM_ERR("rr_param too long (max=%d)!!\n", MAX_DLG_RR_PARAM_NAME);
  337. return -1;
  338. }
  339. if (timeout_spec.s) {
  340. if (pv_parse_spec(&timeout_spec, &timeout_avp) == 0
  341. && (timeout_avp.type != PVT_AVP)) {
  342. LM_ERR("malformed or non AVP timeout "
  343. "AVP definition in '%.*s'\n", timeout_spec.len, timeout_spec.s);
  344. return -1;
  345. }
  346. }
  347. if (default_timeout <= 0) {
  348. LM_ERR("0 default_timeout not accepted!!\n");
  349. return -1;
  350. }
  351. if (ruri_pvar_param.s == NULL || *ruri_pvar_param.s == '\0') {
  352. LM_ERR("invalid r-uri PV string\n");
  353. return -1;
  354. }
  355. ruri_pvar_param.len = strlen(ruri_pvar_param.s);
  356. if (pv_parse_format(&ruri_pvar_param, &ruri_param_model) < 0
  357. || ruri_param_model == NULL) {
  358. LM_ERR("malformed r-uri PV string: %s\n", ruri_pvar_param.s);
  359. return -1;
  360. }
  361. /* update the len of the extra headers */
  362. if (dlg_extra_hdrs.s)
  363. dlg_extra_hdrs.len = strlen(dlg_extra_hdrs.s);
  364. if (seq_match_mode != SEQ_MATCH_NO_ID &&
  365. seq_match_mode != SEQ_MATCH_FALLBACK &&
  366. seq_match_mode != SEQ_MATCH_STRICT_ID) {
  367. LM_ERR("invalid value %d for seq_match_mode param!!\n", seq_match_mode);
  368. return -1;
  369. }
  370. if (detect_spirals != 0 && detect_spirals != 1) {
  371. LM_ERR("invalid value %d for detect_spirals param!!\n", detect_spirals);
  372. return -1;
  373. }
  374. /* create profile hashes */
  375. if (add_profile_definitions(profiles_nv_s, 0) != 0) {
  376. LM_ERR("failed to add profiles without value\n");
  377. return -1;
  378. }
  379. if (add_profile_definitions(profiles_wv_s, 1) != 0) {
  380. LM_ERR("failed to add profiles with value\n");
  381. return -1;
  382. }
  383. /* load the TM API */
  384. if (load_tm_api(&d_tmb) != 0) {
  385. LM_ERR("can't load TM API\n");
  386. return -1;
  387. }
  388. /* load RR API also */
  389. if (load_rr_api(&d_rrb) != 0) {
  390. LM_ERR("can't load RR API\n");
  391. return -1;
  392. }
  393. /* register callbacks*/
  394. /* listen for all incoming requests */
  395. if (d_tmb.register_tmcb(0, 0, TMCB_REQUEST_IN, dlg_onreq, 0, 0) <= 0) {
  396. LM_ERR("cannot register TMCB_REQUEST_IN callback\n");
  397. return -1;
  398. }
  399. /* listen for all routed requests */
  400. if (d_rrb.register_rrcb(dlg_onroute, 0) < 0) {
  401. LM_ERR("cannot register RR callback\n");
  402. return -1;
  403. }
  404. if (register_script_cb(profile_cleanup, POST_SCRIPT_CB | REQUEST_CB, 0) < 0) {
  405. LM_ERR("cannot regsiter script callback");
  406. return -1;
  407. }
  408. if (register_script_cb(dlg_cfg_cb,
  409. PRE_SCRIPT_CB | REQUEST_CB, 0) < 0) {
  410. LM_ERR("cannot regsiter pre-script ctx callback\n");
  411. return -1;
  412. }
  413. if (register_script_cb(dlg_cfg_cb,
  414. POST_SCRIPT_CB | REQUEST_CB, 0) < 0) {
  415. LM_ERR("cannot regsiter post-script ctx callback\n");
  416. return -1;
  417. }
  418. if (register_script_cb(spiral_detect_reset, POST_SCRIPT_CB | REQUEST_CB, 0) < 0) {
  419. LM_ERR("cannot register req pre-script spiral detection reset callback\n");
  420. return -1;
  421. }
  422. if (register_timer(dlg_timer_routine, 0, 1) < 0) {
  423. LM_ERR("failed to register timer \n");
  424. return -1;
  425. }
  426. /*for testing only!!!! setup timer to call print all dlg every 10 seconds!*/
  427. if (register_timer(print_all_dlgs, 0, 10) < 0) {
  428. LM_ERR("failed to register timer \n");
  429. return -1;
  430. }
  431. /* init handlers */
  432. init_dlg_handlers(rr_param, dlg_flag,
  433. timeout_spec.s ? &timeout_avp : 0, default_timeout, seq_match_mode);
  434. /* init timer */
  435. if (init_dlg_timer(dlg_ontimeout) != 0) {
  436. LM_ERR("cannot init timer list\n");
  437. return -1;
  438. }
  439. /* sanitize dlg_hash_zie */
  440. if (dlg_hash_size < 1) {
  441. LM_WARN("hash_size is smaller "
  442. "then 1 -> rounding from %d to 1\n",
  443. dlg_hash_size);
  444. dlg_hash_size = 1;
  445. }
  446. /* initialized the hash table */
  447. for (n = 0; n < (8 * sizeof (n)); n++) {
  448. if (dlg_hash_size == (1 << n))
  449. break;
  450. if (n && dlg_hash_size < (1 << n)) {
  451. LM_WARN("hash_size is not a power "
  452. "of 2 as it should be -> rounding from %d to %d\n",
  453. dlg_hash_size, 1 << (n - 1));
  454. dlg_hash_size = 1 << (n - 1);
  455. }
  456. }
  457. if (init_dlg_table(dlg_hash_size) < 0) {
  458. LM_ERR("failed to create hash table\n");
  459. return -1;
  460. }
  461. /* if a database should be used to store the dialogs' information */
  462. dlg_db_mode = dlg_db_mode_param;
  463. if (dlg_db_mode==DB_MODE_NONE) {
  464. db_url.s = 0; db_url.len = 0;
  465. } else {
  466. if (dlg_db_mode!=DB_MODE_REALTIME &&
  467. dlg_db_mode!=DB_MODE_DELAYED && dlg_db_mode!=DB_MODE_SHUTDOWN ) {
  468. LM_ERR("unsupported db_mode %d\n", dlg_db_mode);
  469. return -1;
  470. }
  471. if ( !db_url.s || db_url.len==0 ) {
  472. LM_ERR("db_url not configured for db_mode %d\n", dlg_db_mode);
  473. return -1;
  474. }
  475. if (init_dlg_db(&db_url, dlg_hash_size, db_update_period, db_fetch_rows)!=0) {
  476. LM_ERR("failed to initialize the DB support\n");
  477. return -1;
  478. }
  479. run_load_callbacks();
  480. }
  481. destroy_dlg_callbacks(DLGCB_LOADED);
  482. return 0;
  483. }
  484. static int child_init(int rank) {
  485. dlg_db_mode = dlg_db_mode_param;
  486. if ( ((dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
  487. (rank>0 || rank==PROC_TIMER)) ||
  488. (dlg_db_mode==DB_MODE_SHUTDOWN && (rank==PROC_MAIN)) ) {
  489. if ( dlg_connect_db(&db_url) ) {
  490. LM_ERR("failed to connect to database (rank=%d)\n",rank);
  491. return -1;
  492. }
  493. }
  494. /* in DB_MODE_SHUTDOWN only PROC_MAIN will do a DB dump at the end, so
  495. * for the rest of the processes will be the same as DB_MODE_NONE */
  496. if (dlg_db_mode==DB_MODE_SHUTDOWN && rank!=PROC_MAIN)
  497. dlg_db_mode = DB_MODE_NONE;
  498. /* in DB_MODE_REALTIME and DB_MODE_DELAYED the PROC_MAIN have no DB handle */
  499. if ( (dlg_db_mode==DB_MODE_REALTIME || dlg_db_mode==DB_MODE_DELAYED) &&
  500. rank==PROC_MAIN)
  501. dlg_db_mode = DB_MODE_NONE;
  502. return 0;
  503. }
  504. static void mod_destroy(void) {
  505. if(dlg_db_mode == DB_MODE_DELAYED || dlg_db_mode == DB_MODE_SHUTDOWN) {
  506. dialog_update_db(0, 0);
  507. destroy_dlg_db();
  508. }
  509. destroy_dlg_table();
  510. destroy_dlg_timer();
  511. destroy_dlg_callbacks(DLGCB_CREATED | DLGCB_LOADED);
  512. destroy_dlg_handlers();
  513. destroy_dlg_profiles();
  514. }
  515. static int w_set_dlg_profile(struct sip_msg *msg, char *profile, char *value) {
  516. pv_elem_t *pve;
  517. str val_s;
  518. pve = (pv_elem_t *) value;
  519. if (((struct dlg_profile_table*) profile)->has_value) {
  520. if (pve == NULL || pv_printf_s(msg, pve, &val_s) != 0 ||
  521. val_s.len == 0 || val_s.s == NULL) {
  522. LM_WARN("cannot get string for value\n");
  523. return -1;
  524. }
  525. if (set_dlg_profile(msg, &val_s,
  526. (struct dlg_profile_table*) profile) < 0) {
  527. LM_ERR("failed to set profile");
  528. return -1;
  529. }
  530. } else {
  531. if (set_dlg_profile(msg, NULL,
  532. (struct dlg_profile_table*) profile) < 0) {
  533. LM_ERR("failed to set profile");
  534. return -1;
  535. }
  536. }
  537. return 1;
  538. }
  539. static int w_unset_dlg_profile(struct sip_msg *msg, char *profile, char *value) {
  540. pv_elem_t *pve;
  541. str val_s;
  542. pve = (pv_elem_t *) value;
  543. if (((struct dlg_profile_table*) profile)->has_value) {
  544. if (pve == NULL || pv_printf_s(msg, pve, &val_s) != 0 ||
  545. val_s.len == 0 || val_s.s == NULL) {
  546. LM_WARN("cannot get string for value\n");
  547. return -1;
  548. }
  549. if (unset_dlg_profile(msg, &val_s,
  550. (struct dlg_profile_table*) profile) < 0) {
  551. LM_ERR("failed to unset profile");
  552. return -1;
  553. }
  554. } else {
  555. if (unset_dlg_profile(msg, NULL,
  556. (struct dlg_profile_table*) profile) < 0) {
  557. LM_ERR("failed to unset profile");
  558. return -1;
  559. }
  560. }
  561. return 1;
  562. }
  563. static int w_is_in_profile(struct sip_msg *msg, char *profile, char *value) {
  564. pv_elem_t *pve;
  565. str val_s;
  566. pve = (pv_elem_t *) value;
  567. if (pve != NULL && ((struct dlg_profile_table*) profile)->has_value) {
  568. if (pv_printf_s(msg, pve, &val_s) != 0 ||
  569. val_s.len == 0 || val_s.s == NULL) {
  570. LM_WARN("cannot get string for value\n");
  571. return -1;
  572. }
  573. return is_dlg_in_profile(msg, (struct dlg_profile_table*) profile,
  574. &val_s);
  575. } else {
  576. return is_dlg_in_profile(msg, (struct dlg_profile_table*) profile,
  577. NULL);
  578. }
  579. }
  580. /**
  581. * get dynamic name profile size
  582. */
  583. static int w_get_profile_size3(struct sip_msg *msg, char *profile,
  584. char *value, char *result) {
  585. pv_elem_t *pve;
  586. str val_s;
  587. pv_spec_t *sp_dest;
  588. unsigned int size;
  589. pv_value_t val;
  590. if (result != NULL) {
  591. pve = (pv_elem_t *) value;
  592. sp_dest = (pv_spec_t *) result;
  593. } else {
  594. pve = NULL;
  595. sp_dest = (pv_spec_t *) value;
  596. }
  597. if (pve != NULL && ((struct dlg_profile_table*) profile)->has_value) {
  598. if (pv_printf_s(msg, pve, &val_s) != 0 ||
  599. val_s.len == 0 || val_s.s == NULL) {
  600. LM_WARN("cannot get string for value\n");
  601. return -1;
  602. }
  603. size = get_profile_size((struct dlg_profile_table*) profile, &val_s);
  604. } else {
  605. size = get_profile_size((struct dlg_profile_table*) profile, NULL);
  606. }
  607. memset(&val, 0, sizeof (pv_value_t));
  608. val.flags = PV_VAL_INT | PV_TYPE_INT;
  609. val.ri = (int) size;
  610. if (sp_dest->setf(msg, &sp_dest->pvp, (int) EQ_T, &val) < 0) {
  611. LM_ERR("setting profile PV failed\n");
  612. return -1;
  613. }
  614. return 1;
  615. }
  616. /**
  617. * get static name profile size
  618. */
  619. static int w_get_profile_size2(struct sip_msg *msg, char *profile, char *result) {
  620. return w_get_profile_size3(msg, profile, result, NULL);
  621. }
  622. static int w_dlg_setflag(struct sip_msg *msg, char *flag, char *s2) {
  623. dlg_ctx_t *dctx;
  624. int val;
  625. if (fixup_get_ivalue(msg, (gparam_p) flag, &val) != 0) {
  626. LM_ERR("no flag value\n");
  627. return -1;
  628. }
  629. if (val < 0 || val > 31)
  630. return -1;
  631. if ((dctx = dlg_get_dlg_ctx()) == NULL)
  632. return -1;
  633. dctx->flags |= 1 << val;
  634. if (dctx->dlg)
  635. dctx->dlg->sflags |= 1 << val;
  636. return 1;
  637. }
  638. static int w_dlg_resetflag(struct sip_msg *msg, char *flag, str *s2) {
  639. dlg_ctx_t *dctx;
  640. int val;
  641. if (fixup_get_ivalue(msg, (gparam_p) flag, &val) != 0) {
  642. LM_ERR("no flag value\n");
  643. return -1;
  644. }
  645. if (val < 0 || val > 31)
  646. return -1;
  647. if ((dctx = dlg_get_dlg_ctx()) == NULL)
  648. return -1;
  649. dctx->flags &= ~(1 << val);
  650. if (dctx->dlg)
  651. dctx->dlg->sflags &= ~(1 << val);
  652. return 1;
  653. }
  654. static int w_dlg_isflagset(struct sip_msg *msg, char *flag, str *s2) {
  655. dlg_ctx_t *dctx;
  656. int val;
  657. if (fixup_get_ivalue(msg, (gparam_p) flag, &val) != 0) {
  658. LM_ERR("no flag value\n");
  659. return -1;
  660. }
  661. if (val < 0 || val > 31)
  662. return -1;
  663. if ((dctx = dlg_get_dlg_ctx()) == NULL)
  664. return -1;
  665. if (dctx->dlg)
  666. return (dctx->dlg->sflags & (1 << val)) ? 1 : -1;
  667. return (dctx->flags & (1 << val)) ? 1 : -1;
  668. }
  669. static int w_dlg_terminate(struct sip_msg *msg, char *side, char *r) {
  670. struct dlg_cell *dlg;
  671. str reason = {0, 0};
  672. int n = (int) (long) side;
  673. //check if a reason was given
  674. if (r) {
  675. if (get_str_fparam(&reason, msg, (fparam_t *) r) < 0) {
  676. LM_ERR("failed to recover reason parameter\n");
  677. return -1;
  678. }
  679. }
  680. dlg = get_current_dialog(msg);
  681. //dlg_get_ctx_dialog();
  682. if (!dlg) {
  683. LM_DBG("Unable to find dialog for terminate\n");
  684. return -1;
  685. }
  686. if (!dlg_terminate(dlg, msg, &reason, n, NULL)) {
  687. LM_DBG("Failed to terminate dialog\n");
  688. return -1;
  689. }
  690. return 1;
  691. }
  692. /*
  693. * Wrapper around is_known_dlg().
  694. */
  695. static int w_is_known_dlg(struct sip_msg *msg) {
  696. return is_known_dlg(msg);
  697. }
  698. /**************************** RPC functions ******************************/
  699. /*!
  700. * \brief Helper method that outputs a dialog via the RPC interface
  701. * \see rpc_print_dlg
  702. * \param rpc RPC node that should be filled
  703. * \param c RPC void pointer
  704. * \param dlg printed dialog
  705. * \param with_context if 1 then the dialog context will be also printed
  706. * \return 0 on success, -1 on failure
  707. */
  708. static inline void internal_rpc_print_dlg(rpc_t *rpc, void *c, struct dlg_cell *dlg, void *dh)
  709. {
  710. void* dlg_outs_h;
  711. struct dlg_cell_out* dlg_out;
  712. rpc->struct_add(dh, "dd", "Entry", dlg->h_entry, "Id", dlg->h_id);
  713. rpc->struct_add(dh, "SSSSSSSsd{",
  714. "RURI", &dlg->req_uri,
  715. "From", &dlg->from_uri,
  716. "Call-ID", &dlg->callid,
  717. "Caller Contact", &dlg->caller_contact,
  718. "Caller Route Set", &dlg->caller_route_set,
  719. "Dialog-ID", &dlg->did,
  720. "From Tag", &dlg->from_tag,
  721. "State", state_to_char(dlg->state),
  722. "Ref", dlg->ref,
  723. "dlg_outs", &dlg_outs_h
  724. );
  725. lock_get(dlg->dlg_out_entries_lock);
  726. dlg_out = dlg->dlg_entry_out.first;
  727. while (dlg_out) {
  728. rpc->struct_add(dlg_outs_h, "dd", "Entry", dlg_out->h_entry, "Id", dlg_out->h_id);
  729. dlg_out = dlg_out->next;
  730. }
  731. lock_release(dlg->dlg_out_entries_lock);
  732. /*now traverse dlg_outs*/
  733. }
  734. /*!
  735. * \brief Helper function that outputs all dialogs via the RPC interface
  736. * \see rpc_print_dlgs
  737. * \param rpc RPC node that should be filled
  738. * \param c RPC void pointer
  739. * \param with_context if 1 then the dialog context will be also printed
  740. */
  741. static void internal_rpc_print_dlgs(rpc_t *rpc, void *c)
  742. {
  743. struct dlg_cell *dlg;
  744. unsigned int i;
  745. void *ah;
  746. void *dh; /*beginning struct holding dialogs*/
  747. if (rpc->add(c, "{", &ah) < 0) {
  748. rpc->fault(c, 500, "Internal error creating top rpc");
  749. return;
  750. }
  751. if (rpc->struct_add(ah, "d{", "Size", (int) d_table->size, "Dialogs", &dh) < 0) {
  752. rpc->fault(c, 500, "Internal error creating inner struct");
  753. return;
  754. }
  755. for( i=0 ; i<d_table->size ; i++ ) {
  756. dlg_lock( d_table, &(d_table->entries[i]) );
  757. for( dlg=d_table->entries[i].first ; dlg ; dlg=dlg->next ) {
  758. internal_rpc_print_dlg(rpc, c, dlg, dh);
  759. }
  760. dlg_unlock( d_table, &(d_table->entries[i]) );
  761. }
  762. }
  763. static const char *rpc_print_dlgs_doc[2] = {
  764. "Print all dialogs", 0
  765. };
  766. static void rpc_print_dlgs(rpc_t *rpc, void *c) {
  767. internal_rpc_print_dlgs(rpc, c);
  768. }
  769. /*static const char *rpc_end_dlg_entry_id_doc[2] = {
  770. "End a given dialog based on [h_entry] [h_id]", 0
  771. };
  772. static void rpc_end_dlg_entry_id(rpc_t *rpc, void *c) {
  773. unsigned int h_entry, h_id;
  774. struct dlg_cell * dlg = NULL;
  775. str rpc_extra_hdrs = {NULL, 0};
  776. if (rpc->scan(c, "ddS", &h_entry, &h_id, &rpc_extra_hdrs) < 2) return;
  777. dlg = lookup_dlg(h_entry, h_id);
  778. if (dlg) {
  779. //dlg_bye_all(dlg, (rpc_extra_hdrs.len>0)?&rpc_extra_hdrs:NULL);
  780. unref_dlg(dlg, 1);
  781. }
  782. }*/
  783. static rpc_export_t rpc_methods[] = {
  784. {"dlg2.list", rpc_print_dlgs, rpc_print_dlgs_doc, 0},
  785. //{"dlg.end_dlg", rpc_end_dlg_entry_id, rpc_end_dlg_entry_id_doc, 0},
  786. {0, 0, 0, 0}
  787. };