udomain.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of ser, a free SIP server.
  7. *
  8. * ser is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * For a license to use the ser software under conditions
  14. * other than those described here, or to purchase support for this
  15. * software, please contact iptel.org by e-mail at the following addresses:
  16. * [email protected]
  17. *
  18. * ser is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU General Public License
  24. * along with this program; if not, write to the Free Software
  25. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  26. *
  27. * History:
  28. * ---------
  29. * 2003-03-11 changed to the new locking scheme: locking.h (andrei)
  30. * 2003-03-12 added replication mark and zombie state (nils)
  31. * 2004-06-07 updated to the new DB api (andrei)
  32. * 2004-08-23 hash function changed to process characters as unsigned
  33. * -> no negative results occur (jku)
  34. * 2005-02-25 incoming socket is saved in ucontact record (bogdan)
  35. * 2006-11-23 switched to better hash functions and fixed hash size (andrei)
  36. *
  37. */
  38. #include "udomain.h"
  39. #include <string.h>
  40. #include "../../mem/shm_mem.h"
  41. #include "../../dprint.h"
  42. #include "../../lib/srdb2/db.h"
  43. #include "../../ut.h"
  44. #include "../../parser/parse_param.h"
  45. #include "../../parser/parse_uri.h"
  46. #include "../../resolve.h"
  47. #include "../../socket_info.h"
  48. #include "ul_mod.h" /* usrloc module parameters */
  49. #include "notify.h"
  50. #include "reg_avps.h"
  51. #include "reg_avps_db.h"
  52. #include "utime.h"
  53. #include "../../hashes.h"
  54. /* #define HASH_STRING_OPTIMIZE */
  55. /*
  56. * Hash function
  57. */
  58. static inline int hash_func(udomain_t* _d, unsigned char* _s, int _l)
  59. {
  60. #ifdef HASH_STRING_OPTIMIZE
  61. return get_hash1_raw((char*)_s, _l) % UDOMAIN_HASH_SIZE;
  62. #else
  63. return get_hash1_raw2((char*)_s, _l) % UDOMAIN_HASH_SIZE;
  64. #endif
  65. }
  66. /*
  67. * Add a record to list of all records in a domain
  68. */
  69. static inline void udomain_add(udomain_t* _d, urecord_t* _r)
  70. {
  71. if (_d->d_ll.n == 0) {
  72. _d->d_ll.first = _r;
  73. _d->d_ll.last = _r;
  74. } else {
  75. _r->d_ll.prev = _d->d_ll.last;
  76. _d->d_ll.last->d_ll.next = _r;
  77. _d->d_ll.last = _r;
  78. }
  79. _d->d_ll.n++;
  80. }
  81. /*
  82. * Remove a record from list of all records in a domain
  83. */
  84. static inline void udomain_remove(udomain_t* _d, urecord_t* _r)
  85. {
  86. if (_d->d_ll.n == 0) return;
  87. if (_r->d_ll.prev) {
  88. _r->d_ll.prev->d_ll.next = _r->d_ll.next;
  89. } else {
  90. _d->d_ll.first = _r->d_ll.next;
  91. }
  92. if (_r->d_ll.next) {
  93. _r->d_ll.next->d_ll.prev = _r->d_ll.prev;
  94. } else {
  95. _d->d_ll.last = _r->d_ll.prev;
  96. }
  97. _r->d_ll.prev = _r->d_ll.next = 0;
  98. _d->d_ll.n--;
  99. }
  100. /*
  101. * Create a new domain structure
  102. * _n is pointer to str representing
  103. * name of the domain, the string is
  104. * not copied, it should point to str
  105. * structure stored in domain list
  106. */
  107. int new_udomain(str* _n, udomain_t** _d)
  108. {
  109. int i;
  110. /* Must be always in shared memory, since
  111. * the cache is accessed from timer which
  112. * lives in a separate process
  113. */
  114. *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
  115. if (!(*_d)) {
  116. LOG(L_ERR, "new_udomain(): No memory left\n");
  117. return -1;
  118. }
  119. memset(*_d, 0, sizeof(udomain_t));
  120. (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * UDOMAIN_HASH_SIZE);
  121. if (!(*_d)->table) {
  122. LOG(L_ERR, "new_udomain(): No memory left 2\n");
  123. shm_free(*_d);
  124. return -2;
  125. }
  126. (*_d)->name = _n;
  127. for(i = 0; i < UDOMAIN_HASH_SIZE; i++) {
  128. if (init_slot(*_d, &((*_d)->table[i])) < 0) {
  129. LOG(L_ERR, "new_udomain(): Error while initializing hash table\n");
  130. shm_free((*_d)->table);
  131. shm_free(*_d);
  132. return -3;
  133. }
  134. }
  135. lock_init(&(*_d)->lock);
  136. (*_d)->users = 0;
  137. (*_d)->expired = 0;
  138. return 0;
  139. }
  140. /*
  141. * Free all memory allocated for
  142. * the domain
  143. */
  144. void free_udomain(udomain_t* _d)
  145. {
  146. int i;
  147. lock_udomain(_d);
  148. if (_d->table) {
  149. for(i = 0; i < UDOMAIN_HASH_SIZE; i++) {
  150. deinit_slot(_d->table + i);
  151. }
  152. shm_free(_d->table);
  153. }
  154. unlock_udomain(_d);
  155. lock_destroy(&_d->lock);/* destroy the lock (required for SYSV sems!)*/
  156. shm_free(_d);
  157. }
  158. /*
  159. * Just for debugging
  160. */
  161. void print_udomain(FILE* _f, udomain_t* _d)
  162. {
  163. struct urecord* r;
  164. fprintf(_f, "---Domain---\n");
  165. fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
  166. fprintf(_f, "size : %d\n", UDOMAIN_HASH_SIZE);
  167. fprintf(_f, "table: %p\n", _d->table);
  168. fprintf(_f, "d_ll {\n");
  169. fprintf(_f, " n : %d\n", _d->d_ll.n);
  170. fprintf(_f, " first: %p\n", _d->d_ll.first);
  171. fprintf(_f, " last : %p\n", _d->d_ll.last);
  172. fprintf(_f, "}\n");
  173. /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
  174. if (_d->d_ll.n > 0) {
  175. fprintf(_f, "\n");
  176. r = _d->d_ll.first;
  177. while(r) {
  178. print_urecord(_f, r);
  179. r = r->d_ll.next;
  180. }
  181. fprintf(_f, "\n");
  182. }
  183. fprintf(_f, "---/Domain---\n");
  184. }
  185. static struct socket_info* find_socket(str* received)
  186. {
  187. struct sip_uri puri;
  188. param_hooks_t hooks;
  189. struct hostent* he;
  190. struct ip_addr ip;
  191. struct socket_info* si;
  192. param_t* params;
  193. unsigned short port;
  194. char* buf;
  195. int error;
  196. if (!received) return 0;
  197. si = 0;
  198. if (parse_uri(received->s, received->len, &puri) < 0) {
  199. LOG(L_ERR, "find_socket: Error while parsing received URI\n");
  200. return 0;
  201. }
  202. if (parse_params(&puri.params, CLASS_URI, &hooks, &params) < 0) {
  203. LOG(L_ERR, "find_socket: Error while parsing received URI parameters\n");
  204. return 0;
  205. }
  206. if (!hooks.uri.dstip || !hooks.uri.dstip->body.s || !hooks.uri.dstip->body.len) goto end;
  207. buf = (char*)pkg_malloc(hooks.uri.dstip->body.len + 1);
  208. if (!buf) {
  209. LOG(L_ERR, "find_socket: No memory left\n");
  210. goto end;
  211. }
  212. memcpy(buf, hooks.uri.dstip->body.s, hooks.uri.dstip->body.len);
  213. buf[hooks.uri.dstip->body.len] = '\0';
  214. he = resolvehost(buf);
  215. if (he == 0) {
  216. LOG(L_ERR, "find_socket: Unable to resolve '%s'\n", buf);
  217. pkg_free(buf);
  218. goto end;
  219. }
  220. pkg_free(buf);
  221. if (hooks.uri.dstport && hooks.uri.dstport->body.s && hooks.uri.dstport->body.len) {
  222. port = str2s(hooks.uri.dstport->body.s, hooks.uri.dstport->body.len, &error);
  223. if (error != 0) {
  224. LOG(L_ERR, "find_socket: Unable to convert port number\n");
  225. goto end;
  226. }
  227. } else {
  228. port = 0;
  229. }
  230. hostent2ip_addr(&ip, he, 0);
  231. si = find_si(&ip, port, puri.proto);
  232. if (si == 0) {
  233. LOG(L_ERR, "find_socket: Unable to find socket, using the default one\n");
  234. goto end;
  235. }
  236. end:
  237. if (params) free_params(params);
  238. return si;
  239. }
  240. int preload_udomain(udomain_t* _d)
  241. {
  242. db_fld_t columns[] = {
  243. {.name = uid_col.s, .type = DB_STR},
  244. {.name = contact_col.s, .type = DB_STR},
  245. {.name = expires_col.s, .type = DB_DATETIME},
  246. {.name = q_col.s, .type = DB_DOUBLE},
  247. {.name = callid_col.s, .type = DB_STR},
  248. {.name = cseq_col.s, .type = DB_INT},
  249. {.name = flags_col.s, .type = DB_BITMAP},
  250. {.name = user_agent_col.s, .type = DB_STR},
  251. {.name = received_col.s, .type = DB_STR},
  252. {.name = instance_col.s, .type = DB_STR},
  253. {.name = aor_col.s, .type = DB_STR},
  254. {.name = server_id_col.s, .type = DB_INT},
  255. {.name = avp_column, .type = DB_STR}, /* Must be the last element in the array */
  256. {.name = NULL}
  257. };
  258. db_res_t* res = NULL;
  259. db_rec_t* rec;
  260. db_cmd_t* get_all = NULL;
  261. struct socket_info* sock;
  262. str callid, ua, instance, aor;
  263. str* receivedp;
  264. qvalue_t q;
  265. unsigned int flags;
  266. urecord_t* r;
  267. ucontact_t* c;
  268. get_all = db_cmd(DB_GET, db, _d->name->s, columns, NULL, NULL);
  269. if (get_all == NULL) {
  270. ERR("usrloc: Error while compiling DB_GET command\n");
  271. return -1;
  272. }
  273. if (db_setopt(get_all, "fetch_all", 0) < 0) {
  274. ERR("usrloc: Error while disabling 'fetch_all' database option\n");
  275. }
  276. if (db_exec(&res, get_all) < 0) goto error;
  277. rec = db_first(res);
  278. if (rec == NULL) {
  279. DBG("preload_udomain(): Table is empty\n");
  280. db_res_free(res);
  281. db_cmd_free(get_all);
  282. return 0;
  283. }
  284. lock_udomain(_d);
  285. get_act_time();
  286. for(; rec != NULL; rec = db_next(res)) {
  287. /* UID column must never be NULL */
  288. if (rec->fld[0].flags & DB_NULL) {
  289. LOG(L_CRIT, "preload_udomain: ERROR: bad uid "
  290. "record in table %.*s, skipping...\n",
  291. _d->name->len, _d->name->s);
  292. continue;
  293. }
  294. /* Contact column must never be NULL */
  295. if (rec->fld[1].flags & DB_NULL) {
  296. LOG(L_CRIT, "ERROR: Bad contact for uid %.*s in table %.*s, skipping\n",
  297. rec->fld[0].v.lstr.len, rec->fld[0].v.lstr.s,
  298. _d->name->len, _d->name->s);
  299. continue;
  300. }
  301. /* We only skip expired contacts if db_skip_delete is enabled. If
  302. * db_skip_delete is disabled then we must load expired contacts
  303. * in memory so that the timer can delete them later.
  304. */
  305. if (db_skip_delete && (rec->fld[2].v.time < act_time)) {
  306. DBG("preload_udomain: Skipping expired contact\n");
  307. continue;
  308. }
  309. q = double2q(rec->fld[3].v.dbl);
  310. if (rec->fld[4].flags & DB_NULL) {
  311. callid.s = NULL;
  312. callid.len = 0;
  313. } else {
  314. callid = rec->fld[4].v.lstr;
  315. }
  316. if (rec->fld[7].flags & DB_NULL) {
  317. ua.s = NULL;
  318. ua.len = 0;
  319. } else {
  320. ua = rec->fld[7].v.lstr;
  321. }
  322. if (rec->fld[8].flags & DB_NULL) {
  323. receivedp = 0;
  324. sock = 0;
  325. } else {
  326. receivedp = &rec->fld[8].v.lstr;
  327. sock = find_socket(receivedp);
  328. }
  329. if (rec->fld[9].flags & DB_NULL) {
  330. instance.s = NULL;
  331. instance.len = 0;
  332. } else {
  333. instance = rec->fld[9].v.lstr;
  334. }
  335. if (rec->fld[10].flags & DB_NULL) {
  336. aor.s = NULL;
  337. aor.len = 0;
  338. } else {
  339. aor = rec->fld[10].v.lstr;
  340. }
  341. if (get_urecord(_d, &rec->fld[0].v.lstr, &r) > 0) {
  342. if (mem_insert_urecord(_d, &rec->fld[0].v.lstr, &r) < 0) {
  343. LOG(L_ERR, "preload_udomain(): Can't create a record\n");
  344. unlock_udomain(_d);
  345. goto error;
  346. }
  347. }
  348. flags = rec->fld[6].v.bitmap;
  349. if (rec->fld[11].v.int4 != server_id) {
  350. /* FIXME: this should not be hardcoded here this way */
  351. /* This is a records from another SIP server instance, mark
  352. * it as in memory only because the other SIP server is responsible
  353. * for updating the record in database
  354. */
  355. flags |= FL_MEM;
  356. }
  357. if (mem_insert_ucontact(r, &aor, &rec->fld[1].v.lstr, rec->fld[2].v.int4,
  358. q, &callid, rec->fld[5].v.int4, flags, &c, &ua, receivedp,
  359. sock, &instance, rec->fld[11].v.int4) < 0) {
  360. LOG(L_ERR, "preload_udomain(): Error while inserting contact\n");
  361. unlock_udomain(_d);
  362. goto error;
  363. }
  364. if (use_reg_avps() && ((rec->fld[12].flags & DB_NULL) != DB_NULL)) {
  365. c->avps = deserialize_avps(&rec->fld[12].v.lstr);
  366. }
  367. /* We have to do this, because insert_ucontact sets state to CS_NEW
  368. * and we have the contact in the database already
  369. * we also store zombies in database so we have to restore
  370. * the correct state
  371. */
  372. c->state = CS_SYNC;
  373. }
  374. unlock_udomain(_d);
  375. db_res_free(res);
  376. db_cmd_free(get_all);
  377. return 0;
  378. error:
  379. if (res) db_res_free(res);
  380. if (get_all) db_cmd_free(get_all);
  381. return -1;
  382. }
  383. /*
  384. * Insert a new record into domain
  385. */
  386. int mem_insert_urecord(udomain_t* _d, str* _uid, struct urecord** _r)
  387. {
  388. int sl;
  389. if (new_urecord(_d->name, _uid, _r) < 0) {
  390. LOG(L_ERR, "insert_urecord(): Error while creating urecord\n");
  391. return -1;
  392. }
  393. sl = hash_func(_d, (unsigned char*)_uid->s, _uid->len);
  394. slot_add(&_d->table[sl], *_r);
  395. udomain_add(_d, *_r);
  396. _d->users++;
  397. return 0;
  398. }
  399. /*
  400. * Remove a record from domain
  401. */
  402. void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
  403. {
  404. if (_r->watchers == 0) {
  405. udomain_remove(_d, _r);
  406. slot_rem(_r->slot, _r);
  407. free_urecord(_r);
  408. _d->users--; /* FIXME */
  409. }
  410. }
  411. int timer_udomain(udomain_t* _d)
  412. {
  413. struct urecord* ptr, *t;
  414. lock_udomain(_d);
  415. ptr = _d->d_ll.first;
  416. while(ptr) {
  417. if (timer_urecord(ptr) < 0) {
  418. LOG(L_ERR, "timer_udomain(): Error in timer_urecord\n");
  419. unlock_udomain(_d);
  420. return -1;
  421. }
  422. /* Remove the entire record
  423. * if it is empty
  424. */
  425. if (ptr->contacts == 0) {
  426. t = ptr;
  427. ptr = ptr->d_ll.next;
  428. mem_delete_urecord(_d, t);
  429. } else {
  430. ptr = ptr->d_ll.next;
  431. }
  432. }
  433. unlock_udomain(_d);
  434. /* process_del_list(_d->name); */
  435. /* process_ins_list(_d->name); */
  436. return 0;
  437. }
  438. /*
  439. * Get lock
  440. */
  441. void lock_udomain(udomain_t* _d)
  442. {
  443. lock_get(&_d->lock);
  444. cur_cmd = _d->db_cmd_idx;
  445. }
  446. /*
  447. * Release lock
  448. */
  449. void unlock_udomain(udomain_t* _d)
  450. {
  451. lock_release(&_d->lock);
  452. }
  453. /*
  454. * Create and insert a new record
  455. */
  456. int insert_urecord(udomain_t* _d, str* _uid, struct urecord** _r)
  457. {
  458. if (mem_insert_urecord(_d, _uid, _r) < 0) {
  459. LOG(L_ERR, "insert_urecord(): Error while inserting record\n");
  460. return -1;
  461. }
  462. return 0;
  463. }
  464. /*
  465. * Obtain a urecord pointer if the urecord exists in domain
  466. */
  467. int get_urecord(udomain_t* _d, str* _uid, struct urecord** _r)
  468. {
  469. int sl, i;
  470. urecord_t* r;
  471. sl = hash_func(_d, (unsigned char*)_uid->s, _uid->len);
  472. r = _d->table[sl].first;
  473. for(i = 0; i < _d->table[sl].n; i++) {
  474. if ((r->uid.len == _uid->len) && !memcmp(r->uid.s, _uid->s, _uid->len)) {
  475. *_r = r;
  476. return 0;
  477. }
  478. r = r->s_ll.next;
  479. }
  480. return 1; /* Nothing found */
  481. }
  482. /*
  483. * Delete a urecord from domain
  484. */
  485. int delete_urecord(udomain_t* _d, str* _uid)
  486. {
  487. struct ucontact* c, *t;
  488. struct urecord* r;
  489. if (get_urecord(_d, _uid, &r) > 0) {
  490. return 0;
  491. }
  492. c = r->contacts;
  493. while(c) {
  494. t = c;
  495. c = c->next;
  496. if (delete_ucontact(r, t) < 0) {
  497. LOG(L_ERR, "delete_urecord(): Error while deleting contact\n");
  498. return -1;
  499. }
  500. }
  501. release_urecord(r);
  502. return 0;
  503. }