utils.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * utils Module
  3. *
  4. * Copyright (C) 2008 Juha Heinanen
  5. * Copyright (C) 2009 1&1 Internet AG
  6. *
  7. * This file is part of Kamailio, a free SIP server.
  8. *
  9. * Kamailio is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version
  13. *
  14. * Kamailio is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22. *
  23. * History:
  24. * -------
  25. * 2008-11-24: Introduced utils module and its first function: http_query.
  26. *
  27. */
  28. /*! \file
  29. * \brief SIP-router utils :: Module core
  30. * \ingroup utils
  31. */
  32. /*! \defgroup Utils SIP-router :: Various utilities
  33. *
  34. */
  35. #include <curl/curl.h>
  36. #include "../../mod_fix.h"
  37. #include "../../sr_module.h"
  38. #include "../../ut.h"
  39. #include "../../forward.h"
  40. #include "../../resolve.h"
  41. #include "../../locking.h"
  42. #include "../../script_cb.h"
  43. #include "../../mem/shm_mem.h"
  44. #include "../../lib/srdb1/db.h"
  45. #include "functions.h"
  46. #include "conf.h"
  47. #include "xcap_auth.h"
  48. MODULE_VERSION
  49. #define XCAP_TABLE_VERSION 3
  50. /* Module parameter variables */
  51. int http_query_timeout = 4;
  52. static int forward_active = 0;
  53. static int mp_max_id = 0;
  54. static char* mp_switch = "";
  55. static char* mp_filter = "";
  56. static char* mp_proxy = "";
  57. str xcap_table= str_init("xcap");
  58. str pres_db_url = {0, 0};
  59. /* lock for configuration access */
  60. static gen_lock_t *conf_lock = NULL;
  61. /* FIFO interface functions */
  62. static struct mi_root* forward_fifo_list(struct mi_root* cmd_tree, void *param);
  63. static struct mi_root* forward_fifo_switch(struct mi_root* cmd_tree, void* param);
  64. static struct mi_root* forward_fifo_filter(struct mi_root* cmd_tree, void* param);
  65. static struct mi_root* forward_fifo_proxy(struct mi_root* cmd_tree, void* param);
  66. /* Database connection */
  67. db1_con_t *pres_dbh = NULL;
  68. db_func_t pres_dbf;
  69. /* Module management function prototypes */
  70. static int mod_init(void);
  71. static int child_init(int);
  72. static void destroy(void);
  73. /* Fixup functions to be defined later */
  74. static int fixup_http_query(void** param, int param_no);
  75. static int fixup_free_http_query(void** param, int param_no);
  76. /* forward function */
  77. int utils_forward(struct sip_msg *msg, int id, int proto);
  78. /* Exported functions */
  79. static cmd_export_t cmds[] = {
  80. {"http_query", (cmd_function)http_query, 2, fixup_http_query,
  81. fixup_free_http_query,
  82. REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
  83. {"xcap_auth_status", (cmd_function)xcap_auth_status, 2, fixup_pvar_pvar,
  84. fixup_free_pvar_pvar, REQUEST_ROUTE},
  85. {0, 0, 0, 0, 0, 0}
  86. };
  87. /* Exported parameters */
  88. static param_export_t params[] = {
  89. {"pres_db_url", STR_PARAM, &pres_db_url.s},
  90. {"xcap_table", STR_PARAM, &xcap_table.s},
  91. {"http_query_timeout", INT_PARAM, &http_query_timeout},
  92. {"forward_active", INT_PARAM, &forward_active},
  93. {0, 0, 0}
  94. };
  95. static mi_export_t mi_cmds[] = {
  96. { "forward_list", forward_fifo_list, MI_NO_INPUT_FLAG, 0, 0 },
  97. { "forward_switch", forward_fifo_switch, 0, 0, 0 },
  98. { "forward_filter", forward_fifo_filter, 0, 0, 0 },
  99. { "forward_proxy", forward_fifo_proxy, 0, 0, 0 },
  100. { 0, 0, 0, 0, 0}
  101. };
  102. /* Module interface */
  103. struct module_exports exports = {
  104. "utils",
  105. DEFAULT_DLFLAGS, /* dlopen flags */
  106. cmds, /* Exported functions */
  107. params, /* Exported parameters */
  108. 0, /* exported statistics */
  109. mi_cmds, /* exported MI functions */
  110. 0, /* exported pseudo-variables */
  111. 0, /* extra processes */
  112. mod_init, /* module initialization function */
  113. 0, /* response function*/
  114. destroy, /* destroy function */
  115. child_init /* per-child init function */
  116. };
  117. static int init_shmlock(void)
  118. {
  119. conf_lock = lock_alloc();
  120. if (conf_lock == NULL) {
  121. LM_CRIT("cannot allocate memory for lock.\n");
  122. return -1;
  123. }
  124. if (lock_init(conf_lock) == 0) {
  125. LM_CRIT("cannot initialize lock.\n");
  126. return -1;
  127. }
  128. return 0;
  129. }
  130. static int pre_script_filter(struct sip_msg *msg, unsigned int flags, void *unused)
  131. {
  132. /* use id 0 for pre script callback */
  133. utils_forward(msg, 0, PROTO_UDP);
  134. /* always return 1 so that routing skript is called for msg */
  135. return 1;
  136. }
  137. static void destroy_shmlock(void)
  138. {
  139. if (conf_lock) {
  140. lock_destroy(conf_lock);
  141. lock_dealloc((void *)conf_lock);
  142. conf_lock = NULL;
  143. }
  144. }
  145. static void pres_db_close(void) {
  146. if (pres_dbh) {
  147. pres_dbf.close(pres_dbh);
  148. pres_dbh = NULL;
  149. }
  150. }
  151. static int pres_db_init(void) {
  152. if (!pres_db_url.s || !pres_db_url.len) {
  153. LM_INFO("xcap_auth_status function is disabled\n");
  154. return 0;
  155. }
  156. if (db_bind_mod(&pres_db_url, &pres_dbf) < 0) {
  157. LM_ERR("can't bind database module\n");
  158. return -1;
  159. }
  160. if ((pres_dbh = pres_dbf.init(&pres_db_url)) == NULL) {
  161. LM_ERR("can't connect to database\n");
  162. return -1;
  163. }
  164. if (db_check_table_version(&pres_dbf, pres_dbh, &xcap_table,
  165. XCAP_TABLE_VERSION) < 0) {
  166. LM_ERR("during table version check\n");
  167. pres_db_close();
  168. return -1;
  169. }
  170. pres_db_close();
  171. return 0;
  172. }
  173. static int pres_db_open(void) {
  174. if (!pres_db_url.s || !pres_db_url.len) {
  175. return 0;
  176. }
  177. if (pres_dbh) {
  178. pres_dbf.close(pres_dbh);
  179. }
  180. if ((pres_dbh = pres_dbf.init(&pres_db_url)) == NULL) {
  181. LM_ERR("can't connect to database\n");
  182. return -1;
  183. }
  184. if (pres_dbf.use_table(pres_dbh, &xcap_table) < 0) {
  185. LM_ERR("in use_table: %.*s\n", xcap_table.len, xcap_table.s);
  186. return -1;
  187. }
  188. return 0;
  189. }
  190. /* Module initialization function */
  191. static int mod_init(void)
  192. {
  193. if(register_mi_mod(exports.name, mi_cmds)!=0)
  194. {
  195. LM_ERR("failed to register MI commands\n");
  196. return -1;
  197. }
  198. /* Initialize curl */
  199. if (curl_global_init(CURL_GLOBAL_ALL)) {
  200. LM_ERR("curl_global_init failed\n");
  201. return -1;
  202. }
  203. if (init_shmlock() != 0) {
  204. LM_CRIT("cannot initialize shmlock.\n");
  205. return -1;
  206. }
  207. if (conf_init(mp_max_id) < 0) {
  208. LM_CRIT("cannot initialize configuration.\n");
  209. return -1;
  210. }
  211. /* read module parameters and update configuration structure */
  212. if (conf_parse_proxy(mp_proxy) < 0) {
  213. LM_CRIT("cannot parse proxy module parameter.\n");
  214. return -1;
  215. }
  216. if (conf_parse_filter(mp_filter) < 0) {
  217. LM_CRIT("cannot parse filter module parameter.\n");
  218. return -1;
  219. }
  220. if (conf_parse_switch(mp_switch) < 0) {
  221. LM_CRIT("cannot parse switch module parameter.\n");
  222. return -1;
  223. }
  224. if (forward_active == 1) {
  225. /* register callback for id 0 */
  226. if (register_script_cb(pre_script_filter, PRE_SCRIPT_CB|ONREPLY_CB, 0) < 0) {
  227. LM_CRIT("cannot register script callback for requests.\n");
  228. return -1;
  229. }
  230. if (register_script_cb(pre_script_filter, PRE_SCRIPT_CB|ONREPLY_CB, 0) < 0) {
  231. LM_CRIT("cannot register script callback for replies.\n");
  232. return -1;
  233. }
  234. } else {
  235. LM_INFO("forward functionality disabled");
  236. }
  237. /* presence database */
  238. pres_db_url.len = pres_db_url.s ? strlen(pres_db_url.s) : 0;
  239. LM_DBG("pres_db_url=%s/%d/%p\n", ZSW(pres_db_url.s), pres_db_url.len,
  240. pres_db_url.s);
  241. xcap_table.len = xcap_table.s ? strlen(xcap_table.s) : 0;
  242. if(pres_db_init() < 0) {
  243. return -1;
  244. }
  245. return 0;
  246. }
  247. /* Child initialization function */
  248. static int child_init(int rank)
  249. {
  250. if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
  251. return 0; /* do nothing for the main process */
  252. return pres_db_open();
  253. }
  254. static void destroy(void)
  255. {
  256. /* Cleanup curl */
  257. curl_global_cleanup();
  258. /* Cleanup forward */
  259. conf_destroy();
  260. destroy_shmlock();
  261. /* Close pres db */
  262. pres_db_close();
  263. }
  264. /* Fixup functions */
  265. /*
  266. * Fix http_query params: url (string that may contain pvars) and
  267. * result (writable pvar).
  268. */
  269. static int fixup_http_query(void** param, int param_no)
  270. {
  271. if (param_no == 1) {
  272. return fixup_spve_null(param, 1);
  273. }
  274. if (param_no == 2) {
  275. if (fixup_pvar_null(param, 1) != 0) {
  276. LM_ERR("failed to fixup result pvar\n");
  277. return -1;
  278. }
  279. if (((pv_spec_t *)(*param))->setf == NULL) {
  280. LM_ERR("result pvar is not writeble\n");
  281. return -1;
  282. }
  283. return 0;
  284. }
  285. LM_ERR("invalid parameter number <%d>\n", param_no);
  286. return -1;
  287. }
  288. /*
  289. * Free http_query params.
  290. */
  291. static int fixup_free_http_query(void** param, int param_no)
  292. {
  293. if (param_no == 1) {
  294. LM_WARN("free function has not been defined for spve\n");
  295. return 0;
  296. }
  297. if (param_no == 2) {
  298. return fixup_free_pvar_null(param, 1);
  299. }
  300. LM_ERR("invalid parameter number <%d>\n", param_no);
  301. return -1;
  302. }
  303. /*!
  304. * \brief checks precondition, switch, filter and forwards msg if necessary
  305. * \param msg the message to be forwarded
  306. * \param id use configuration with this ID when checking switch, filter, proxy.
  307. * \param proto protocol to be used. Should be PROTO_UDP.
  308. * \return 0 on success, -1 otherwise
  309. */
  310. int utils_forward(struct sip_msg *msg, int id, int proto)
  311. {
  312. int ret = -1;
  313. struct dest_info dst;
  314. init_dest_info(&dst);
  315. dst.proto = proto;
  316. // critical section start:
  317. // avoids dirty reads when updating configuration.
  318. lock_get(conf_lock);
  319. struct proxy_l *proxy = conf_needs_forward(msg, id);
  320. if (proxy != NULL) {
  321. proxy2su(&dst.to, proxy);
  322. if (forward_request(msg, NULL, 0, &dst) < 0){
  323. LM_ERR("could not forward message\n");
  324. }
  325. ret = 0;
  326. }
  327. // critical section end
  328. lock_release(conf_lock);
  329. return ret;
  330. }
  331. /* FIFO functions */
  332. /*!
  333. * \brief fifo command for listing configuration
  334. * \return pointer to the mi_root on success, 0 otherwise
  335. */
  336. static struct mi_root* forward_fifo_list(struct mi_root* cmd_tree, void *param)
  337. {
  338. struct mi_node *node = NULL;
  339. struct mi_root * ret = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
  340. if(ret == NULL)
  341. return 0;
  342. node = addf_mi_node_child( &ret->node, 0, 0, 0, "Printing forwarding information:");
  343. if(node == NULL)
  344. goto error;
  345. // critical section start:
  346. // avoids dirty reads when updating configuration.
  347. lock_get(conf_lock);
  348. conf_show(ret);
  349. // critical section end
  350. lock_release(conf_lock);
  351. return ret;
  352. error:
  353. free_mi_tree(ret);
  354. return 0;
  355. }
  356. /*!
  357. * \brief fifo command for configuring switch
  358. * \return pointer to the mi_root on success, 0 otherwise
  359. */
  360. static struct mi_root* forward_fifo_switch(struct mi_root* cmd_tree, void* param)
  361. {
  362. struct mi_node *node = NULL;
  363. int result;
  364. node = cmd_tree->node.kids;
  365. if (node==NULL || node->next!=NULL || node->value.s==NULL)
  366. return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
  367. // critical section start:
  368. // avoids dirty reads when updating configuration.
  369. lock_get(conf_lock);
  370. result = conf_parse_switch(node->value.s);
  371. // critical section end
  372. lock_release(conf_lock);
  373. if (result < 0) {
  374. LM_ERR("cannot parse parameter\n");
  375. return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
  376. }
  377. return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
  378. }
  379. /*!
  380. * \brief fifo command for configuring filter
  381. * \return pointer to the mi_root on success, 0 otherwise
  382. */
  383. static struct mi_root* forward_fifo_filter(struct mi_root* cmd_tree, void* param)
  384. {
  385. struct mi_node *node = NULL;
  386. int result;
  387. node = cmd_tree->node.kids;
  388. if (node==NULL || node->next!=NULL || node->value.s==NULL)
  389. return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
  390. // critical section start:
  391. // avoids dirty reads when updating configuration.
  392. lock_get(conf_lock);
  393. result = conf_parse_filter(node->value.s);
  394. // critical section end
  395. lock_release(conf_lock);
  396. if (result < 0) {
  397. LM_ERR("cannot parse parameter\n");
  398. return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
  399. }
  400. return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
  401. }
  402. /*!
  403. * \brief fifo command for configuring proxy
  404. * \return pointer to the mi_root on success, 0 otherwise
  405. */
  406. static struct mi_root* forward_fifo_proxy(struct mi_root* cmd_tree, void* param)
  407. {
  408. struct mi_node *node = NULL;
  409. int result;
  410. node = cmd_tree->node.kids;
  411. if (node==NULL || node->next!=NULL || node->value.s==NULL)
  412. return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
  413. // critical section start:
  414. // avoids dirty reads when updating configuration.
  415. lock_get(conf_lock);
  416. result = conf_parse_proxy(node->value.s);
  417. // critical section end
  418. lock_release(conf_lock);
  419. if (result < 0) {
  420. LM_ERR("cannot parse parameter\n");
  421. return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
  422. }
  423. return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
  424. }