utils.c 14 KB

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