udomain.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /*
  2. * $Id: udomain.c 5272 2008-11-27 12:32:26Z henningw $
  3. *
  4. * Copyright (C) 2001-2003 FhG Fokus
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio 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. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * History:
  23. * ---------
  24. * 2003-03-11 changed to the new locking scheme: locking.h (andrei)
  25. * 2003-03-12 added replication mark and zombie state (nils)
  26. * 2004-06-07 updated to the new DB api (andrei)
  27. * 2004-08-23 hash function changed to process characters as unsigned
  28. * -> no negative results occur (jku)
  29. */
  30. /*! \file
  31. * \brief USRLOC - Userloc domain handling functions
  32. * \ingroup usrloc
  33. *
  34. * - Module: \ref usrloc
  35. */
  36. #include "udomain.h"
  37. #include <string.h>
  38. #include "../../parser/parse_methods.h"
  39. #include "../../mem/shm_mem.h"
  40. #include "../../dprint.h"
  41. #include "../../lib/srdb1/db.h"
  42. #include "../../socket_info.h"
  43. #include "../../ut.h"
  44. #include "../../hashes.h"
  45. #include "p_usrloc_mod.h" /* usrloc module parameters */
  46. #include "utime.h"
  47. #include "ul_db_layer.h"
  48. #ifdef STATISTICS
  49. static char *build_stat_name( str* domain, char *var_name)
  50. {
  51. int n;
  52. char *s;
  53. char *p;
  54. n = domain->len + 1 + strlen(var_name) + 1;
  55. s = (char*)shm_malloc( n );
  56. if (s==0) {
  57. LM_ERR("no more shm mem\n");
  58. return 0;
  59. }
  60. memcpy( s, domain->s, domain->len);
  61. p = s + domain->len;
  62. *(p++) = '-';
  63. memcpy( p , var_name, strlen(var_name));
  64. p += strlen(var_name);
  65. *(p++) = 0;
  66. return s;
  67. }
  68. #endif
  69. /*!
  70. * \brief Create a new domain structure
  71. * \param _n is pointer to str representing name of the domain, the string is
  72. * not copied, it should point to str structure stored in domain list
  73. * \param _s is hash table size
  74. * \param _d new created domain
  75. * \return 0 on success, -1 on failure
  76. */
  77. int new_udomain(str* _n, int _s, udomain_t** _d)
  78. {
  79. int i;
  80. #ifdef STATISTICS
  81. char *name;
  82. #endif
  83. /* Must be always in shared memory, since
  84. * the cache is accessed from timer which
  85. * lives in a separate process
  86. */
  87. *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
  88. if (!(*_d)) {
  89. LM_ERR("new_udomain(): No memory left\n");
  90. goto error0;
  91. }
  92. memset(*_d, 0, sizeof(udomain_t));
  93. (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
  94. if (!(*_d)->table) {
  95. LM_ERR("no memory left 2\n");
  96. goto error1;
  97. }
  98. (*_d)->name = _n;
  99. for(i = 0; i < _s; i++) {
  100. init_slot(*_d, &((*_d)->table[i]), i);
  101. }
  102. (*_d)->size = _s;
  103. #ifdef STATISTICS
  104. /* register the statistics */
  105. if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
  106. name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
  107. LM_ERR("failed to add stat variable\n");
  108. goto error2;
  109. }
  110. if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
  111. name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
  112. LM_ERR("failed to add stat variable\n");
  113. goto error2;
  114. }
  115. if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
  116. name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
  117. LM_ERR("failed to add stat variable\n");
  118. goto error2;
  119. }
  120. #endif
  121. return 0;
  122. #ifdef STATISTICS
  123. error2:
  124. shm_free((*_d)->table);
  125. #endif
  126. error1:
  127. shm_free(*_d);
  128. error0:
  129. return -1;
  130. }
  131. /*!
  132. * \brief Free all memory allocated for the domain
  133. * \param _d freed domain
  134. */
  135. void free_udomain(udomain_t* _d)
  136. {
  137. int i;
  138. if (_d->table) {
  139. for(i = 0; i < _d->size; i++) {
  140. lock_ulslot(_d, i);
  141. deinit_slot(_d->table + i);
  142. unlock_ulslot(_d, i);
  143. }
  144. shm_free(_d->table);
  145. }
  146. shm_free(_d);
  147. }
  148. /*!
  149. * \brief Returns a static dummy urecord for temporary usage
  150. * \param _d domain (needed for the name)
  151. * \param _aor address of record
  152. * \param _r new created urecord
  153. */
  154. static inline void get_static_urecord(udomain_t* _d, str* _aor,
  155. struct urecord** _r)
  156. {
  157. static struct urecord r;
  158. memset( &r, 0, sizeof(struct urecord) );
  159. r.aor = *_aor;
  160. r.aorhash = ul_get_aorhash(_aor);
  161. r.domain = _d->name;
  162. *_r = &r;
  163. }
  164. /*!
  165. * \brief Debugging helper function
  166. */
  167. void print_udomain(FILE* _f, udomain_t* _d)
  168. {
  169. int i;
  170. int max=0, slot=0, n=0;
  171. struct urecord* r;
  172. fprintf(_f, "---Domain---\n");
  173. fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
  174. fprintf(_f, "size : %d\n", _d->size);
  175. fprintf(_f, "table: %p\n", _d->table);
  176. /*fprintf(_f, "lock : %d\n", _d->lock); -- can be a structure --andrei*/
  177. fprintf(_f, "\n");
  178. for(i=0; i<_d->size; i++)
  179. {
  180. r = _d->table[i].first;
  181. n += _d->table[i].n;
  182. if(max<_d->table[i].n){
  183. max= _d->table[i].n;
  184. slot = i;
  185. }
  186. while(r) {
  187. print_urecord(_f, r);
  188. r = r->next;
  189. }
  190. }
  191. fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
  192. fprintf(_f, "\n---/Domain---\n");
  193. }
  194. /*!
  195. * \brief Convert database values into ucontact_info
  196. *
  197. * Convert database values into ucontact_info,
  198. * expects 12 rows (contact, expirs, q, callid, cseq, flags,
  199. * ua, received, path, socket, methods, last_modified)
  200. * \param vals database values
  201. * \param contact contact
  202. * \return pointer to the ucontact_info on success, 0 on failure
  203. */
  204. static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
  205. {
  206. static ucontact_info_t ci;
  207. static str callid, ua, received, host, path;
  208. int port, proto;
  209. char *p;
  210. memset( &ci, 0, sizeof(ucontact_info_t));
  211. contact->s = (char*)VAL_STRING(vals);
  212. if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
  213. LM_CRIT("bad contact\n");
  214. return 0;
  215. }
  216. contact->len = strlen(contact->s);
  217. if (VAL_NULL(vals+1)) {
  218. LM_CRIT("empty expire\n");
  219. return 0;
  220. }
  221. ci.expires = VAL_TIME(vals+1);
  222. if (VAL_NULL(vals+2)) {
  223. LM_CRIT("empty q\n");
  224. return 0;
  225. }
  226. ci.q = double2q(VAL_DOUBLE(vals+2));
  227. if (VAL_NULL(vals+4)) {
  228. LM_CRIT("empty cseq_nr\n");
  229. return 0;
  230. }
  231. ci.cseq = VAL_INT(vals+4);
  232. callid.s = (char*)VAL_STRING(vals+3);
  233. if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
  234. LM_CRIT("bad callid\n");
  235. return 0;
  236. }
  237. callid.len = strlen(callid.s);
  238. ci.callid = &callid;
  239. if (VAL_NULL(vals+5)) {
  240. LM_CRIT("empty flag\n");
  241. return 0;
  242. }
  243. ci.flags = VAL_BITMAP(vals+5);
  244. if (VAL_NULL(vals+6)) {
  245. LM_CRIT("empty cflag\n");
  246. return 0;
  247. }
  248. ci.cflags = VAL_BITMAP(vals+6);
  249. ua.s = (char*)VAL_STRING(vals+7);
  250. if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
  251. ua.s = 0;
  252. ua.len = 0;
  253. } else {
  254. ua.len = strlen(ua.s);
  255. }
  256. ci.user_agent = &ua;
  257. received.s = (char*)VAL_STRING(vals+8);
  258. if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
  259. received.len = 0;
  260. received.s = 0;
  261. } else {
  262. received.len = strlen(received.s);
  263. }
  264. ci.received = received;
  265. path.s = (char*)VAL_STRING(vals+9);
  266. if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
  267. path.len = 0;
  268. path.s = 0;
  269. } else {
  270. path.len = strlen(path.s);
  271. }
  272. ci.path= &path;
  273. /* socket name */
  274. p = (char*)VAL_STRING(vals+10);
  275. if (VAL_NULL(vals+10) || p==0 || p[0]==0){
  276. ci.sock = 0;
  277. } else {
  278. if (parse_phostport( p, &host.s, &host.len,
  279. &port, &proto)!=0){
  280. LM_ERR("bad socket <%s>\n", p);
  281. return 0;
  282. }
  283. ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
  284. if (ci.sock==0) {
  285. LM_INFO("non-local socket <%s>...ignoring\n", p);
  286. }
  287. }
  288. /* supported methods */
  289. if (VAL_NULL(vals+11)) {
  290. ci.methods = ALL_METHODS;
  291. } else {
  292. ci.methods = VAL_BITMAP(vals+11);
  293. }
  294. /* last modified time */
  295. if (!VAL_NULL(vals+12)) {
  296. ci.last_modified = VAL_TIME(vals+12);
  297. }
  298. /* record internal uid */
  299. if (!VAL_NULL(vals+13)) {
  300. ci.ruid.s = (char*)VAL_STRING(vals+13);
  301. ci.ruid.len = strlen(ci.ruid.s);
  302. }
  303. /* sip instance */
  304. if (!VAL_NULL(vals+14)) {
  305. ci.instance.s = (char*)VAL_STRING(vals+14);
  306. ci.instance.len = strlen(ci.instance.s);
  307. }
  308. /* reg-id */
  309. if (!VAL_NULL(vals+15)) {
  310. ci.reg_id = VAL_UINT(vals+15);
  311. }
  312. return &ci;
  313. }
  314. /*!
  315. * \brief Loads from DB all contacts for an AOR
  316. * \param _c database connection
  317. * \param _d domain
  318. * \param _aor address of record
  319. * \return pointer to the record on success, 0 on errors or if nothing is found
  320. */
  321. urecord_t* db_load_urecord(udomain_t* _d, str *_aor)
  322. {
  323. ucontact_info_t *ci;
  324. db_key_t columns[16];
  325. db_key_t keys[2];
  326. db_key_t order;
  327. db_val_t vals[2];
  328. db1_res_t* res = NULL;
  329. str contact;
  330. char *domain;
  331. int i;
  332. urecord_t* r;
  333. ucontact_t* c;
  334. keys[0] = &user_col;
  335. vals[0].type = DB1_STR;
  336. vals[0].nul = 0;
  337. if (use_domain) {
  338. keys[1] = &domain_col;
  339. vals[1].type = DB1_STR;
  340. vals[1].nul = 0;
  341. domain = memchr(_aor->s, '@', _aor->len);
  342. vals[0].val.str_val.s = _aor->s;
  343. if (domain==0) {
  344. vals[0].val.str_val.len = 0;
  345. vals[1].val.str_val = *_aor;
  346. } else {
  347. vals[0].val.str_val.len = domain - _aor->s;
  348. vals[1].val.str_val.s = domain+1;
  349. vals[1].val.str_val.len = _aor->s + _aor->len - domain - 1;
  350. }
  351. } else {
  352. vals[0].val.str_val = *_aor;
  353. }
  354. columns[0] = &contact_col;
  355. columns[1] = &expires_col;
  356. columns[2] = &q_col;
  357. columns[3] = &callid_col;
  358. columns[4] = &cseq_col;
  359. columns[5] = &flags_col;
  360. columns[6] = &cflags_col;
  361. columns[7] = &user_agent_col;
  362. columns[8] = &received_col;
  363. columns[9] = &path_col;
  364. columns[10] = &sock_col;
  365. columns[11] = &methods_col;
  366. columns[12] = &last_mod_col;
  367. columns[13] = &ruid_col;
  368. columns[14] = &instance_col;
  369. columns[15] = &reg_id_col;
  370. if (desc_time_order)
  371. order = &last_mod_col;
  372. else
  373. order = &q_col;
  374. if (ul_db_layer_query(_d, &vals[0].val.str_val, &vals[1].val.str_val, keys, 0, vals, columns, (use_domain)?2:1, 16, order,
  375. &res) < 0) {
  376. LM_ERR("db_query failed\n");
  377. return 0;
  378. }
  379. if (RES_ROW_N(res) == 0) {
  380. LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
  381. ul_db_layer_free_result(_d, res);
  382. return 0;
  383. }
  384. r = 0;
  385. for(i = 0; i < RES_ROW_N(res); i++) {
  386. ci = dbrow2info( ROW_VALUES(RES_ROWS(res) + i), &contact);
  387. if (ci==0) {
  388. LM_ERR("skipping record for %.*s in table %s\n",
  389. _aor->len, _aor->s, _d->name->s);
  390. continue;
  391. }
  392. if ( r==0 )
  393. get_static_urecord( _d, _aor, &r);
  394. if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
  395. LM_ERR("mem_insert failed\n");
  396. free_urecord(r);
  397. ul_db_layer_free_result(_d, res);
  398. return 0;
  399. }
  400. /* We have to do this, because insert_ucontact sets state to CS_NEW
  401. * and we have the contact in the database already */
  402. c->state = CS_SYNC;
  403. }
  404. ul_db_layer_free_result(_d, res);
  405. return r;
  406. }
  407. /*!
  408. * \brief Loads from DB all contacts for a RUID
  409. * \param _c database connection
  410. * \param _d domain
  411. * \param _aor address of record
  412. * \return pointer to the record on success, 0 on errors or if nothing is found
  413. */
  414. urecord_t* db_load_urecord_by_ruid(udomain_t* _d, str *_ruid)
  415. {
  416. ucontact_info_t *ci;
  417. db_key_t columns[18];
  418. db_key_t keys[1];
  419. db_key_t order;
  420. db_val_t vals[1];
  421. db1_res_t* res = NULL;
  422. db_row_t *row;
  423. str contact;
  424. str aor;
  425. char aorbuf[512];
  426. str domain;
  427. urecord_t* r;
  428. ucontact_t* c;
  429. keys[0] = &ruid_col;
  430. vals[0].type = DB1_STR;
  431. vals[0].nul = 0;
  432. vals[0].val.str_val = *_ruid;
  433. columns[0] = &contact_col;
  434. columns[1] = &expires_col;
  435. columns[2] = &q_col;
  436. columns[3] = &callid_col;
  437. columns[4] = &cseq_col;
  438. columns[5] = &flags_col;
  439. columns[6] = &cflags_col;
  440. columns[7] = &user_agent_col;
  441. columns[8] = &received_col;
  442. columns[9] = &path_col;
  443. columns[10] = &sock_col;
  444. columns[11] = &methods_col;
  445. columns[12] = &last_mod_col;
  446. columns[13] = &ruid_col;
  447. columns[14] = &instance_col;
  448. columns[15] = &user_col;
  449. columns[16] = &reg_id_col;
  450. columns[17] = &domain_col;
  451. if (desc_time_order)
  452. order = &last_mod_col;
  453. else
  454. order = &q_col;
  455. if (ul_db_layer_query(_d, &vals[0].val.str_val, &vals[1].val.str_val, keys, 0, vals, columns, 1, 18, order,
  456. &res) < 0) {
  457. LM_ERR("db_query failed\n");
  458. return 0;
  459. }
  460. if (RES_ROW_N(res) == 0) {
  461. LM_DBG("aor %.*s not found in table %.*s\n",_ruid->len, _ruid->s,
  462. _d->name->len, _d->name->s);
  463. ul_db_layer_free_result(_d, res);
  464. return 0;
  465. }
  466. r = 0;
  467. /* use first row - shouldn't be more */
  468. row = RES_ROWS(res);
  469. ci = dbrow2info(ROW_VALUES(RES_ROWS(res)), &contact);
  470. if (ci==0) {
  471. LM_ERR("skipping record for %.*s in table %s\n",
  472. _ruid->len, _ruid->s, _d->name->s);
  473. goto done;
  474. }
  475. aor.s = (char*)VAL_STRING(ROW_VALUES(row) + 15);
  476. aor.len = strlen(aor.s);
  477. if (use_domain) {
  478. domain.s = (char*)VAL_STRING(ROW_VALUES(row) + 17);
  479. if (VAL_NULL(ROW_VALUES(row)+17) || domain.s==0 || domain.s[0]==0){
  480. LM_CRIT("empty domain record for user %.*s...skipping\n",
  481. aor.len, aor.s);
  482. goto done;
  483. }
  484. domain.len = strlen(domain.s);
  485. if(aor.len + domain.len + 2 >= 512) {
  486. LM_ERR("AoR is too big\n");
  487. goto done;
  488. }
  489. memcpy(aorbuf, aor.s, aor.len);
  490. aorbuf[aor.len] = '@';
  491. memcpy(aorbuf + aor.len + 1, domain.s, domain.len);
  492. aor.len += 1 + domain.len;
  493. aor.s = aorbuf;
  494. aor.s[aor.len] = '\0';
  495. }
  496. get_static_urecord( _d, &aor, &r);
  497. if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
  498. LM_ERR("mem_insert failed\n");
  499. free_urecord(r);
  500. ul_db_layer_free_result(_d, res);
  501. return 0;
  502. }
  503. /* We have to do this, because insert_ucontact sets state to CS_NEW
  504. * and we have the contact in the database already */
  505. c->state = CS_SYNC;
  506. done:
  507. ul_db_layer_free_result(_d, res);
  508. ;
  509. return r;
  510. }
  511. /*!
  512. * \brief Timer function to cleanup expired contacts, DB_ONLY db_mode
  513. * \param _d cleaned domain
  514. * \return 0 on success, -1 on failure
  515. */
  516. /*
  517. int db_timer_udomain(udomain_t* _d)
  518. {
  519. db_key_t keys[2];
  520. db_op_t ops[2];
  521. db_val_t vals[2];
  522. keys[0] = &expires_col;
  523. ops[0] = "<";
  524. vals[0].type = DB1_DATETIME;
  525. vals[0].nul = 0;
  526. vals[0].val.time_val = act_time + 1;
  527. keys[1] = &expires_col;
  528. ops[1] = "!=";
  529. vals[1].type = DB1_DATETIME;
  530. vals[1].nul = 0;
  531. vals[1].val.time_val = 0;
  532. // we're using a local cron job to delete expired entries
  533. LM_INFO("using sp-ul_db database interface, expires is not implemented");
  534. //if (ul_db_layer_delete(_d, NULL, NULL, keys, ops, vals, 2) < 0) { //FIXME
  535. return 0;
  536. }
  537. */
  538. /*!
  539. * \brief Insert a new record into domain in memory
  540. * \param _d domain the record belongs to
  541. * \param _aor address of record
  542. * \param _r new created record
  543. * \return 0 on success, -1 on failure
  544. */
  545. int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
  546. {
  547. int sl;
  548. if (new_urecord(_d->name, _aor, _r) < 0) {
  549. LM_ERR("creating urecord failed\n");
  550. return -1;
  551. }
  552. sl = ((*_r)->aorhash)&(_d->size-1);
  553. slot_add(&_d->table[sl], *_r);
  554. update_stat( _d->users, 1);
  555. return 0;
  556. }
  557. /*!
  558. * \brief Remove a record from domain in memory
  559. * \param _d domain the record belongs to
  560. * \param _r deleted record
  561. */
  562. void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
  563. {
  564. slot_rem(_r->slot, _r);
  565. free_urecord(_r);
  566. update_stat( _d->users, -1);
  567. }
  568. /*!
  569. * \brief Run timer handler for given domain
  570. * \param _d domain
  571. */
  572. void mem_timer_udomain(udomain_t* _d)
  573. {
  574. struct urecord* ptr, *t;
  575. int i;
  576. for(i=0; i<_d->size; i++)
  577. {
  578. lock_ulslot(_d, i);
  579. ptr = _d->table[i].first;
  580. while(ptr) {
  581. timer_urecord(ptr);
  582. /* Remove the entire record if it is empty */
  583. if (ptr->contacts == 0) {
  584. t = ptr;
  585. ptr = ptr->next;
  586. mem_delete_urecord(_d, t);
  587. } else {
  588. ptr = ptr->next;
  589. }
  590. }
  591. unlock_ulslot(_d, i);
  592. }
  593. }
  594. /*!
  595. * \brief Get lock for a domain
  596. * \param _d domain
  597. * \param _aor adress of record, used as hash source for the lock slot
  598. */
  599. void lock_udomain(udomain_t* _d, str* _aor)
  600. {
  601. unsigned int sl;
  602. if (db_mode!=DB_ONLY)
  603. {
  604. sl = ul_get_aorhash(_aor) & (_d->size - 1);
  605. #ifdef GEN_LOCK_T_PREFERED
  606. lock_get(_d->table[sl].lock);
  607. #else
  608. ul_lock_idx(_d->table[sl].lockidx);
  609. #endif
  610. }
  611. }
  612. /*!
  613. * \brief Release lock for a domain
  614. * \param _d domain
  615. * \param _aor address of record, uses as hash source for the lock slot
  616. */
  617. void unlock_udomain(udomain_t* _d, str* _aor)
  618. {
  619. unsigned int sl;
  620. if (db_mode!=DB_ONLY)
  621. {
  622. sl = ul_get_aorhash(_aor) & (_d->size - 1);
  623. #ifdef GEN_LOCK_T_PREFERED
  624. lock_release(_d->table[sl].lock);
  625. #else
  626. ul_release_idx(_d->table[sl].lockidx);
  627. #endif
  628. }
  629. }
  630. /*!
  631. * \brief Get lock for a slot
  632. * \param _d domain
  633. * \param i slot number
  634. */
  635. void lock_ulslot(udomain_t* _d, int i)
  636. {
  637. if (db_mode!=DB_ONLY)
  638. #ifdef GEN_LOCK_T_PREFERED
  639. lock_get(_d->table[i].lock);
  640. #else
  641. ul_lock_idx(_d->table[i].lockidx);
  642. #endif
  643. }
  644. /*!
  645. * \brief Release lock for a slot
  646. * \param _d domain
  647. * \param i slot number
  648. */
  649. void unlock_ulslot(udomain_t* _d, int i)
  650. {
  651. if (db_mode!=DB_ONLY)
  652. #ifdef GEN_LOCK_T_PREFERED
  653. lock_release(_d->table[i].lock);
  654. #else
  655. ul_release_idx(_d->table[i].lockidx);
  656. #endif
  657. }
  658. /*!
  659. * \brief Create and insert a new record
  660. * \param _d domain to insert the new record
  661. * \param _aor address of the record
  662. * \param _r new created record
  663. * \return return 0 on success, -1 on failure
  664. */
  665. int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
  666. {
  667. if (db_mode!=DB_ONLY) {
  668. if (mem_insert_urecord(_d, _aor, _r) < 0) {
  669. LM_ERR("inserting record failed\n");
  670. return -1;
  671. }
  672. } else {
  673. get_static_urecord( _d, _aor, _r);
  674. }
  675. return 0;
  676. }
  677. /*!
  678. * \brief Obtain a urecord pointer if the urecord exists in domain
  679. * \param _d domain to search the record
  680. * \param _aor address of record
  681. * \param _r new created record
  682. * \return 0 if a record was found, 1 if nothing could be found
  683. */
  684. int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
  685. {
  686. unsigned int sl, i, aorhash;
  687. urecord_t* r;
  688. if (db_mode!=DB_ONLY) {
  689. /* search in cache */
  690. aorhash = ul_get_aorhash(_aor);
  691. sl = aorhash&(_d->size-1);
  692. r = _d->table[sl].first;
  693. for(i = 0; r!=NULL && i < _d->table[sl].n; i++) {
  694. if((r->aorhash==aorhash) && (r->aor.len==_aor->len)
  695. && !memcmp(r->aor.s,_aor->s,_aor->len)){
  696. *_r = r;
  697. return 0;
  698. }
  699. r = r->next;
  700. }
  701. } else {
  702. /* search in DB */
  703. r = db_load_urecord(_d, _aor);
  704. if (r) {
  705. *_r = r;
  706. return 0;
  707. }
  708. }
  709. return 1; /* Nothing found */
  710. }
  711. /*!
  712. * \brief Obtain a urecord pointer if the urecord exists in domain (lock slot)
  713. * \param _d domain to search the record
  714. * \param _aorhash hash id for address of record
  715. * \param _ruid record internal unique id
  716. * \param _r store pointer to location record
  717. * \param _c store pointer to contact structure
  718. * \return 0 if a record was found, 1 if nothing could be found
  719. */
  720. int get_urecord_by_ruid(udomain_t* _d, unsigned int _aorhash,
  721. str *_ruid, struct urecord** _r, struct ucontact** _c)
  722. {
  723. unsigned int sl, i;
  724. urecord_t* r;
  725. ucontact_t* c;
  726. sl = _aorhash&(_d->size-1);
  727. lock_ulslot(_d, sl);
  728. if (db_mode!=DB_ONLY) {
  729. /* search in cache */
  730. r = _d->table[sl].first;
  731. for(i = 0; i < _d->table[sl].n; i++) {
  732. if(r->aorhash==_aorhash) {
  733. c = r->contacts;
  734. while(c) {
  735. if(c->ruid.len==_ruid->len
  736. && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
  737. *_r = r;
  738. *_c = c;
  739. return 0;
  740. }
  741. }
  742. }
  743. r = r->next;
  744. }
  745. } else {
  746. /* search in DB */
  747. r = db_load_urecord_by_ruid(_d, _ruid);
  748. if (r) {
  749. if(r->aorhash==_aorhash) {
  750. c = r->contacts;
  751. while(c) {
  752. if(c->ruid.len==_ruid->len
  753. && !memcmp(c->ruid.s, _ruid->s, _ruid->len)) {
  754. *_r = r;
  755. *_c = c;
  756. return 0;
  757. }
  758. }
  759. }
  760. }
  761. }
  762. unlock_ulslot(_d, (_aorhash & (_d->size - 1)));
  763. return -1; /* Nothing found */
  764. }
  765. /*!
  766. * \brief Delete a urecord from domain
  767. * \param _d domain where the record should be deleted
  768. * \param _aor address of record
  769. * \param _r deleted record
  770. * \return 0 on success, -1 if the record could not be deleted
  771. */
  772. int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r)
  773. {
  774. struct ucontact* c, *t;
  775. if (db_mode==DB_ONLY) {
  776. if (_r==0)
  777. get_static_urecord( _d, _aor, &_r);
  778. if (db_delete_urecord(_d, _r)<0) {
  779. LM_ERR("DB delete failed\n");
  780. return -1;
  781. }
  782. free_urecord(_r);
  783. return 0;
  784. }
  785. if (_r==0) {
  786. if (get_urecord(_d, _aor, &_r) > 0) {
  787. return 0;
  788. }
  789. }
  790. c = _r->contacts;
  791. while(c) {
  792. t = c;
  793. c = c->next;
  794. if (delete_ucontact(_r, t) < 0) {
  795. LM_ERR("deleting contact failed\n");
  796. return -1;
  797. }
  798. }
  799. release_urecord(_r);
  800. return 0;
  801. }