presentity.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. * Presence Agent, presentity structure and related functions
  3. *
  4. * $Id$
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. * Copyright (C) 2004 Jamey Hicks
  8. *
  9. * This file is part of ser, a free SIP server.
  10. *
  11. * ser is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * For a license to use the ser software under conditions
  17. * other than those described here, or to purchase support for this
  18. * software, please contact iptel.org by e-mail at the following addresses:
  19. * [email protected]
  20. *
  21. * ser is distributed in the hope that it will be useful,
  22. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. * GNU General Public License for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software
  28. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include "../../lib/srdb2/db.h"
  34. #include "../../dprint.h"
  35. #include "../../id.h"
  36. #include "../../mem/shm_mem.h"
  37. #include "../../ut.h"
  38. #include "../../parser/parse_event.h"
  39. #include "paerrno.h"
  40. #include "dlist.h"
  41. #include "notify.h"
  42. #include "pdomain.h"
  43. #include "presentity.h"
  44. #include "ptime.h"
  45. #include "pa_mod.h"
  46. #include "qsa_interface.h"
  47. #include <cds/logger.h>
  48. #include <cds/dbid.h>
  49. #include "async_auth.h"
  50. #include "tuple.h"
  51. #include "pres_notes.h"
  52. #include "extension_elements.h"
  53. extern int use_db;
  54. int auth_rules_refresh_time = 300;
  55. /* ----- helper functions ----- */
  56. int get_presentity_uid(str *uid_dst, struct sip_msg *m)
  57. {
  58. /* Independently on implementation of get_to_uid this function
  59. * gets UID from the message. It never uses dynamic allocation of
  60. * data (better to use static buffer instead due to speed)! */
  61. return get_to_uid(uid_dst, m);
  62. }
  63. void free_tuple_change_info_content(tuple_change_info_t *i)
  64. {
  65. str_free_content(&i->user);
  66. str_free_content(&i->contact);
  67. }
  68. int pres_uri2uid(str_t *uid_dst, const str_t *uri)
  69. {
  70. /* FIXME: convert uri to uid - used by internal subscriptions and fifo
  71. * commands - throw it out and use UUID only! */
  72. struct sip_uri puri;
  73. str_clear(uid_dst);
  74. /* if (db_lookup_user(uri, uid_dst) == 0) return 0; */
  75. /* else try the "hack" */
  76. if (parse_uri(uri->s, uri->len, &puri) == -1) {
  77. LOG(L_ERR, "get_from_uid: Error while parsing From URI\n");
  78. return -1;
  79. }
  80. str_dup(uid_dst, &puri.user);
  81. strlower(uid_dst);
  82. return 0;
  83. }
  84. /* ----- presentity functions ----- */
  85. /* Create a new presentity but do not update database.
  86. * If pres_id not set it generates new one, but only if db_mode set. */
  87. static inline int new_presentity_no_wb(struct pdomain *pdomain, str* _uri,
  88. str *uid,
  89. xcap_query_params_t *xcap_params,
  90. str *pres_id,
  91. presentity_t** _p)
  92. {
  93. presentity_t* presentity;
  94. int size = 0;
  95. dbid_t id;
  96. int id_len = 0;
  97. char *xcap_param_buffer;
  98. if ((!_uri) || (!_p) || (!uid)) {
  99. paerrno = PA_INTERNAL_ERROR;
  100. ERR("Invalid parameter value\n");
  101. return -1;
  102. }
  103. if (pres_id) size += pres_id->len;
  104. else {
  105. if (use_db) { /* do not generate IDs if not using DB */
  106. generate_dbid(id);
  107. id_len = dbid_strlen(id);
  108. size += id_len;
  109. }
  110. else id_len = 0;
  111. }
  112. if (xcap_params) size += get_inline_xcap_buf_len(xcap_params);
  113. size += sizeof(presentity_t) + _uri->len + uid->len;
  114. presentity = (presentity_t*)mem_alloc(size);
  115. /* TRACE("allocating presentity: %d\n", size); */
  116. if (!presentity) {
  117. paerrno = PA_NO_MEMORY;
  118. LOG(L_ERR, "No memory left: size=%d\n", size);
  119. *_p = NULL;
  120. return -1;
  121. }
  122. /* fill whole structure with zeros */
  123. memset(presentity, 0, sizeof(presentity_t));
  124. msg_queue_init(&presentity->mq);
  125. presentity->data.uri.s = ((char*)presentity) + sizeof(presentity_t);
  126. str_cpy(&presentity->data.uri, _uri);
  127. presentity->uuid.s = presentity->data.uri.s + presentity->data.uri.len;
  128. str_cpy(&presentity->uuid, uid);
  129. presentity->pres_id.s = presentity->uuid.s + presentity->uuid.len;
  130. if (pres_id) str_cpy(&presentity->pres_id, pres_id);
  131. else {
  132. if (use_db) dbid_strcpy(&presentity->pres_id, id, id_len);
  133. else presentity->pres_id.len = 0;
  134. }
  135. xcap_param_buffer = after_str_ptr(&presentity->pres_id);
  136. presentity->pdomain = pdomain;
  137. if (pa_auth_params.type == auth_xcap) {
  138. /* store XCAP parameters for async XCAP queries and refreshing
  139. * (FIXME: rewrite - use table of a few of existing XCAP parameter
  140. * sets instead of always duplicating because it will be mostly
  141. * the same!) */
  142. if (dup_xcap_params_inline(&presentity->xcap_params, xcap_params,
  143. xcap_param_buffer) < 0) {
  144. ERR("can't duplicate XCAP parameters\n");
  145. shm_free(presentity);
  146. *_p = NULL;
  147. return -1;
  148. }
  149. }
  150. if (ask_auth_rules(presentity) < 0) {
  151. /* try it from timer again if fails here */
  152. presentity->auth_rules_refresh_time = act_time;
  153. }
  154. else presentity->auth_rules_refresh_time = act_time + auth_rules_refresh_time;
  155. *_p = presentity;
  156. /* add presentity into domain */
  157. add_presentity(pdomain, *_p);
  158. return 0;
  159. }
  160. static inline int db_add_presentity(presentity_t* presentity)
  161. {
  162. db_key_t query_cols[6];
  163. db_val_t query_vals[6];
  164. int n_query_cols = 0;
  165. int res;
  166. str str_xcap_params;
  167. query_cols[0] = col_uri;
  168. query_vals[0].type = DB_STR;
  169. query_vals[0].nul = 0;
  170. query_vals[0].val.str_val = presentity->data.uri;
  171. n_query_cols++;
  172. query_cols[n_query_cols] = col_pdomain;
  173. query_vals[n_query_cols].type = DB_STR;
  174. query_vals[n_query_cols].nul = 0;
  175. query_vals[n_query_cols].val.str_val = *presentity->pdomain->name;
  176. n_query_cols++;
  177. query_cols[n_query_cols] = col_uid;
  178. query_vals[n_query_cols].type = DB_STR;
  179. query_vals[n_query_cols].nul = 0;
  180. query_vals[n_query_cols].val.str_val = presentity->uuid;
  181. n_query_cols++;
  182. query_cols[n_query_cols] = col_pres_id;
  183. query_vals[n_query_cols].type = DB_STR;
  184. query_vals[n_query_cols].nul = 0;
  185. query_vals[n_query_cols].val.str_val = presentity->pres_id;
  186. n_query_cols++;
  187. /*query_cols[n_query_cols] = "id_cntr";
  188. query_vals[n_query_cols].type = DB_INT;
  189. query_vals[n_query_cols].nul = 0;
  190. query_vals[n_query_cols].val.int_val = presentity->id_cntr;
  191. n_query_cols++;*/
  192. /* store XCAP parameters with presentity */
  193. if (xcap_params2str(&str_xcap_params, &presentity->xcap_params) != 0) {
  194. LOG(L_ERR, "Error while serializing xcap params\n");
  195. return -1;
  196. }
  197. query_cols[n_query_cols] = col_xcap_params;
  198. query_vals[n_query_cols].type = DB_BLOB;
  199. query_vals[n_query_cols].nul = 0;
  200. query_vals[n_query_cols].val.blob_val = str_xcap_params;
  201. n_query_cols++;
  202. res = 0;
  203. if (pa_dbf.use_table(pa_db, presentity_table) < 0) {
  204. ERR("Error in use_table\n");
  205. res = -1;
  206. }
  207. /* insert new record into database */
  208. if (res == 0) {
  209. if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) {
  210. ERR("Error while inserting presentity into DB\n");
  211. res = -1;
  212. }
  213. }
  214. str_free_content(&str_xcap_params);
  215. return res;
  216. }
  217. /*
  218. * Create a new presentity
  219. */
  220. int new_presentity(struct pdomain *pdomain, str* _uri, str *uid,
  221. xcap_query_params_t *params,
  222. presentity_t** _p)
  223. {
  224. int res = 0;
  225. res = new_presentity_no_wb(pdomain, _uri, uid, params, NULL, _p);
  226. if (res != 0) return res;
  227. if (use_db) {
  228. if (db_add_presentity(*_p) != 0) {
  229. paerrno = PA_INTERNAL_ERROR;
  230. free_presentity(*_p);
  231. *_p = NULL;
  232. return -1;
  233. }
  234. }
  235. return res;
  236. }
  237. /* Removes all data for presentity (tuples, watchers, tuple notes, ...)
  238. * from database. It is possible due to that pres_id is unique identifier
  239. * common for all tables */
  240. int db_remove_presentity_data(presentity_t* presentity, const char *table)
  241. {
  242. db_key_t keys[] = { col_pres_id };
  243. db_op_t ops[] = { OP_EQ };
  244. db_val_t k_vals[] = { { DB_STR, 0, { .str_val = presentity->pres_id } } };
  245. if (!use_db) return 0;
  246. if (pa_dbf.use_table(pa_db, table) < 0) {
  247. ERR("Error in use_table\n");
  248. return -1;
  249. }
  250. if (pa_dbf.delete(pa_db, keys, ops, k_vals, 1) < 0) {
  251. LOG(L_ERR, "Error while querying presentity\n");
  252. return -1;
  253. }
  254. return 0;
  255. }
  256. static inline int db_remove_presentity(presentity_t* presentity)
  257. {
  258. int res = 0;
  259. if (!use_db) return 0;
  260. res = db_remove_presentity_data(presentity, presentity_contact_table);
  261. res = db_remove_presentity_data(presentity, tuple_notes_table) | res;
  262. res = db_remove_presentity_data(presentity, watcherinfo_table) | res;
  263. res = db_remove_presentity_data(presentity, presentity_notes_table) | res;
  264. res = db_remove_presentity_data(presentity, extension_elements_table) | res;
  265. res = db_remove_presentity_data(presentity, presentity_table) | res;
  266. return res;
  267. }
  268. void release_presentity(presentity_t *_p)
  269. {
  270. /* remove presentity from DB and free its memory */
  271. if (_p) {
  272. db_remove_presentity(_p);
  273. free_presentity(_p);
  274. }
  275. }
  276. void free_presentity(presentity_t* _p)
  277. {
  278. watcher_t *w, *nw;
  279. presence_tuple_t *tuple, *t;
  280. internal_pa_subscription_t *iw, *niw;
  281. pa_presence_note_t *n, *nn;
  282. pa_extension_element_t *e, *ne;
  283. /* remove presentity from domain */
  284. remove_presentity(_p->pdomain, _p);
  285. /* watchers should be released already */
  286. w = _p->first_watcher;
  287. while (w) {
  288. nw = w->next;
  289. free_watcher(w);
  290. w = nw;
  291. }
  292. w = _p->first_winfo_watcher;
  293. while (w) {
  294. nw = w->next;
  295. free_watcher(w);
  296. w = nw;
  297. }
  298. t = get_first_tuple(_p);
  299. while (t) {
  300. tuple = t;
  301. t = (presence_tuple_t*)t->data.next;
  302. free_presence_tuple(tuple);
  303. }
  304. iw = _p->first_qsa_subscription;
  305. while (iw) {
  306. niw = iw->next;
  307. free_internal_subscription(iw);
  308. iw = niw;
  309. }
  310. /* remove notes */
  311. n = (pa_presence_note_t*)_p->data.first_note;
  312. while (n) {
  313. nn = (pa_presence_note_t*)n->data.next;
  314. free_pres_note(n);
  315. n = nn;
  316. }
  317. /* remove extension_elements */
  318. e = (pa_extension_element_t*)_p->data.first_unknown_element;
  319. while (e) {
  320. ne = (pa_extension_element_t*)e->data.next;
  321. free_pa_extension_element(e);
  322. e = ne;
  323. }
  324. if (_p->authorization_info) {
  325. free_pres_rules(_p->authorization_info);
  326. }
  327. /* XCAP params are allocated "inline" -> no free needed - it will
  328. * be freed with whole structure */
  329. /* free_xcap_params_content(&_p->xcap_params); */
  330. msg_queue_destroy(&_p->mq);
  331. mem_free(_p);
  332. }
  333. int pdomain_load_presentities(pdomain_t *pdomain)
  334. {
  335. if (!use_db) return 0;
  336. db_key_t query_cols[1];
  337. db_op_t query_ops[1];
  338. db_val_t query_vals[1];
  339. db_key_t result_cols[8];
  340. db_res_t *res;
  341. int n_query_cols = 0;
  342. int n_result_cols = 0;
  343. int uri_col;
  344. int presid_col;
  345. int uid_col;
  346. int xcap_col;
  347. int i;
  348. presentity_t *presentity = NULL;
  349. db_con_t* db = create_pa_db_connection(); /* must create its own connection (called before child init)! */
  350. if (!db) {
  351. ERR("Can't load presentities - no DB connection\n");
  352. return -1;
  353. }
  354. act_time = time(NULL); /* needed for fetching auth rules, ... */
  355. query_cols[n_query_cols] = col_pdomain;
  356. query_ops[n_query_cols] = OP_EQ;
  357. query_vals[n_query_cols].type = DB_STR;
  358. query_vals[n_query_cols].nul = 0;
  359. query_vals[n_query_cols].val.str_val = *pdomain->name;
  360. n_query_cols++;
  361. result_cols[uri_col = n_result_cols++] = col_uri;
  362. result_cols[presid_col = n_result_cols++] = col_pres_id;
  363. result_cols[uid_col = n_result_cols++] = col_uid;
  364. result_cols[xcap_col = n_result_cols++] = col_xcap_params;
  365. if (pa_dbf.use_table(db, presentity_table) < 0) {
  366. LOG(L_ERR, "pdomain_load_presentities: Error in use_table\n");
  367. close_pa_db_connection(db);
  368. return -1;
  369. }
  370. if (pa_dbf.query (db, query_cols, query_ops, query_vals,
  371. result_cols, n_query_cols, n_result_cols, 0, &res) < 0) {
  372. LOG(L_ERR, "pdomain_load_presentities: Error while querying presentity\n");
  373. close_pa_db_connection(db);
  374. return -1;
  375. }
  376. if (res) {
  377. for (i = 0; i < res->n; i++) {
  378. /* fill in tuple structure from database query result */
  379. db_row_t *row = &res->rows[i];
  380. db_val_t *row_vals = ROW_VALUES(row);
  381. str uri = STR_NULL;
  382. str pres_id = STR_NULL;
  383. str uid = STR_NULL;
  384. str serialized_xcap_params = STR_NULL;
  385. xcap_query_params_t xcap_params;
  386. if (!row_vals[uri_col].nul) {
  387. uri.s = (char *)row_vals[uri_col].val.string_val;
  388. uri.len = strlen(uri.s);
  389. }
  390. if (!row_vals[uid_col].nul) {
  391. uid.s = (char *)row_vals[uid_col].val.string_val;
  392. uid.len = strlen(uid.s);
  393. }
  394. if (!row_vals[presid_col].nul) {
  395. pres_id.s = (char *)row_vals[presid_col].val.string_val;
  396. pres_id.len = strlen(pres_id.s);
  397. }
  398. if (!row_vals[xcap_col].nul) {
  399. serialized_xcap_params.s = (char *)row_vals[xcap_col].val.string_val;
  400. serialized_xcap_params.len = strlen(serialized_xcap_params.s);
  401. }
  402. DBG("pdomain_load_presentities: pdomain=%.*s presentity uri=%.*s presid=%.*s\n",
  403. pdomain->name->len, pdomain->name->s, uri.len, uri.s,
  404. pres_id.len, pres_id.s);
  405. str2xcap_params(&xcap_params, &serialized_xcap_params);
  406. new_presentity_no_wb(pdomain, &uri, &uid, &xcap_params, &pres_id, &presentity);
  407. free_xcap_params_content(&xcap_params);
  408. }
  409. pa_dbf.free_result(db, res);
  410. }
  411. for (presentity = pdomain->first; presentity; presentity = presentity->next) {
  412. db_read_watcherinfo(presentity, db);
  413. db_read_tuples(presentity, db);
  414. db_read_notes(presentity, db);
  415. db_read_extension_elements(presentity, db);
  416. }
  417. close_pa_db_connection(db);
  418. return 0;
  419. }
  420. int set_auth_rules(presentity_t *p, presence_rules_t *new_auth_rules)
  421. {
  422. watcher_t *w;
  423. watcher_status_t s;
  424. /* ! call from locked region only ! */
  425. /* INFO("setting auth rules\n"); */
  426. if (p->authorization_info) {
  427. free_pres_rules(p->authorization_info); /* free old rules */
  428. }
  429. p->authorization_info = new_auth_rules;
  430. /* reauthorize all watchers (but NOT winfo watchers - not needed
  431. * now because we have only "implicit" auth. rules for them) */
  432. w = p->first_watcher;
  433. while (w) {
  434. s = authorize_watcher(p, w);
  435. if (w->status != s) {
  436. /* status has changed */
  437. w->status = s;
  438. w->flags |= WFLAG_SUBSCRIPTION_CHANGED;
  439. p->flags |= PFLAG_WATCHERINFO_CHANGED;
  440. /* NOTIFYs, terminating, ... wil be done in timer */
  441. }
  442. w = w->next;
  443. }
  444. return 0;
  445. }