utils.c 12 KB

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