00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00038 #include "udomain.h"
00039 #include <string.h>
00040 #include "../../parser/parse_methods.h"
00041 #include "../../mem/shm_mem.h"
00042 #include "../../dprint.h"
00043 #include "../../lib/srdb1/db.h"
00044 #include "../../socket_info.h"
00045 #include "../../ut.h"
00046 #include "../../hashes.h"
00047 #include "p_usrloc_mod.h"
00048 #include "utime.h"
00049 #include "ul_db_layer.h"
00050
00051
00052 #ifdef STATISTICS
00053 static char *build_stat_name( str* domain, char *var_name)
00054 {
00055 int n;
00056 char *s;
00057 char *p;
00058
00059 n = domain->len + 1 + strlen(var_name) + 1;
00060 s = (char*)shm_malloc( n );
00061 if (s==0) {
00062 LM_ERR("no more shm mem\n");
00063 return 0;
00064 }
00065 memcpy( s, domain->s, domain->len);
00066 p = s + domain->len;
00067 *(p++) = '-';
00068 memcpy( p , var_name, strlen(var_name));
00069 p += strlen(var_name);
00070 *(p++) = 0;
00071 return s;
00072 }
00073 #endif
00074
00075
00084 int new_udomain(str* _n, int _s, udomain_t** _d)
00085 {
00086 int i;
00087 #ifdef STATISTICS
00088 char *name;
00089 #endif
00090
00091
00092
00093
00094
00095 *_d = (udomain_t*)shm_malloc(sizeof(udomain_t));
00096 if (!(*_d)) {
00097 LM_ERR("new_udomain(): No memory left\n");
00098 goto error0;
00099 }
00100 memset(*_d, 0, sizeof(udomain_t));
00101
00102 (*_d)->table = (hslot_t*)shm_malloc(sizeof(hslot_t) * _s);
00103 if (!(*_d)->table) {
00104 LM_ERR("no memory left 2\n");
00105 goto error1;
00106 }
00107
00108 (*_d)->name = _n;
00109
00110 for(i = 0; i < _s; i++) {
00111 init_slot(*_d, &((*_d)->table[i]), i);
00112 }
00113
00114 (*_d)->size = _s;
00115
00116 #ifdef STATISTICS
00117
00118 if ( (name=build_stat_name(_n,"users"))==0 || register_stat("usrloc",
00119 name, &(*_d)->users, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
00120 LM_ERR("failed to add stat variable\n");
00121 goto error2;
00122 }
00123 if ( (name=build_stat_name(_n,"contacts"))==0 || register_stat("usrloc",
00124 name, &(*_d)->contacts, STAT_NO_RESET|STAT_SHM_NAME)!=0 ) {
00125 LM_ERR("failed to add stat variable\n");
00126 goto error2;
00127 }
00128 if ( (name=build_stat_name(_n,"expires"))==0 || register_stat("usrloc",
00129 name, &(*_d)->expires, STAT_SHM_NAME)!=0 ) {
00130 LM_ERR("failed to add stat variable\n");
00131 goto error2;
00132 }
00133 #endif
00134
00135 return 0;
00136
00137 #ifdef STATISTICS
00138 error2:
00139 shm_free((*_d)->table);
00140 #endif
00141 error1:
00142 shm_free(*_d);
00143 error0:
00144 return -1;
00145 }
00146
00147
00152 void free_udomain(udomain_t* _d)
00153 {
00154 int i;
00155
00156 if (_d->table) {
00157 for(i = 0; i < _d->size; i++) {
00158 lock_ulslot(_d, i);
00159 deinit_slot(_d->table + i);
00160 unlock_ulslot(_d, i);
00161 }
00162 shm_free(_d->table);
00163 }
00164 shm_free(_d);
00165 }
00166
00167
00174 static inline void get_static_urecord(udomain_t* _d, str* _aor,
00175 struct urecord** _r)
00176 {
00177 static struct urecord r;
00178
00179 memset( &r, 0, sizeof(struct urecord) );
00180 r.aor = *_aor;
00181 r.domain = _d->name;
00182 *_r = &r;
00183 }
00184
00185
00189 void print_udomain(FILE* _f, udomain_t* _d)
00190 {
00191 int i;
00192 int max=0, slot=0, n=0;
00193 struct urecord* r;
00194 fprintf(_f, "---Domain---\n");
00195 fprintf(_f, "name : '%.*s'\n", _d->name->len, ZSW(_d->name->s));
00196 fprintf(_f, "size : %d\n", _d->size);
00197 fprintf(_f, "table: %p\n", _d->table);
00198
00199 fprintf(_f, "\n");
00200 for(i=0; i<_d->size; i++)
00201 {
00202 r = _d->table[i].first;
00203 n += _d->table[i].n;
00204 if(max<_d->table[i].n){
00205 max= _d->table[i].n;
00206 slot = i;
00207 }
00208 while(r) {
00209 print_urecord(_f, r);
00210 r = r->next;
00211 }
00212 }
00213 fprintf(_f, "\nMax slot: %d (%d/%d)\n", max, slot, n);
00214 fprintf(_f, "\n---/Domain---\n");
00215 }
00216
00217
00228 static inline ucontact_info_t* dbrow2info( db_val_t *vals, str *contact)
00229 {
00230 static ucontact_info_t ci;
00231 static str callid, ua, received, host, path;
00232 int port, proto;
00233 char *p;
00234
00235 memset( &ci, 0, sizeof(ucontact_info_t));
00236
00237 contact->s = (char*)VAL_STRING(vals);
00238 if (VAL_NULL(vals) || contact->s==0 || contact->s[0]==0) {
00239 LM_CRIT("bad contact\n");
00240 return 0;
00241 }
00242 contact->len = strlen(contact->s);
00243
00244 if (VAL_NULL(vals+1)) {
00245 LM_CRIT("empty expire\n");
00246 return 0;
00247 }
00248 ci.expires = VAL_TIME(vals+1);
00249
00250 if (VAL_NULL(vals+2)) {
00251 LM_CRIT("empty q\n");
00252 return 0;
00253 }
00254 ci.q = double2q(VAL_DOUBLE(vals+2));
00255
00256 if (VAL_NULL(vals+4)) {
00257 LM_CRIT("empty cseq_nr\n");
00258 return 0;
00259 }
00260 ci.cseq = VAL_INT(vals+4);
00261
00262 callid.s = (char*)VAL_STRING(vals+3);
00263 if (VAL_NULL(vals+3) || !callid.s || !callid.s[0]) {
00264 LM_CRIT("bad callid\n");
00265 return 0;
00266 }
00267 callid.len = strlen(callid.s);
00268 ci.callid = &callid;
00269
00270 if (VAL_NULL(vals+5)) {
00271 LM_CRIT("empty flag\n");
00272 return 0;
00273 }
00274 ci.flags = VAL_BITMAP(vals+5);
00275
00276 if (VAL_NULL(vals+6)) {
00277 LM_CRIT("empty cflag\n");
00278 return 0;
00279 }
00280 ci.cflags = VAL_BITMAP(vals+6);
00281
00282 ua.s = (char*)VAL_STRING(vals+7);
00283 if (VAL_NULL(vals+7) || !ua.s || !ua.s[0]) {
00284 ua.s = 0;
00285 ua.len = 0;
00286 } else {
00287 ua.len = strlen(ua.s);
00288 }
00289 ci.user_agent = &ua;
00290
00291 received.s = (char*)VAL_STRING(vals+8);
00292 if (VAL_NULL(vals+8) || !received.s || !received.s[0]) {
00293 received.len = 0;
00294 received.s = 0;
00295 } else {
00296 received.len = strlen(received.s);
00297 }
00298 ci.received = received;
00299
00300 path.s = (char*)VAL_STRING(vals+9);
00301 if (VAL_NULL(vals+9) || !path.s || !path.s[0]) {
00302 path.len = 0;
00303 path.s = 0;
00304 } else {
00305 path.len = strlen(path.s);
00306 }
00307 ci.path= &path;
00308
00309
00310 p = (char*)VAL_STRING(vals+10);
00311 if (VAL_NULL(vals+10) || p==0 || p[0]==0){
00312 ci.sock = 0;
00313 } else {
00314 if (parse_phostport( p, &host.s, &host.len,
00315 &port, &proto)!=0){
00316 LM_ERR("bad socket <%s>\n", p);
00317 return 0;
00318 }
00319 ci.sock = grep_sock_info( &host, (unsigned short)port, proto);
00320 if (ci.sock==0) {
00321 LM_INFO("non-local socket <%s>...ignoring\n", p);
00322 }
00323 }
00324
00325
00326 if (VAL_NULL(vals+11)) {
00327 ci.methods = ALL_METHODS;
00328 } else {
00329 ci.methods = VAL_BITMAP(vals+11);
00330 }
00331
00332
00333 if (!VAL_NULL(vals+12)) {
00334 ci.last_modified = VAL_TIME(vals+12);
00335 }
00336
00337 return &ci;
00338 }
00339
00340
00341
00349 urecord_t* db_load_urecord(udomain_t* _d, str *_aor)
00350 {
00351 ucontact_info_t *ci;
00352 db_key_t columns[13];
00353 db_key_t keys[2];
00354 db_key_t order;
00355 db_val_t vals[2];
00356 db1_res_t* res = NULL;
00357 str contact;
00358 char *domain;
00359 int i;
00360
00361 urecord_t* r;
00362 ucontact_t* c;
00363
00364 keys[0] = &user_col;
00365 vals[0].type = DB1_STR;
00366 vals[0].nul = 0;
00367 if (use_domain) {
00368 keys[1] = &domain_col;
00369 vals[1].type = DB1_STR;
00370 vals[1].nul = 0;
00371 domain = memchr(_aor->s, '@', _aor->len);
00372 vals[0].val.str_val.s = _aor->s;
00373 if (domain==0) {
00374 vals[0].val.str_val.len = 0;
00375 vals[1].val.str_val = *_aor;
00376 } else {
00377 vals[0].val.str_val.len = domain - _aor->s;
00378 vals[1].val.str_val.s = domain+1;
00379 vals[1].val.str_val.len = _aor->s + _aor->len - domain - 1;
00380 }
00381 } else {
00382 vals[0].val.str_val = *_aor;
00383 }
00384
00385 columns[0] = &contact_col;
00386 columns[1] = &expires_col;
00387 columns[2] = &q_col;
00388 columns[3] = &callid_col;
00389 columns[4] = &cseq_col;
00390 columns[5] = &flags_col;
00391 columns[6] = &cflags_col;
00392 columns[7] = &user_agent_col;
00393 columns[8] = &received_col;
00394 columns[9] = &path_col;
00395 columns[10] = &sock_col;
00396 columns[11] = &methods_col;
00397 columns[12] = &last_mod_col;
00398
00399 if (desc_time_order)
00400 order = &last_mod_col;
00401 else
00402 order = &q_col;
00403
00404 if (ul_db_layer_query(_d, &vals[0].val.str_val, &vals[1].val.str_val, keys, 0, vals, columns, (use_domain)?2:1, 13, order,
00405 &res) < 0) {
00406 LM_ERR("db_query failed\n");
00407 return 0;
00408 }
00409
00410 if (RES_ROW_N(res) == 0) {
00411 LM_DBG("aor %.*s not found in table %.*s\n",_aor->len, _aor->s, _d->name->len, _d->name->s);
00412
00413 ul_db_layer_free_result(_d, res);
00414 return 0;
00415 }
00416
00417 r = 0;
00418
00419 for(i = 0; i < RES_ROW_N(res); i++) {
00420 ci = dbrow2info( ROW_VALUES(RES_ROWS(res) + i), &contact);
00421 if (ci==0) {
00422 LM_ERR("skipping record for %.*s in table %s\n",
00423 _aor->len, _aor->s, _d->name->s);
00424 continue;
00425 }
00426
00427 if ( r==0 )
00428 get_static_urecord( _d, _aor, &r);
00429
00430 if ( (c=mem_insert_ucontact(r, &contact, ci)) == 0) {
00431 LM_ERR("mem_insert failed\n");
00432 free_urecord(r);
00433 ul_db_layer_free_result(_d, res);
00434 return 0;
00435 }
00436
00437
00438
00439 c->state = CS_SYNC;
00440 }
00441
00442 ul_db_layer_free_result(_d, res);
00443 return r;
00444 }
00445
00446
00452 int db_timer_udomain(udomain_t* _d)
00453 {
00454 db_key_t keys[2];
00455 db_op_t ops[2];
00456 db_val_t vals[2];
00457
00458 keys[0] = &expires_col;
00459 ops[0] = "<";
00460 vals[0].type = DB1_DATETIME;
00461 vals[0].nul = 0;
00462 vals[0].val.time_val = act_time + 1;
00463
00464 keys[1] = &expires_col;
00465 ops[1] = "!=";
00466 vals[1].type = DB1_DATETIME;
00467 vals[1].nul = 0;
00468 vals[1].val.time_val = 0;
00469
00470 LM_INFO("using sp-ul_db database interface, expires is not implemented");
00471
00472 return 0;
00473 }
00474
00475
00476
00484 int mem_insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00485 {
00486 int sl;
00487
00488 if (new_urecord(_d->name, _aor, _r) < 0) {
00489 LM_ERR("creating urecord failed\n");
00490 return -1;
00491 }
00492
00493 sl = ((*_r)->aorhash)&(_d->size-1);
00494 slot_add(&_d->table[sl], *_r);
00495 update_stat( _d->users, 1);
00496 return 0;
00497 }
00498
00499
00505 void mem_delete_urecord(udomain_t* _d, struct urecord* _r)
00506 {
00507 slot_rem(_r->slot, _r);
00508 free_urecord(_r);
00509 update_stat( _d->users, -1);
00510 }
00511
00512
00517 void mem_timer_udomain(udomain_t* _d)
00518 {
00519 struct urecord* ptr, *t;
00520 int i;
00521
00522 for(i=0; i<_d->size; i++)
00523 {
00524 lock_ulslot(_d, i);
00525
00526 ptr = _d->table[i].first;
00527
00528 while(ptr) {
00529 timer_urecord(ptr);
00530
00531 if (ptr->contacts == 0) {
00532 t = ptr;
00533 ptr = ptr->next;
00534 mem_delete_urecord(_d, t);
00535 } else {
00536 ptr = ptr->next;
00537 }
00538 }
00539 unlock_ulslot(_d, i);
00540 }
00541 }
00542
00543
00549 void lock_udomain(udomain_t* _d, str* _aor)
00550 {
00551 unsigned int sl;
00552 if (db_mode!=DB_ONLY)
00553 {
00554 sl = core_hash(_aor, 0, _d->size);
00555
00556 #ifdef GEN_LOCK_T_PREFERED
00557 lock_get(_d->table[sl].lock);
00558 #else
00559 ul_lock_idx(_d->table[sl].lockidx);
00560 #endif
00561 }
00562 }
00563
00564
00570 void unlock_udomain(udomain_t* _d, str* _aor)
00571 {
00572 unsigned int sl;
00573 if (db_mode!=DB_ONLY)
00574 {
00575 sl = core_hash(_aor, 0, _d->size);
00576 #ifdef GEN_LOCK_T_PREFERED
00577 lock_release(_d->table[sl].lock);
00578 #else
00579 ul_release_idx(_d->table[sl].lockidx);
00580 #endif
00581 }
00582 }
00583
00589 void lock_ulslot(udomain_t* _d, int i)
00590 {
00591 if (db_mode!=DB_ONLY)
00592 #ifdef GEN_LOCK_T_PREFERED
00593 lock_get(_d->table[i].lock);
00594 #else
00595 ul_lock_idx(_d->table[i].lockidx);
00596 #endif
00597 }
00598
00599
00605 void unlock_ulslot(udomain_t* _d, int i)
00606 {
00607 if (db_mode!=DB_ONLY)
00608 #ifdef GEN_LOCK_T_PREFERED
00609 lock_release(_d->table[i].lock);
00610 #else
00611 ul_release_idx(_d->table[i].lockidx);
00612 #endif
00613 }
00614
00615
00616
00624 int insert_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00625 {
00626 if (db_mode!=DB_ONLY) {
00627 if (mem_insert_urecord(_d, _aor, _r) < 0) {
00628 LM_ERR("inserting record failed\n");
00629 return -1;
00630 }
00631 } else {
00632 get_static_urecord( _d, _aor, _r);
00633 }
00634 return 0;
00635 }
00636
00637
00645 int get_urecord(udomain_t* _d, str* _aor, struct urecord** _r)
00646 {
00647 unsigned int sl, i, aorhash;
00648 urecord_t* r;
00649 if (db_mode!=DB_ONLY) {
00650
00651 aorhash = core_hash(_aor, 0, 0);
00652 sl = aorhash&(_d->size-1);
00653 r = _d->table[sl].first;
00654
00655 for(i = 0; i < _d->table[sl].n; i++) {
00656 if((r->aorhash==aorhash) && (r->aor.len==_aor->len)
00657 && !memcmp(r->aor.s,_aor->s,_aor->len)){
00658 *_r = r;
00659 return 0;
00660 }
00661
00662 r = r->next;
00663 }
00664 } else {
00665
00666 r = db_load_urecord(_d, _aor);
00667 if (r) {
00668 *_r = r;
00669 return 0;
00670 }
00671 }
00672
00673 return 1;
00674 }
00675
00676
00684 int delete_urecord(udomain_t* _d, str* _aor, struct urecord* _r)
00685 {
00686 struct ucontact* c, *t;
00687
00688 if (db_mode==DB_ONLY) {
00689 if (_r==0)
00690 get_static_urecord( _d, _aor, &_r);
00691 if (db_delete_urecord(_d, _r)<0) {
00692 LM_ERR("DB delete failed\n");
00693 return -1;
00694 }
00695 free_urecord(_r);
00696 return 0;
00697 }
00698
00699 if (_r==0) {
00700 if (get_urecord(_d, _aor, &_r) > 0) {
00701 return 0;
00702 }
00703 }
00704
00705 c = _r->contacts;
00706 while(c) {
00707 t = c;
00708 c = c->next;
00709 if (delete_ucontact(_r, t) < 0) {
00710 LM_ERR("deleting contact failed\n");
00711 return -1;
00712 }
00713 }
00714 release_urecord(_r);
00715 return 0;
00716 }