xcap_functions.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * $Id: xcap_functions.c 2230 2007-06-06 07:13:20Z anca_vamanu $
  3. *
  4. * xcap_client module - XCAP client for Kamailio
  5. *
  6. * Copyright (C) 2007 Voice Sistem S.R.L.
  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. * 2007-08-20 initial version (anca)
  27. */
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <sys/types.h>
  32. #include <sys/ipc.h>
  33. #include <unistd.h>
  34. #include <fcntl.h>
  35. #include <time.h>
  36. #include <curl/curl.h>
  37. #include "../../mem/mem.h"
  38. #include "../../lib/srdb1/db.h"
  39. #include "xcap_functions.h"
  40. #include "xcap_client.h"
  41. #include "../presence/hash.h"
  42. #define ETAG_HDR "Etag: "
  43. #define ETAG_HDR_LEN strlen("Etag: ")
  44. size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream);
  45. char* get_xcap_path(xcap_get_req_t req);
  46. int bind_xcap(xcap_api_t* api)
  47. {
  48. if (!api)
  49. {
  50. LM_ERR("Invalid parameter value\n");
  51. return -1;
  52. }
  53. api->get_elem= xcapGetElem;
  54. api->int_node_sel= xcapInitNodeSel;
  55. api->add_step= xcapNodeSelAddStep;
  56. api->add_terminal= xcapNodeSelAddTerminal;
  57. api->free_node_sel= xcapFreeNodeSel;
  58. api->register_xcb= register_xcapcb;
  59. api->getNewDoc= xcapGetNewDoc;
  60. return 0;
  61. }
  62. void xcapFreeNodeSel(xcap_node_sel_t* node)
  63. {
  64. step_t* s, *p;
  65. ns_list_t* n, *m;
  66. s= node->steps;
  67. while(s)
  68. {
  69. p= s;
  70. s= s->next;
  71. pkg_free(p->val.s);
  72. pkg_free(p);
  73. }
  74. n= node->ns_list;
  75. while(n)
  76. {
  77. m= n;
  78. n= n->next;
  79. pkg_free(m->value.s);
  80. pkg_free(m);
  81. }
  82. pkg_free(node);
  83. }
  84. xcap_node_sel_t* xcapInitNodeSel(void)
  85. {
  86. xcap_node_sel_t* nsel= NULL;
  87. nsel= (xcap_node_sel_t*)pkg_malloc(sizeof(xcap_node_sel_t));
  88. if(nsel== NULL)
  89. {
  90. ERR_MEM(PKG_MEM_STR);
  91. }
  92. memset(nsel, 0, sizeof(xcap_node_sel_t));
  93. nsel->steps= (step_t*)pkg_malloc(sizeof(step_t));
  94. if(nsel->steps== NULL)
  95. {
  96. ERR_MEM(PKG_MEM_STR);
  97. }
  98. memset(nsel->steps, 0, sizeof(step_t));
  99. nsel->last_step= nsel->steps;
  100. nsel->ns_list= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
  101. if(nsel->ns_list== NULL)
  102. {
  103. ERR_MEM(PKG_MEM_STR);
  104. }
  105. memset(nsel->ns_list, 0, sizeof(ns_list_t));
  106. nsel->last_ns= nsel->ns_list;
  107. return nsel;
  108. error:
  109. if(nsel)
  110. {
  111. if(nsel->steps)
  112. pkg_free(nsel->steps);
  113. if(nsel->ns_list)
  114. pkg_free(nsel->ns_list);
  115. pkg_free(nsel);
  116. }
  117. return NULL;
  118. }
  119. xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name,
  120. str* namespace, int pos, attr_test_t* attr_test, str* extra_sel)
  121. {
  122. int size= 0;
  123. str new_step= {NULL, 0};
  124. step_t* s= NULL;
  125. char ns_card= 'a';
  126. ns_list_t* ns= NULL;
  127. if(name)
  128. size+= name->len;
  129. else
  130. size+= 1;
  131. if(namespace)
  132. size+= 2;
  133. if(pos> 0)
  134. size+= 7;
  135. if(attr_test)
  136. size+= 2+ attr_test->name.len+ attr_test->value.len;
  137. if(extra_sel)
  138. size+= 2+ extra_sel->len;
  139. new_step.s= (char*)pkg_malloc(size* sizeof(char));
  140. if(new_step.s== NULL)
  141. {
  142. ERR_MEM(PKG_MEM_STR);
  143. }
  144. if(name)
  145. {
  146. if(namespace)
  147. {
  148. ns_card= curr_sel->ns_no+ 'a';
  149. curr_sel->ns_no++;
  150. if(ns_card> 'z')
  151. {
  152. LM_ERR("Insuficient name cards for namespaces\n");
  153. goto error;
  154. }
  155. new_step.len= sprintf(new_step.s, "%c:", ns_card);
  156. }
  157. memcpy(new_step.s+new_step.len, name->s, name->len);
  158. new_step.len+= name->len;
  159. }
  160. else
  161. memcpy(new_step.s+new_step.len, "*", 1);
  162. if(attr_test)
  163. {
  164. new_step.len+= sprintf(new_step.s+ new_step.len, "[%.*s=%.*s]", attr_test->name.len,
  165. attr_test->name.s, attr_test->value.len, attr_test->value.s);
  166. }
  167. if(pos> 0)
  168. new_step.len+= sprintf(new_step.s+ new_step.len, "[%d]", pos);
  169. if(extra_sel)
  170. {
  171. memcpy(new_step.s+ new_step.len, extra_sel->s, extra_sel->len);
  172. new_step.len= extra_sel->len;
  173. }
  174. s= (step_t*)pkg_malloc(sizeof(step_t));
  175. if(s== NULL)
  176. {
  177. ERR_MEM(PKG_MEM_STR);
  178. }
  179. s->val= new_step;
  180. s->next= NULL;
  181. curr_sel->last_step->next= s;
  182. curr_sel->last_step= s;
  183. /* add the namespace binding if present */
  184. if(namespace)
  185. {
  186. ns= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
  187. if(ns== NULL)
  188. {
  189. ERR_MEM(PKG_MEM_STR);
  190. }
  191. ns->name= ns_card;
  192. ns->value.s= (char*)pkg_malloc(namespace->len* sizeof(char));
  193. if(ns->value.s== NULL)
  194. {
  195. ERR_MEM(PKG_MEM_STR);
  196. }
  197. memcpy(ns->value.s, namespace->s, namespace->len);
  198. ns->value.len= namespace->len;
  199. curr_sel->last_ns->next= ns;
  200. curr_sel->last_ns= ns;
  201. }
  202. curr_sel->size+= 1+ new_step.len;
  203. if(namespace->len)
  204. {
  205. curr_sel->size+= namespace->len+ 3;
  206. }
  207. return curr_sel;
  208. error:
  209. if(new_step.s)
  210. pkg_free(new_step.s);
  211. if(s)
  212. pkg_free(s);
  213. if(ns)
  214. {
  215. if(ns->value.s)
  216. pkg_free(ns->value.s);
  217. pkg_free(ns);
  218. }
  219. return NULL;
  220. }
  221. xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel,
  222. char* attr_sel, char* namespace_sel, char* extra_sel )
  223. {
  224. return NULL;
  225. }
  226. char* get_node_selector(xcap_node_sel_t* node_sel)
  227. {
  228. char* buf= NULL;
  229. step_t* s;
  230. int len= 0;
  231. ns_list_t* ns_elem;
  232. buf= (char*)pkg_malloc((node_sel->size+ 10)* sizeof(char));
  233. if(buf== NULL)
  234. {
  235. ERR_MEM(PKG_MEM_STR);
  236. }
  237. s= node_sel->steps->next;
  238. while(1)
  239. {
  240. memcpy(buf+ len, s->val.s, s->val.len);
  241. len+= s->val.len;
  242. s= s->next;
  243. if(s)
  244. buf[len++]= '/';
  245. else
  246. break;
  247. }
  248. ns_elem= node_sel->ns_list;
  249. if(ns_elem)
  250. buf[len++]= '?';
  251. while(ns_elem)
  252. {
  253. len+= sprintf(buf+ len, "xmlns(%c=%.*s)", ns_elem->name,
  254. ns_elem->value.len, ns_elem->value.s);
  255. ns_elem= ns_elem->next;
  256. }
  257. buf[len]= '\0';
  258. return buf;
  259. error:
  260. return NULL;
  261. }
  262. char* xcapGetNewDoc(xcap_get_req_t req, str user, str domain)
  263. {
  264. char* etag= NULL;
  265. char* doc= NULL;
  266. db_key_t query_cols[9];
  267. db_val_t query_vals[9];
  268. int n_query_cols = 0;
  269. char* path= NULL;
  270. path= get_xcap_path(req);
  271. if(path== NULL)
  272. {
  273. LM_ERR("while constructing xcap path\n");
  274. return NULL;
  275. }
  276. /* send HTTP request */
  277. doc= send_http_get(path, req.port, NULL, 0, &etag);
  278. if(doc== NULL)
  279. {
  280. LM_DBG("the searched document was not found\n");
  281. goto done;
  282. }
  283. if(etag== NULL)
  284. {
  285. LM_ERR("no etag found\n");
  286. pkg_free(doc);
  287. doc= NULL;
  288. goto done;
  289. }
  290. /* insert in xcap table*/
  291. query_cols[n_query_cols] = &str_username_col;
  292. query_vals[n_query_cols].type = DB1_STR;
  293. query_vals[n_query_cols].nul = 0;
  294. query_vals[n_query_cols].val.str_val = user;
  295. n_query_cols++;
  296. query_cols[n_query_cols] = &str_domain_col;
  297. query_vals[n_query_cols].type = DB1_STR;
  298. query_vals[n_query_cols].nul = 0;
  299. query_vals[n_query_cols].val.str_val = domain;
  300. n_query_cols++;
  301. query_cols[n_query_cols] = &str_doc_type_col;
  302. query_vals[n_query_cols].type = DB1_INT;
  303. query_vals[n_query_cols].nul = 0;
  304. query_vals[n_query_cols].val.int_val= req.doc_sel.doc_type;
  305. n_query_cols++;
  306. query_cols[n_query_cols] = &str_doc_col;
  307. query_vals[n_query_cols].type = DB1_STRING;
  308. query_vals[n_query_cols].nul = 0;
  309. query_vals[n_query_cols].val.string_val= doc;
  310. n_query_cols++;
  311. query_cols[n_query_cols] = &str_etag_col;
  312. query_vals[n_query_cols].type = DB1_STRING;
  313. query_vals[n_query_cols].nul = 0;
  314. query_vals[n_query_cols].val.string_val= etag;
  315. n_query_cols++;
  316. query_cols[n_query_cols] = &str_source_col;
  317. query_vals[n_query_cols].type = DB1_INT;
  318. query_vals[n_query_cols].nul = 0;
  319. query_vals[n_query_cols].val.int_val= XCAP_CL_MOD;
  320. n_query_cols++;
  321. query_cols[n_query_cols] = &str_doc_uri_col;
  322. query_vals[n_query_cols].type = DB1_STRING;
  323. query_vals[n_query_cols].nul = 0;
  324. query_vals[n_query_cols].val.string_val= path;
  325. n_query_cols++;
  326. query_cols[n_query_cols] = &str_port_col;
  327. query_vals[n_query_cols].type = DB1_INT;
  328. query_vals[n_query_cols].nul = 0;
  329. query_vals[n_query_cols].val.int_val= req.port;
  330. n_query_cols++;
  331. if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0)
  332. {
  333. LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s);
  334. goto done;
  335. }
  336. if(xcap_dbf.insert(xcap_db, query_cols, query_vals, n_query_cols)< 0)
  337. {
  338. LM_ERR("in sql insert\n");
  339. goto done;
  340. }
  341. done:
  342. pkg_free(path);
  343. return doc;
  344. }
  345. char* get_xcap_path(xcap_get_req_t req)
  346. {
  347. int len= 0, size;
  348. char* path= NULL;
  349. char* node_selector= NULL;
  350. len= (strlen(req.xcap_root)+ 1+ req.doc_sel.auid.len+ 5+
  351. req.doc_sel.xid.len+ req.doc_sel.filename.len+ 50)* sizeof(char);
  352. if(req.node_sel)
  353. len+= req.node_sel->size;
  354. path= (char*)pkg_malloc(len);
  355. if(path== NULL)
  356. {
  357. ERR_MEM(PKG_MEM_STR);
  358. }
  359. if(req.node_sel)
  360. {
  361. node_selector= get_node_selector(req.node_sel);
  362. if(node_selector== NULL)
  363. {
  364. LM_ERR("while constructing node selector\n");
  365. goto error;
  366. }
  367. }
  368. size= sprintf(path, "%s/%.*s/", req.xcap_root, req.doc_sel.auid.len,
  369. req.doc_sel.auid.s);
  370. if(req.doc_sel.type==USERS_TYPE)
  371. size+= sprintf(path+ size, "%s/%.*s/", "users", req.doc_sel.xid.len,
  372. req.doc_sel.xid.s);
  373. else
  374. size+= sprintf(path+ size, "%s/", "global");
  375. size+= sprintf(path+ size, "%.*s", req.doc_sel.filename.len,
  376. req.doc_sel.filename.s);
  377. if(node_selector)
  378. {
  379. size+= sprintf(path+ size, "/~~%s", node_selector);
  380. }
  381. if(size> len)
  382. {
  383. LM_ERR("buffer size overflow\n");
  384. goto error;
  385. }
  386. pkg_free(node_selector);
  387. return path;
  388. error:
  389. if(path)
  390. pkg_free(path);
  391. if(node_selector)
  392. pkg_free(node_selector);
  393. return NULL;
  394. }
  395. /* xcap_root must be a NULL terminated string */
  396. char* xcapGetElem(xcap_get_req_t req, char** etag)
  397. {
  398. char* path= NULL;
  399. char* stream= NULL;
  400. path= get_xcap_path(req);
  401. if(path== NULL)
  402. {
  403. LM_ERR("while constructing xcap path\n");
  404. return NULL;
  405. }
  406. stream= send_http_get(path, req.port, req.etag, req.match_type, etag);
  407. if(stream== NULL)
  408. {
  409. LM_DBG("the serched element was not found\n");
  410. }
  411. if(etag== NULL)
  412. {
  413. LM_ERR("no etag found\n");
  414. pkg_free(stream);
  415. stream= NULL;
  416. }
  417. if(path)
  418. pkg_free(path);
  419. return stream;
  420. }
  421. size_t get_xcap_etag( void *ptr, size_t size, size_t nmemb, void *stream)
  422. {
  423. int len= 0;
  424. char* etag= NULL;
  425. if(strncasecmp(ptr, ETAG_HDR, ETAG_HDR_LEN)== 0)
  426. {
  427. len= size* nmemb- ETAG_HDR_LEN;
  428. etag= (char*)pkg_malloc((len+ 1)* sizeof(char));
  429. if(etag== NULL)
  430. {
  431. ERR_MEM(PKG_MEM_STR);
  432. }
  433. memcpy(etag, ptr+ETAG_HDR_LEN, len);
  434. etag[len]= '\0';
  435. *((char**)stream)= etag;
  436. }
  437. return len;
  438. error:
  439. return -1;
  440. }
  441. char* send_http_get(char* path, unsigned int xcap_port, char* match_etag,
  442. int match_type, char** etag)
  443. {
  444. int len;
  445. char* stream= NULL;
  446. CURLcode ret_code;
  447. CURL* curl_handle= NULL;
  448. static char buf[128];
  449. char* match_header= NULL;
  450. *etag= NULL;
  451. if(match_etag)
  452. {
  453. char* hdr_name= NULL;
  454. memset(buf, 0, 128* sizeof(char));
  455. match_header= buf;
  456. hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match";
  457. len=sprintf(match_header, "%s: %s\n", hdr_name, match_etag);
  458. match_header[len]= '\0';
  459. }
  460. curl_handle = curl_easy_init();
  461. curl_easy_setopt(curl_handle, CURLOPT_URL, path);
  462. curl_easy_setopt(curl_handle, CURLOPT_PORT, xcap_port);
  463. curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
  464. curl_easy_setopt(curl_handle, CURLOPT_STDERR, stdout);
  465. curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_function);
  466. curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
  467. curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_xcap_etag);
  468. curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, &etag);
  469. if(match_header)
  470. curl_easy_setopt(curl_handle, CURLOPT_HEADER, (long)match_header);
  471. /* non-2xx => error */
  472. curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
  473. ret_code= curl_easy_perform(curl_handle );
  474. if( ret_code== CURLE_WRITE_ERROR)
  475. {
  476. LM_ERR("while performing curl option\n");
  477. if(stream)
  478. pkg_free(stream);
  479. stream= NULL;
  480. return NULL;
  481. }
  482. curl_global_cleanup();
  483. return stream;
  484. }
  485. size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream)
  486. {
  487. /* allocate memory and copy */
  488. char* data;
  489. data= (char*)pkg_malloc(size* nmemb);
  490. if(data== NULL)
  491. {
  492. ERR_MEM(PKG_MEM_STR);
  493. }
  494. memcpy(data, (char*)ptr, size* nmemb);
  495. *((char**) stream)= data;
  496. return size* nmemb;
  497. error:
  498. return CURLE_WRITE_ERROR;
  499. }