📄 urecord.c
字号:
/* * $Id: urecord.c,v 1.14 2006/07/04 11:19:51 bogdan_iancu Exp $ * * Usrloc record structure * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * --------- * 2003-03-12 added replication mark and zombie state support (nils) * 2004-03-17 generic callbacks added (bogdan) * 2004-06-07 updated to the new DB api (andrei) */#include "urecord.h"#include <string.h>#include "../../mem/shm_mem.h"#include "../../dprint.h"#include "../../ut.h"#include "ul_mod.h"#include "utime.h"#include "notify.h"#include "ul_callback.h"int matching_mode = CONTACT_ONLY;int cseq_delay = 20;/* * Create and initialize new record structure */int new_urecord(str* _dom, str* _aor, urecord_t** _r){ *_r = (urecord_t*)shm_malloc(sizeof(urecord_t)); if (*_r == 0) { LOG(L_ERR, "ERROR:usrloc:new_urecord: no shm memory left\n"); return -1; } memset(*_r, 0, sizeof(urecord_t)); (*_r)->aor.s = (char*)shm_malloc(_aor->len); if ((*_r)->aor.s == 0) { LOG(L_ERR, "ERROR:usrloc:new_urecord: no shm memory left\n"); shm_free(*_r); return -2; } memcpy((*_r)->aor.s, _aor->s, _aor->len); (*_r)->aor.len = _aor->len; (*_r)->domain = _dom; return 0;}/* * Free all memory used by the given structure * The structure must be removed from all linked * lists first */void free_urecord(urecord_t* _r){ notify_cb_t* watcher; ucontact_t* ptr; while(_r->watchers) { watcher = _r->watchers; _r->watchers = watcher->next; shm_free(watcher); } while(_r->contacts) { ptr = _r->contacts; _r->contacts = _r->contacts->next; free_ucontact(ptr); } /* if mem cache is not used, the urecord struct is static*/ if (db_mode!=DB_ONLY) { if (_r->aor.s) shm_free(_r->aor.s); shm_free(_r); }}/* * Print a record */void print_urecord(FILE* _f, urecord_t* _r){ ucontact_t* ptr; fprintf(_f, "...Record(%p)...\n", _r); fprintf(_f, "domain: '%.*s'\n", _r->domain->len, ZSW(_r->domain->s)); fprintf(_f, "aor : '%.*s'\n", _r->aor.len, ZSW(_r->aor.s)); if (_r->contacts) { ptr = _r->contacts; while(ptr) { print_ucontact(_f, ptr); ptr = ptr->next; } } fprintf(_f, ".../Record...\n");}/* * Add a new contact * Contacts are ordered by: 1) q * 2) descending modification time */ucontact_t* mem_insert_ucontact(urecord_t* _r, str* _c, ucontact_info_t* _ci){ ucontact_t* ptr, *prev = 0; ucontact_t* c; if ( (c=new_ucontact(_r->domain, &_r->aor, _c, _ci)) == 0) { LOG(L_ERR, "ERROR:usrloc:mem_insert_ucontact: failed to " "create new contact\n"); return 0; } if_update_stat( _r->slot, _r->slot->d->contacts, 1); ptr = _r->contacts; if (!desc_time_order) { while(ptr) { if (ptr->q < c->q) break; prev = ptr; ptr = ptr->next; } } if (ptr) { if (!ptr->prev) { ptr->prev = c; c->next = ptr; _r->contacts = c; } else { c->next = ptr; c->prev = ptr->prev; ptr->prev->next = c; ptr->prev = c; } } else if (prev) { prev->next = c; c->prev = prev; } else { _r->contacts = c; } return c;}/* * Remove the contact from lists */void mem_remove_ucontact(urecord_t* _r, ucontact_t* _c){ if (_c->prev) { _c->prev->next = _c->next; if (_c->next) { _c->next->prev = _c->prev; } } else { _r->contacts = _c->next; if (_c->next) { _c->next->prev = 0; } }} /* * Remove contact from the list and delete */void mem_delete_ucontact(urecord_t* _r, ucontact_t* _c){ mem_remove_ucontact(_r, _c); if_update_stat( _r->slot, _r->slot->d->contacts, -1); free_ucontact(_c);}/* * This timer routine is used when * db_mode is set to NO_DB */static inline int nodb_timer(urecord_t* _r){ ucontact_t* ptr, *t; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); notify_watchers(_r, ptr, PRES_OFFLINE); DBG("DEBUG:usrloc:nodb_timer: Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; mem_delete_ucontact(_r, t); update_stat( _r->slot->d->expires, 1); } else { ptr = ptr->next; } } return 0;}/* * This routine is used when db_mode is * set to WRITE_THROUGH */static inline int wt_timer(urecord_t* _r){ ucontact_t* ptr, *t; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } notify_watchers(_r, ptr, PRES_OFFLINE); DBG("DEBUG:usrloc:wt_timer: Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wt_timer(): Error while deleting contact from " "database\n"); } mem_delete_ucontact(_r, t); update_stat( _r->slot->d->expires, 1); } else { ptr = ptr->next; } } return 0;}/* * Write-back timer */static inline int wb_timer(urecord_t* _r){ ucontact_t* ptr, *t; int op; ptr = _r->contacts; while(ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(UL_CONTACT_EXPIRE)) { run_ul_callbacks( UL_CONTACT_EXPIRE, ptr); } notify_watchers(_r, ptr, PRES_OFFLINE); DBG("DEBUG:usrloc:wb_timer: Binding '%.*s','%.*s' has expired\n", ptr->aor->len, ZSW(ptr->aor->s), ptr->c.len, ZSW(ptr->c.s)); update_stat( _r->slot->d->expires, 1); t = ptr; ptr = ptr->next; /* Should we remove the contact from the database ? */ if (st_expired_ucontact(t) == 1) { if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wb_timer: Can't delete contact from " "the database\n"); } } mem_delete_ucontact(_r, t); } else { /* Determine the operation we have to do */ op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_insert_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer: Error while inserting contact " "into database\n"); } break; case 2: /* update */ if (db_update_ucontact(ptr) < 0) { LOG(L_ERR,"wb_timer: Error while updating contact in db\n"); } break; } ptr = ptr->next; } } return 0;}int timer_urecord(urecord_t* _r){ switch(db_mode) { case NO_DB: return nodb_timer(_r); case WRITE_THROUGH: return wt_timer(_r); case WRITE_BACK: return wb_timer(_r); } return 0; /* Makes gcc happy */}int db_delete_urecord(urecord_t* _r){ db_key_t keys[2]; db_val_t vals[2]; char* dom; keys[0] = user_col.s; keys[1] = domain_col.s; vals[0].type = DB_STR; vals[0].nul = 0; vals[0].val.str_val.s = _r->aor.s; vals[0].val.str_val.len = _r->aor.len; if (use_domain) { dom = q_memchr(_r->aor.s, '@', _r->aor.len); vals[0].val.str_val.len = dom - _r->aor.s; vals[1].type = DB_STR; vals[1].nul = 0; vals[1].val.str_val.s = dom + 1; vals[1].val.str_val.len = _r->aor.s + _r->aor.len - dom - 1; } if (ul_dbf.use_table(ul_dbh, _r->domain->s) < 0) { LOG(L_ERR, "ERROR:usrloc:db_delete_urecord: use_table failed\n"); return -1; } if (ul_dbf.delete(ul_dbh, keys, 0, vals, (use_domain) ? (2) : (1)) < 0) { LOG(L_ERR, "ERROR:usrloc:db_delete_urecord:" " failed to delete from database\n"); return -1; } return 0;}/* * Release urecord previously obtained * through get_urecord */void release_urecord(urecord_t* _r){ if (db_mode==DB_ONLY) { free_urecord(_r); } else if (_r->contacts == 0) { mem_delete_urecord(_r->slot->d, _r); }}/* * Create and insert new contact * into urecord */int insert_ucontact(urecord_t* _r, str* _contact, ucontact_info_t* _ci, ucontact_t** _c){ if ( ((*_c)=mem_insert_ucontact(_r, _contact, _ci)) == 0) { LOG(L_ERR, "ERROR:usrloc:insert_ucontact: failed to insert contact\n"); return -1; } notify_watchers(_r, (*_c), ((*_c)->expires > 0) ? PRES_ONLINE : PRES_OFFLINE); if (exists_ulcb_type(UL_CONTACT_INSERT)) { run_ul_callbacks( UL_CONTACT_INSERT, *_c); } if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { if (db_insert_ucontact(*_c) < 0) { LOG(L_ERR, "ERROR:usrloc:insert_ucontact: failed to insert " "in database\n"); } (*_c)->state = CS_SYNC; } return 0;}/* * Delete ucontact from urecord */int delete_ucontact(urecord_t* _r, struct ucontact* _c){ if (exists_ulcb_type(UL_CONTACT_DELETE)) { run_ul_callbacks( UL_CONTACT_DELETE, _c); } notify_watchers(_r, _c, PRES_OFFLINE); if (st_delete_ucontact(_c) > 0) { if (db_mode == WRITE_THROUGH || db_mode==DB_ONLY) { if (db_delete_ucontact(_c) < 0) { LOG(L_ERR, "delete_ucontact(): Can't remove contact from " "database\n"); } } mem_delete_ucontact(_r, _c); } return 0;}static inline struct ucontact* contact_match( ucontact_t* ptr, str* _c){ while(ptr) { if ((_c->len == ptr->c.len) && !memcmp(_c->s, ptr->c.s, _c->len)) { return ptr; } ptr = ptr->next; } return 0;}static inline struct ucontact* contact_callid_match( ucontact_t* ptr, str* _c, str *_callid){ while(ptr) { if ( (_c->len==ptr->c.len) && (_callid->len==ptr->callid.len) && !memcmp(_c->s, ptr->c.s, _c->len) && !memcmp(_callid->s, ptr->callid.s, _callid->len) ) { return ptr; } ptr = ptr->next; } return 0;}/* * Get pointer to ucontact with given contact * Returns: * 0 - found * 1 - not found * -1 - invalid found * -2 - found, but to be skipped (same cseq) */int get_ucontact(urecord_t* _r, str* _c, str* _callid, int _cseq, struct ucontact** _co){ ucontact_t* ptr; int no_callid; ptr = 0; no_callid = 0; switch (matching_mode) { case CONTACT_ONLY: ptr = contact_match( _r->contacts, _c); break; case CONTACT_CALLID: ptr = contact_callid_match( _r->contacts, _c, _callid); no_callid = 1; break; default: LOG(L_CRIT,"BUG:usrloc:get_ucontact: unknown matching_mode %d\n", matching_mode); return -1; } if (ptr) { /* found -> check callid and cseq */ if ( no_callid || (ptr->callid.len==_callid->len && memcmp(_callid->s, ptr->callid.s, _callid->len)==0 ) ) { if (_cseq<ptr->cseq) return -1; if (_cseq==ptr->cseq) { get_act_time(); return (ptr->last_modified+cseq_delay>act_time)?-2:-1; } } *_co = ptr; return 0; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -