/* * Return true if the AOR in the Request-URI is registered, * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ int registered(struct sip_msg* _m, char* _t, char* _s) { str uid; urecord_t* r; ucontact_t* ptr; int res; if (get_to_uid(&uid, _m) < 0) return -1; ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &uid, &r); if (res < 0) { ul.unlock_udomain((udomain_t*)_t); LOG(L_ERR, "registered(): Error while querying usrloc\n"); return -1; } if (res == 0) { ptr = r->contacts; while (ptr && !VALID_CONTACT(ptr, act_time)) { ptr = ptr->next; } if (ptr) { ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' found in usrloc\n", uid.len, ZSW(uid.s)); return 1; } } ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' not found in usrloc\n", uid.len, ZSW(uid.s)); return -1; }
/*! \brief * Calculate the length of buffer needed to * print contacts */ static inline unsigned int calc_buf_len(ucontact_t* c) { unsigned int len; int qlen; len = 0; while(c) { if (VALID_CONTACT(c, act_time)) { if (len) len += CONTACT_SEP_LEN; len += 2 /* < > */ + c->c.len; qlen = len_q(c->q); if (qlen) len += Q_PARAM_LEN + qlen; len += EXPIRES_PARAM_LEN + INT2STR_MAX_LEN; if (c->received.s) { len += 1 /* ; */ + rcv_param.len + 1 /* = */ + 1 /* dquote */ + c->received.len + 1 /* dquote */ ; } } c = c->next; } if (len) len += CONTACT_BEGIN_LEN + CRLF_LEN; return len; }
/*! * \brief Write through timer, used for WRITE_THROUGH db_mode * * Write through timer, used for WRITE_THROUGH db_mode. Process all * contacts from the record, delete all expired ones from the DB. * \param _r processed record * \note currently unused, this mode is also handled by the wb_timer */ static inline void 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); } LM_DBG("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) { LM_ERR("deleting contact from database failed\n"); } mem_delete_ucontact(_r, t); update_stat( _r->slot->d->expires, 1); } else { ptr = ptr->next; } } }
/*! \brief * Calculate the length of buffer needed to * print contacts */ static inline unsigned int calc_buf_len(impurecord_t* impurec) { unsigned int len; int qlen; int i=0; ucontact_t* c; len = 0; while (i<MAX_CONTACTS_PER_IMPU && (c=impurec->newcontacts[i])) { if (VALID_CONTACT(c, act_time)) { if (len) len += CONTACT_SEP_LEN; len += 2 /* < > */ + c->c.len; qlen = len_q(c->q); if (qlen) len += Q_PARAM_LEN + qlen; len += EXPIRES_PARAM_LEN + INT2STR_MAX_LEN; if (c->received.s) { len += 1 /* ; */ + rcv_param.len + 1 /* = */ + 1 /* dquote */ + c->received.len + 1 /* dquote */ ; } } i++; } if (len) len += CONTACT_BEGIN_LEN + CRLF_LEN; return len; }
/*! * \brief Write-back timer, used for WRITE_BACK db_mode * * Write-back timer, used for WRITE_BACK db_mode. Process * all contacts from the record, delete expired ones from the DB. * Furthermore it updates changed contacts, and also insert new * ones in the DB. * \param _r processed record */ static inline void wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; cstate_t old_state; 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); } LM_DBG("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) { LM_ERR("failed to delete contact from the database\n"); } } mem_delete_ucontact(_r, t); } else { /* Determine the operation we have to do */ old_state = ptr->state; op = st_flush_ucontact(ptr); switch(op) { case 0: /* do nothing, contact is synchronized */ break; case 1: /* insert */ if (db_insert_ucontact(ptr) < 0) { LM_ERR("inserting contact into database failed\n"); ptr->state = old_state; } break; case 2: /* update */ if (db_update_ucontact(ptr) < 0) { LM_ERR("updating contact in db failed\n"); ptr->state = old_state; } break; } ptr = ptr->next; } } }
/*! \brief the is_registered() function * Return true if the AOR in the Request-URI is registered, * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ int registered(struct sip_msg* _m, udomain_t* _d, str* _uri) { str uri, aor; urecord_t* r; ucontact_t* ptr; int res; int_str match_callid=(int_str)0; if(_uri!=NULL) { uri = *_uri; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor, NULL) < 0) { LM_ERR("failed to extract address of record\n"); return -1; } ul.lock_udomain(_d, &aor); res = ul.get_urecord(_d, &aor, &r); if (res < 0) { ul.unlock_udomain(_d, &aor); LM_ERR("failed to query usrloc\n"); return -1; } if (res == 0) { if (reg_callid_avp_name.n) { struct usr_avp *avp = search_first_avp( reg_callid_avp_type, reg_callid_avp_name, &match_callid, 0); if (!(avp && is_avp_str_val(avp))) match_callid.n = 0; match_callid.s.s = NULL; } else { match_callid.n = 0; match_callid.s.s = NULL; } for (ptr = r->contacts; ptr; ptr = ptr->next) { if(!VALID_CONTACT(ptr, act_time)) continue; if (match_callid.s.s && /* optionally enforce tighter matching w/ Call-ID */ memcmp(match_callid.s.s,ptr->callid.s,match_callid.s.len)) continue; ul.release_urecord(r); ul.unlock_udomain(_d, &aor); LM_DBG("'%.*s' found in usrloc\n", aor.len, ZSW(aor.s)); return 1; } } ul.unlock_udomain(_d, &aor); LM_DBG("'%.*s' not found in usrloc\n", aor.len, ZSW(aor.s)); return -1; }
static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c, ucontact_info_t *ci, int mc) { int num; int e; ucontact_t* ptr, *cont; int ret; num = 0; ptr = _r->contacts; while(ptr) { if (VALID_CONTACT(ptr, act_time)) { num++; } ptr = ptr->next; } LM_DBG("%d valid contacts\n", num); for( ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &e); ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci, &cont); if (ret==-1) { LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s); rerrno = R_INV_CSEQ; return -1; } else if (ret==-2) { continue; } if (ret > 0) { /* Contact not found */ if (e != 0) num++; } else { if (e == 0) num--; } } LM_DBG("%d contacts after commit\n", num); if (num > mc) { LM_INFO("too many contacts for AOR <%.*s>\n", _r->aor.len, _r->aor.s); rerrno = R_TOO_MANY; return -1; } return 0; }
/** * Check that the IMPU at the Term S has at least one valid contact... * @param _m - msg * @param _t - t * @param _s - s * @return true if there is at least one valid contact. false if not */ int term_impu_has_contact(struct sip_msg* _m, udomain_t* _d, char* _s) { impurecord_t* r; str aor, uri; ucontact_t* ptr; int res; int ret; int i = 0; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain(_d, &aor); res = ul.get_impurecord(_d, &aor, &r); if (res != 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s); i++; ret = 1; break; } i++; } /* look first for an un-expired and supported contact */ if (ptr == 0) { /* nothing found */ ret = -1; } ul.unlock_udomain(_d, &aor); return ret; }
/* * This routine is used when db_mode is * set to WRITE_THROUGH */ static inline int wt_timer(urecord_t* _r) { ucontact_t* ptr, *t; int not = 0; 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); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; /* it was the last contact and it was in normal * state, so notify */ if (!ptr && t->state == CS_SYNC) not=1; if (db_delete_ucontact(t) < 0) { LOG(L_ERR, "wt_timer(): Error while deleting contact from " "database\n"); } delete_reg_avps(t); mem_delete_ucontact(_r, t); _r->slot->d->expired++; } else { /* the contact was unregistered and is not marked * for replication so remove it, but the notify was * already done during unregister */ ptr = ptr->next; } } return 0; }
/*! + * \brief Match a contact record to a contact string and path + * \param ptr contact record + * \param _c contact string + * \param _path path + * \return ptr on successfull match, 0 when they not match + */ static inline struct ucontact* contact_path_match(unsigned int slot, str* _c, str *_path) { ucontact_t* ptr = contact_list->slot[slot].first; /* if no path is preset (in REGISTER request) or use_path is not configured in registrar module, default to contact_match() */ if (_path == NULL) return contact_match(slot, _c); while (ptr) { if ((_c->len == ptr->c.len) && (_path->len == ptr->path.len) && !memcmp(_c->s, ptr->c.s, _c->len) && !memcmp(_path->s, ptr->path.s, _path->len) && VALID_CONTACT(ptr, act_time) ) { return ptr; } ptr = ptr->next; } return 0; }
int lookup_path_to_contact(struct sip_msg* _m, char* contact_uri) { ucontact_t* contact; str s_contact_uri; str path_dst; get_act_time(); if (get_str_fparam(&s_contact_uri, _m, (fparam_t*) contact_uri) < 0) { LM_ERR("failed to get RURI\n"); return -1; } LM_DBG("Looking up contact [%.*s]\n", s_contact_uri.len, s_contact_uri.s); if (ul.get_ucontact(NULL, &s_contact_uri, 0, 0, 0, &contact) == 0) { //get_contact returns with lock if (!VALID_CONTACT(contact, act_time)) { LM_DBG("Contact is not valid...ignoring\n"); ul.release_ucontact(contact); } else { LM_DBG("CONTACT FOUND and path is [%.*s]\n", contact->path.len, contact->path.s); if (get_path_dst_uri(&contact->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ul.release_ucontact(contact); return -1; } if (set_path_vector(_m, &contact->path) < 0) { LM_ERR("failed to set path vector\n"); ul.release_ucontact(contact); return -1; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ul.release_ucontact(contact); return -1; } ul.release_ucontact(contact); return 1; } } LM_DBG("no contact found for [%.*s]\n", s_contact_uri.len, s_contact_uri.s); return -1; }
/* * Build Contact HF for reply */ static inline int print_contacts(FILE* _o, ucontact_t* _c) { int cnt = 0; while(_c) { if (VALID_CONTACT(_c, act_time)) { cnt++; if (cnt==1) { fputs( "200 OK\n", _o); } fprintf(_o, "<%.*s>;q=%s;expires=%d\n", _c->c.len, ZSW(_c->c.s), q2str(_c->q, 0), (int)(_c->expires - act_time)); } _c = _c->next; } return cnt; }
/* * Return true if the AOR in the Request-URI is registered, * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ int registered(struct sip_msg* _m, char* _t, char* _s) { str uri, aor; urecord_t* r; ucontact_t* ptr; int res; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LOG(L_ERR, "registered(): Error while extracting address of record\n"); return -1; } ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res < 0) { ul.unlock_udomain((udomain_t*)_t); LOG(L_ERR, "registered(): Error while querying usrloc\n"); return -1; } if (res == 0) { ptr = r->contacts; while (ptr && !VALID_CONTACT(ptr, act_time)) { ptr = ptr->next; } if (ptr) { ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' found in usrloc\n", aor.len, ZSW(aor.s)); return 1; } } ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' not found in usrloc\n", aor.len, ZSW(aor.s)); return -1; }
static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c) { int num; int e; ucontact_t* ptr, *cont; num = 0; ptr = _r->contacts; while(ptr) { if (VALID_CONTACT(ptr, act_time)) { num++; } ptr = ptr->next; } DBG("test_max_contacts: %d valid contacts\n", num); while(_c) { if (calc_contact_expires(_m, _c->expires, &e) < 0) { LOG(L_ERR, "test_max_contacts: Error while calculating expires\n"); return -1; } if (ul.get_ucontact(_r, &_c->uri, &cont) > 0) { /* Contact not found */ if (e != 0) num++; } else { if (e == 0) num--; } _c = get_next_contact(_c); } DBG("test_max_contacts: %d contacts after commit\n", num); if (num > max_contacts) { rerrno = R_TOO_MANY; return 1; } return 0; }
/* * Return true if the AOR in the Request-URI is registered, * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ int registered2(struct sip_msg* _m, char* _t, char* p2) { str uid, aor; urecord_t* r; ucontact_t* ptr; int res; if (get_str_fparam(&aor, _m, (fparam_t*)p2) != 0) { ERR("Unable to get the AOR value\n"); return -1; } if (get_to_uid(&uid, _m) < 0) return -1; ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &uid, &r); if (res < 0) { ul.unlock_udomain((udomain_t*)_t); LOG(L_ERR, "registered(): Error while querying usrloc\n"); return -1; } if (res == 0) { ptr = r->contacts; while (ptr && (!VALID_CONTACT(ptr, act_time) || !VALID_AOR(ptr, aor))) { ptr = ptr->next; } if (ptr) { ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' found in usrloc\n", uid.len, ZSW(uid.s)); return 1; } } ul.unlock_udomain((udomain_t*)_t); DBG("registered(): '%.*s' not found in usrloc\n", uid.len, ZSW(uid.s)); return -1; }
/* * Build Contact HF for reply */ static inline int print_contacts(rpc_t* rpc, void* ctx, ucontact_t* _c) { int cnt = 0; void* handle; while(_c) { if (VALID_CONTACT(_c, act_time)) { cnt++; if (rpc->add(ctx, "{", &handle) < 0) return -1; rpc->struct_add(handle, "SfdSS", "contact", &_c->c, "q", q2double(_c->q), "expires", (int)(_c->expires - act_time), "ua", &_c->user_agent, "recv", &_c->received); } _c = _c->next; } return cnt; }
/* * This timer routine is used when * db_mode is set to NO_DB or READONLY */ static inline int nodb_timer(urecord_t* _r) { ucontact_t* ptr, *t; int not = 0; 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); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); t = ptr; ptr = ptr->next; /* it was the last contact and it was in normal * state, so notify */ if (!ptr && t->state == CS_NEW) not=1; delete_reg_avps(t); mem_delete_ucontact(_r, t); _r->slot->d->expired++; } else { ptr = ptr->next; } } return 0; }
/*! \brief * Message contained some contacts and appropriate * record was found, so we have to walk through * all contacts and do the following: * 1) If contact in usrloc doesn't exists and * expires > 0, insert new contact * 2) If contact in usrloc exists and expires * > 0, update the contact * 3) If contact in usrloc exists and expires * == 0, delete contact */ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c, struct save_ctx *_sctx) { ucontact_info_t *ci; ucontact_t* c; int e; unsigned int cflags; int ret; int num; #ifdef USE_TCP int e_max; int tcp_check; struct sip_uri uri; #endif /* mem flag */ cflags = (_sctx->flags®_SAVE_MEMORY_FLAG)?FL_MEM:FL_NONE; /* pack the contact_info */ if ( (ci=pack_ci( _m, 0, 0, cflags, _sctx->flags))==0 ) { LM_ERR("failed to initial pack contact info\n"); goto error; } /* count how many contacts we have right now */ num = 0; if (_sctx->max_contacts) { c = _r->contacts; while(c) { if (VALID_CONTACT(c, act_time)) num++; c = c->next; } } #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) { e_max = -1; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif for( ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &e); /* search for the contact*/ ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->cseq, &c); if (ret==-1) { LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s); rerrno = R_INV_CSEQ; goto error; } else if (ret==-2) { continue; } if ( ret > 0 ) { /* Contact not found -> expired? */ if (e==0) continue; /* we need to add a new contact -> too many ?? */ if (_sctx->max_contacts && num>=_sctx->max_contacts) { if (_sctx->flags®_SAVE_FORCE_REG_FLAG) { /* we are overflowing the number of maximum contacts, so remove the first (oldest) one to prevent this */ if (_r==NULL || _r->contacts==NULL) { LM_CRIT("BUG - overflow detected with r=%p and " "contacts=%p\n",_r,_r->contacts); goto error; } if (ul.delete_ucontact( _r, _r->contacts)!=0) { LM_ERR("failed to remove contact\n"); goto error; } } else { LM_INFO("too many contacts for AOR <%.*s>, max=%d\n", _r->aor.len, _r->aor.s, _sctx->max_contacts); rerrno = R_TOO_MANY; return -1; } } /* pack the contact_info */ if ( (ci=pack_ci( 0, _c, e, 0, _sctx->flags))==0 ) { LM_ERR("failed to extract contact info\n"); goto error; } if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } } else { /* Contact found */ if (e == 0) { /* it's expired */ if (_sctx->flags®_SAVE_MEMORY_FLAG) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c) < 0) { rerrno = R_UL_DEL_C; LM_ERR("failed to delete contact\n"); goto error; } } else { /* do update */ /* pack the contact specific info */ if ( (ci=pack_ci( 0, _c, e, 0, _sctx->flags))==0 ) { LM_ERR("failed to pack contact specific info\n"); goto error; } if (ul.update_ucontact(_r, c, ci) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } } } #ifdef USE_TCP if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) { if (e_max>0) { LM_WARN("multiple TCP contacts on single REGISTER\n"); } if (e>e_max) e_max = e; } } #endif } #ifdef USE_TCP if ( tcp_check && e_max>-1 ) { if (e_max) e_max -= act_time; force_tcp_conn_lifetime( &_m->rcv , e_max + 10 ); } #endif return 0; error: return -1; }
/*! * \brief Expires timer for NO_DB db_mode * * Expires timer for NO_DB db_mode, process all contacts from * the record, delete the expired ones from memory. * \param _r processed record */ static inline void process_impurecord(impurecord_t* _r) { int flag, mustdeleteimpu = 1, n, k; unsigned int sl; ucontact_t* ptr; int hascontacts; udomain_t* _d; reg_subscriber *s; subs_t* sub_dialog; get_act_time(); s = _r->shead; LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s); while (s) { if (!valid_subscriber(s, act_time)) { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s); delete_subscriber(_r, s); } else { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s, (unsigned int) (s->expires - time(NULL))); sl = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size); LM_DBG("Hash size: <%i>", sub_dialog_hash_size); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, sl); /* search the record in hash table */ lock_get(&sub_dialog_table[sl].lock); sub_dialog = pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, sl); if (sub_dialog == NULL) { LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n"); } else { LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s); } lock_release(&sub_dialog_table[sl].lock); mustdeleteimpu = 0; } s = s->next; } LM_DBG("\tPublic Identity %.*s, Barred: [%d], State: [%s]\n", _r->public_identity.len, _r->public_identity.s, _r->barring, get_impu_regstate_as_string(_r->reg_state)); flag = 0; hascontacts = 0; num_contacts_to_expire = 0; for (k = 0; (k < _r->num_contacts) && (k < MAX_CONTACTS_PER_IMPU); k++) { if ((ptr = _r->newcontacts[k])) { flag = 1; if (!VALID_CONTACT(ptr, act_time)) { if (ptr->state == CONTACT_DELETED) { LM_DBG("Contact: <%.*s> has been deleted - unlinking from IMPU\n", ptr->c.len, ptr->c.s); contacts_to_expire[num_contacts_to_expire] = ptr; num_contacts_to_expire++; } else if (ptr->state == CONTACT_EXPIRE_PENDING_NOTIFY) { LM_DBG("Contact: <%.*s> is in state CONTACT_EXPIRE_PENDING_NOTIFY....running callback\n", ptr->c.len, ptr->c.s); if (exists_ulcb_type(_r->cbs, UL_IMPU_DELETE_CONTACT)) { LM_DBG("Running callback UL_IMPU_DELETE_CONTACT for contact [%.*s] and impu [%.*s]\n", ptr->c.len, ptr->c.s, _r->public_identity.len, _r->public_identity.s); run_ul_callbacks(_r->cbs, UL_IMPU_DELETE_CONTACT, _r, ptr); } hascontacts = 1; // we do this because the impu must only be deleted if in state deleted.... mustdeleteimpu = 0; } else if (ptr->state == CONTACT_VALID) { LM_DBG("Contact: <%.*s> is in state valid but it has expired.... ignoring as the contact check will set the appropriate action/state\n", ptr->c.len, ptr->c.s); mustdeleteimpu = 0; hascontacts = 1; } else { LM_WARN("Bogus state for contact [%.*s] - state: %d... ignoring", ptr->c.len, ptr->c.s, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_DBG("\t\tContact #%i - %.*s, Ref [%d] (expires in %ld seconds) (State: %d)\n", k, ptr->c.len, ptr->c.s, ptr->ref_count, ptr->expires - act_time, ptr->state); mustdeleteimpu = 0; hascontacts = 1; } } else { LM_WARN("num_contacts and actual data not consistent... .aborting\n"); break; } } if (num_contacts_to_expire > 0) { LM_DBG("\tThere are %d contacts to expire/unlink\n", num_contacts_to_expire); for (n = 0; n < num_contacts_to_expire; n++) { ptr = contacts_to_expire[n]; LM_DBG("\t\texpiring contact %i: [%.*s] in slot [%d]\n", n, contacts_to_expire[n]->c.len, contacts_to_expire[n]->c.s, contacts_to_expire[n]->sl); sl = ptr->sl; lock_contact_slot_i(sl); unlink_contact_from_impu(_r, ptr, 1, 0 /*implicit dereg of contact from IMPU*/); unlock_contact_slot_i(sl); } } if (!flag) LM_DBG("no contacts\n"); if (mustdeleteimpu) { register_udomain("location", &_d); delete_impurecord(_d, &_r->public_identity, _r); } else { if (!hascontacts) { LM_DBG("This impu is not to be deleted but has no contacts - changing state to IMPU_UNREGISTERED\n"); _r->reg_state = IMPU_UNREGISTERED; } } }
/*! \brief * Allocate a memory buffer and print Contact * header fields into it */ int build_contact(ucontact_t* c) { char *p, *cp; int fl, len; contact.data_len = calc_buf_len(c); if (!contact.data_len) return 0; if (!contact.buf || (contact.buf_len < contact.data_len)) { if (contact.buf) pkg_free(contact.buf); contact.buf = (char*)pkg_malloc(contact.data_len); if (!contact.buf) { contact.data_len = 0; contact.buf_len = 0; LM_ERR("no pkg memory left\n"); return -1; } else { contact.buf_len = contact.data_len; } } p = contact.buf; memcpy(p, CONTACT_BEGIN, CONTACT_BEGIN_LEN); p += CONTACT_BEGIN_LEN; fl = 0; while(c) { if (VALID_CONTACT(c, act_time)) { if (fl) { memcpy(p, CONTACT_SEP, CONTACT_SEP_LEN); p += CONTACT_SEP_LEN; } else { fl = 1; } *p++ = '<'; memcpy(p, c->c.s, c->c.len); p += c->c.len; *p++ = '>'; len = len_q(c->q); if (len) { memcpy(p, Q_PARAM, Q_PARAM_LEN); p += Q_PARAM_LEN; memcpy(p, q2str(c->q, 0), len); p += len; } memcpy(p, EXPIRES_PARAM, EXPIRES_PARAM_LEN); p += EXPIRES_PARAM_LEN; cp = int2str((int)(c->expires - act_time), &len); memcpy(p, cp, len); p += len; if (c->received.s) { *p++ = ';'; memcpy(p, rcv_param.s, rcv_param.len); p += rcv_param.len; *p++ = '='; *p++ = '\"'; memcpy(p, c->received.s, c->received.len); p += c->received.len; *p++ = '\"'; } } c = c->next; } memcpy(p, CRLF, CRLF_LEN); p += CRLF_LEN; contact.data_len = p - contact.buf; LM_DBG("created Contact HF: %.*s\n", contact.data_len, contact.buf); return 0; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, udomain_t* _d) { impurecord_t* r; str aor, uri; ucontact_t* ptr; int res; int ret; str path_dst; flag_t old_bflags; int i = 0; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; if (extract_aor(&uri, &aor) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain(_d, &aor); res = ul.get_impurecord(_d, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain(_d, &aor); return -1; } ret = -1; while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s); i++; break; } i++; } /* look first for an un-expired and suported contact */ if (ptr == 0) { /* nothing found */ goto done; } ret = 1; if (ptr) { if (rewrite_uri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* reset next hop address */ reset_dst_uri(_m); /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } set_ruri_q(ptr->q); old_bflags = 0; getbflagsval(0, &old_bflags); setbflagsval(0, old_bflags | ptr->cflags); if (ptr->sock) set_force_socket(_m, ptr->sock); ptr = ptr->next; } /* Append branches if enabled */ if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done; //the last i was the first valid contact we found - let's go through the rest of valid contacts and append the branches. while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) { path_dst.len = 0; if (ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } /* The same as for the first contact applies for branches * regarding path vs. received. */ if (km_append_branch(_m, &ptr->c, path_dst.len ? &path_dst : &ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } } i++; } done: ul.unlock_udomain(_d, &aor); return ret; }
/*! * \brief Dumps the contacts of an AOR * \param cmd mi_root containing the parameter * \param param not used * \note expects 2 nodes: the table name and the AOR * \return mi_root with the result or 0 on failure */ struct mi_root* mi_usrloc_show_contact(struct mi_root *cmd, void *param) { struct mi_root *rpl_tree; struct mi_node *rpl, *node; udomain_t *dom; urecord_t *rec; ucontact_t* con; str *aor; int ret; node = cmd->node.kids; if (node==NULL || node->next==NULL || node->next->next!=NULL) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); /* look for table */ dom = mi_find_domain( &node->value ); if (dom==NULL) return init_mi_tree( 404, "Table not found", 15); /* process the aor */ aor = &node->next->value; if ( mi_fix_aor(aor)!=0 ) return init_mi_tree( 400, "Domain missing in AOR", 21); lock_udomain( dom, aor); ret = get_urecord( dom, aor, &rec); if (ret == 1) { unlock_udomain( dom, aor); return init_mi_tree( 404, "AOR not found", 13); } get_act_time(); rpl_tree = 0; rpl = 0; for( con=rec->contacts ; con ; con=con->next) { if (VALID_CONTACT( con, act_time)) { if (rpl_tree==0) { rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN); if (rpl_tree==0) goto error; rpl = &rpl_tree->node; } node = addf_mi_node_child( rpl, 0, "Contact", 7, "<%.*s>;q=%s;expires=%d;flags=0x%X;cflags=0x%X;socket=<%.*s>;" "methods=0x%X" "%s%.*s%s" /*received*/ "%s%.*s%s" /*user-agent*/ "%s%.*s%s" /*path*/ "%s%.*s" /*instance*/ ";reg-id=%u", con->c.len, ZSW(con->c.s), q2str(con->q, 0), (int)(con->expires - act_time), con->flags, con->cflags, con->sock?con->sock->sock_str.len:3, con->sock?con->sock->sock_str.s:"NULL", con->methods, con->received.len?";received=<":"",con->received.len, ZSW(con->received.s), con->received.len?">":"", con->user_agent.len?";user_agent=<":"",con->user_agent.len, ZSW(con->user_agent.s), con->user_agent.len?">":"", con->path.len?";path=<":"", con->path.len, ZSW(con->path.s), con->path.len?">":"", con->instance.len?";+sip.instance=":"", con->instance.len, ZSW(con->instance.s), con->reg_id ); if (node==0) goto error; } } unlock_udomain( dom, aor); if (rpl_tree==0) return init_mi_tree( 404 , "AOR has no contacts", 18); return rpl_tree; error: if (rpl_tree) free_mi_tree( rpl_tree ); unlock_udomain( dom, aor); return 0; }
/* * Lookup contact in the database and rewrite Request-URI */ int lookup(struct sip_msg* _m, char* _t, char* _s) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri; nat = 0; if (get_to_uid(&uid, _m) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)_t); res = ul.get_urecord((udomain_t*)_t, &uid, &r); if (res < 0) { LOG(L_ERR, "lookup(): Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)_t); return -2; } if (res > 0) { DBG("lookup(): '%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)_t); return -3; } ptr = r->contacts; while ((ptr) && !VALID_CONTACT(ptr, act_time)) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): out of memory\n"); return -4; } /* replace the msg uri */ if (_m->new_uri.s) pkg_free(_m->new_uri.s); _m->new_uri=new_uri; _m->parsed_uri_ok=0; ruri_mark_new(); goto skip_rewrite_uri; }else if (set_dst_uri(_m, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)_t); return -4; } } if (rewrite_uri(_m, &ptr->c) < 0) { LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)_t); return -4; } if (ptr->sock) { set_force_socket(_m, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)_t); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time)) { if (received_to_uri && ptr->received.s && ptr->received.len){ if (add_received(&new_uri, &ptr->c, &ptr->received)<0){ LOG(L_ERR, "ERROR: lookup(): branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(_m, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error==E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ }else{ if (append_branch(_m, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0 /* brflags*/, ptr->sock) == -1) { LOG(L_ERR, "lookup(): Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)_t); if (nat) setflag(_m, load_nat_flag); return 1; }
/* * Lookup contact in the database and rewrite Request-URI, * and filter them by aor */ int lookup2(struct sip_msg* msg, char* table, char* p2) { urecord_t* r; str uid; ucontact_t* ptr; int res; unsigned int nat; str new_uri, aor; fparam_t* fp; nat = 0; fp = (fparam_t*)p2; if (get_str_fparam(&aor, msg, (fparam_t*)p2) != 0) { ERR("Unable to get the AOR value\n"); return -1; } if (get_to_uid(&uid, msg) < 0) return -1; get_act_time(); ul.lock_udomain((udomain_t*)table); res = ul.get_urecord((udomain_t*)table, &uid, &r); if (res < 0) { ERR("Error while querying usrloc\n"); ul.unlock_udomain((udomain_t*)table); return -2; } if (res > 0) { DBG("'%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s)); ul.unlock_udomain((udomain_t*)table); return -3; } ptr = r->contacts; while (ptr && (!VALID_CONTACT(ptr, act_time) || !VALID_AOR(ptr, aor))) ptr = ptr->next; if (ptr) { if (ptr->received.s && ptr->received.len) { if (received_to_uri){ if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("Out of memory\n"); return -4; } /* replace the msg uri */ if (msg->new_uri.s) pkg_free(msg->new_uri.s); msg->new_uri = new_uri; msg->parsed_uri_ok = 0; ruri_mark_new(); goto skip_rewrite_uri; } else if (set_dst_uri(msg, &ptr->received) < 0) { ul.unlock_udomain((udomain_t*)table); return -4; } } if (rewrite_uri(msg, &ptr->c) < 0) { ERR("Unable to rewrite Request-URI\n"); ul.unlock_udomain((udomain_t*)table); return -4; } if (ptr->sock) { set_force_socket(msg, ptr->sock); } skip_rewrite_uri: set_ruri_q(ptr->q); nat |= ptr->flags & FL_NAT; ptr = ptr->next; } else { /* All contacts expired */ ul.unlock_udomain((udomain_t*)table); return -5; } /* Append branches if enabled */ if (!append_branches) goto skip; while(ptr) { if (VALID_CONTACT(ptr, act_time) && VALID_AOR(ptr, aor)) { if (received_to_uri && ptr->received.s && ptr->received.len) { if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) { ERR("branch: out of memory\n"); goto cont; /* try to continue */ } if (append_branch(msg, &new_uri, 0, 0, ptr->q, 0, 0) == -1) { ERR("Error while appending a branch\n"); pkg_free(new_uri.s); if (ser_error == E_TOO_MANY_BRANCHES) goto skip; else goto cont; /* try to continue, maybe we have an oversized contact */ } pkg_free(new_uri.s); /* append_branch doesn't free it */ } else { if (append_branch(msg, &ptr->c, &ptr->received, 0 /* path */, ptr->q, 0, ptr->sock) == -1) { ERR("Error while appending a branch\n"); goto skip; /* Return OK here so the function succeeds */ } } nat |= ptr->flags & FL_NAT; } cont: ptr = ptr->next; } skip: ul.unlock_udomain((udomain_t*)table); if (nat) setflag(msg, load_nat_flag); return 1; }
int process_contact(udomain_t * domain, urecord_t ** ul_record, str aor, str callid, int cseq, int expires, int event, str contact_uri) { str no_str = {0, 0}; static str no_ua = str_init("n/a"); static ucontact_info_t ci; ucontact_t * ul_contact; if (*ul_record == NULL) { switch(event) { case EVENT_REGISTERED: case EVENT_CREATED: case EVENT_REFRESHED: /* In case, no record exists and new one should be created, create a new entry for this user in the usrloc-DB */ if (ul.insert_urecord(domain, &aor, ul_record) < 0) { LM_ERR("failed to insert new user-record\n"); return RESULT_ERROR; } break; default: /* No entry in usrloc and the contact is expired, deleted, unregistered, whatever: We do not need to do anything. */ return RESULT_NO_CONTACTS; break; } } /* Make sure, no crap is in the structure: */ memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ ci.callid = &callid; /* Get CSeq number of the message */ ci.cseq = cseq; ci.sock = NULL; /* additional info from message */ ci.user_agent = &no_ua; ci.last_modified = time(0); /* set expire time */ ci.expires = time(0) + expires; /* set ruid */ if(sruid_next(&_reginfo_sruid) < 0) { LM_ERR("failed to generate ruid"); } else { ci.ruid = _reginfo_sruid.uid; } /* Now we start looking for the contact: */ if (((*ul_record)->contacts == 0) || (ul.get_ucontact(*ul_record, &contact_uri, &callid, &no_str, cseq+1, &ul_contact) != 0)) { if (ul.insert_ucontact(*ul_record, &contact_uri, &ci, &ul_contact) < 0) { LM_ERR("failed to insert new contact\n"); return RESULT_ERROR; } } else { if (ul.update_ucontact(*ul_record, ul_contact, &ci) < 0) { LM_ERR("failed to update contact\n"); return RESULT_ERROR; } } ul_contact = (*ul_record)->contacts; while (ul_contact) { if (VALID_CONTACT(ul_contact, time(0))) return RESULT_CONTACTS_FOUND; ul_contact = ul_contact->next; } return RESULT_NO_CONTACTS; }
/*! \brief * Message contained some contacts and appropriate * record was found, so we have to walk through * all contacts and do the following: * 1) If contact in usrloc doesn't exists and * expires > 0, insert new contact * 2) If contact in usrloc exists and expires * > 0, update the contact * 3) If contact in usrloc exists and expires * == 0, delete contact */ static inline int update_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c, struct save_ctx *_sctx) { ucontact_info_t *ci; ucontact_t *c, *c_last, *c_it; int e; unsigned int cflags; int ret; int num; int e_max; int tcp_check; struct sip_uri uri; /* mem flag */ cflags = (_sctx->flags®_SAVE_MEMORY_FLAG)?FL_MEM:FL_NONE; /* pack the contact_info */ if ( (ci=pack_ci( _m, 0, 0, cflags, _sctx->flags))==0 ) { LM_ERR("failed to initial pack contact info\n"); goto error; } /* count how many contacts we have right now */ num = 0; if (_sctx->max_contacts) { c = _r->contacts; while(c) { if (VALID_CONTACT(c, act_time)) num++; c = c->next; } } if (is_tcp_based_proto(_m->rcv.proto) && (_m->flags&tcp_persistent_flag)) { e_max = -1; tcp_check = 1; } else { e_max = tcp_check = 0; } for( ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &e, _sctx); /* search for the contact*/ ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->cseq, &c); if (ret==-1) { LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s); rerrno = R_INV_CSEQ; goto error; } else if (ret==-2) { continue; } if ( ret > 0 ) { /* Contact not found -> expired? */ if (e==0) continue; /* we need to add a new contact -> too many ?? */ while (_sctx->max_contacts && num>=_sctx->max_contacts) { if (_sctx->flags®_SAVE_FORCE_REG_FLAG) { /* we are overflowing the number of maximum contacts, so remove the oldest valid one to prevent this */ for( c_it=_r->contacts,c_last=NULL ; c_it ; c_it=c_it->next ) if (VALID_CONTACT(c_it, act_time)) c_last=c_it; if (c_last==NULL) { LM_CRIT("BUG - overflow detected but no valid " "contacts found :( \n"); goto error; } LM_DBG("overflow on inserting new contact -> removing " "<%.*s>\n", c_last->c.len, c_last->c.s); if (ul.delete_ucontact( _r, c_last, 0)!=0) { LM_ERR("failed to remove contact\n"); goto error; } num--; } else { LM_INFO("too many contacts for AOR <%.*s>, max=%d\n", _r->aor.len, _r->aor.s, _sctx->max_contacts); rerrno = R_TOO_MANY; return -1; } } /* pack the contact_info */ if ( (ci=pack_ci( 0, _c, e, 0, _sctx->flags))==0 ) { LM_ERR("failed to extract contact info\n"); goto error; } if (ul.insert_ucontact( _r, &_c->uri, ci, &c, 0) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } } else { /* Contact found */ if (e == 0) { /* it's expired */ if (_sctx->flags®_SAVE_MEMORY_FLAG) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c, 0) < 0) { rerrno = R_UL_DEL_C; LM_ERR("failed to delete contact\n"); goto error; } } else { /* do update */ /* if the contact to be updated is not valid, it will be after * update, so need to compensate the total number of contact */ if ( !VALID_CONTACT(c,act_time) ) num++; while ( _sctx->max_contacts && num>_sctx->max_contacts ) { if (_sctx->flags®_SAVE_FORCE_REG_FLAG) { /* we are overflowing the number of maximum contacts, so remove the first (oldest) one to prevent this (but not the one to be updated !) */ for( c_it=_r->contacts,c_last=NULL ; c_it ; c_it=c_it->next ) if (VALID_CONTACT(c_it, act_time) && c_it!=c) c_last=c_it; if (c_last==NULL) { LM_CRIT("BUG - overflow detected but no " "valid contacts found :( \n"); goto error; } LM_DBG("overflow on update -> removing contact " "<%.*s>\n", c_last->c.len, c_last->c.s); if (ul.delete_ucontact( _r, c_last, 0)!=0) { LM_ERR("failed to remove contact\n"); goto error; } num--; } else { LM_INFO("too many contacts for AOR <%.*s>, max=%d\n", _r->aor.len, _r->aor.s, _sctx->max_contacts); rerrno = R_TOO_MANY; return -1; } } /* pack the contact specific info */ if ( (ci=pack_ci( 0, _c, e, 0, _sctx->flags))==0 ) { LM_ERR("failed to pack contact specific info\n"); goto error; } if (ul.update_ucontact(_r, c, ci, 0) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } } } if (tcp_check) { /* parse contact uri to see if transport is TCP */ if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) { LM_ERR("failed to parse contact <%.*s>\n", _c->uri.len, _c->uri.s); } else if (is_tcp_based_proto(uri.proto)) { if (e_max>0) { LM_WARN("multiple TCP contacts on single REGISTER\n"); } if (e>e_max) e_max = e; } } } if ( tcp_check && e_max>-1 ) { if (e_max) e_max -= act_time; trans_set_dst_attr( &_m->rcv, DST_FCNTL_SET_LIFETIME, (void*)(long)(e_max + 10) ); } return 0; error: return -1; }
/* * Write-back timer */ static inline int wb_timer(urecord_t* _r) { ucontact_t* ptr, *t; int op; int not = 0; 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); LOG(L_NOTICE, "Binding '%.*s','%.*s' has expired\n", ptr->uid->len, ZSW(ptr->uid->s), ptr->c.len, ZSW(ptr->c.s)); if (ptr->next == 0) not=1; _r->slot->d->expired++; 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"); } } delete_reg_avps(t); 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_store_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while inserting contact into database\n"); } break; case 2: /* update */ if (db_store_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Error while updating contact in db\n"); } break; case 4: /* delete */ if (db_delete_ucontact(ptr) < 0) { LOG(L_ERR, "wb_timer(): Can't delete contact from database\n"); } /* fall through to the next case statement */ case 3: /* delete from memory */ delete_reg_avps(ptr); mem_delete_ucontact(_r, ptr); break; } ptr = ptr->next; } } return 0; }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: -1 : not found * -2 : found but method not allowed * -3 : error */ int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s) { unsigned int flags; urecord_t* r; str aor, uri; ucontact_t* ptr,*it; int res; int ret; str path_dst; str flags_s; char* ua = NULL; char* re_end = NULL; int re_len = 0; char tmp; regex_t ua_re; int regexp_flags = 0; regmatch_t ua_match; pv_value_t val; int_str istr; str sip_instance = {0,0},call_id = {0,0}; /* branch index */ int idx; /* temporary branch values*/ int tlen; char *turi; qvalue_t tq; flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid owner uri parameter"); return -1; } for( res=0 ; res< flags_s.len ; res++ ) { switch (flags_s.s[res]) { case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break; case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break; case 'r': flags |= REG_BRANCH_AOR_LOOKUP_FLAG; break; case 'u': if (flags_s.s[res+1] != '/') { LM_ERR("no regexp after 'u' flag"); break; } res++; if ((re_end = strrchr(flags_s.s+res+1, '/')) == NULL) { LM_ERR("no regexp after 'u' flag"); break; } res++; re_len = re_end-flags_s.s-res; if (re_len == 0) { LM_ERR("empty regexp"); break; } ua = flags_s.s+res; flags |= REG_LOOKUP_UAFILTER_FLAG; LM_DBG("found regexp /%.*s/", re_len, ua); res += re_len; break; case 'i': regexp_flags |= REG_ICASE; break; case 'e': regexp_flags |= REG_EXTENDED; break; default: LM_WARN("unsuported flag %c \n",flags_s.s[res]); } } } if (flags®_BRANCH_AOR_LOOKUP_FLAG) { /* extract all the branches for further usage */ nbranches = 0; while ( (turi=get_branch(nbranches, &tlen, &tq, NULL, NULL, NULL, NULL)) ) { /* copy uri */ branch_uris[nbranches].s = urimem[nbranches]; if (tlen) { memcpy(branch_uris[nbranches].s, turi, tlen); branch_uris[nbranches].len = tlen; } else { *branch_uris[nbranches].s = '\0'; branch_uris[nbranches].len = 0; } nbranches++; } clear_branches(); idx=0; } if (_s) { if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) { LM_ERR("failed to get PV value\n"); return -1; } if ( (val.flags&PV_VAL_STR)==0 ) { LM_ERR("PV vals is not string\n"); return -1; } uri = val.rs; } else { if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; } if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) { LM_ERR("failed to extract address of record\n"); return -3; } get_act_time(); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); ul.unlock_udomain((udomain_t*)_t, &aor); return -1; } if (flags & REG_LOOKUP_UAFILTER_FLAG) { tmp = *(ua+re_len); *(ua+re_len) = '\0'; if (regcomp(&ua_re, ua, regexp_flags) != 0) { LM_ERR("bad regexp '%s'\n", ua); *(ua+re_len) = tmp; return -1; } *(ua+re_len) = tmp; } ptr = r->contacts; ret = -1; /* look first for an un-expired and suported contact */ search_valid_contact: while ( (ptr) && !(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags))) ptr = ptr->next; if (ptr==0) { /* nothing found */ LM_DBG("nothing found !\n"); goto done; } ua_re_check( ret = -1; ptr = ptr->next; goto search_valid_contact ); if (sip_instance.len && sip_instance.s) { LM_DBG("ruri has gruu in lookup\n"); /* uri has GRUU */ if (ptr->instance.len-2 != sip_instance.len || memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) { LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1, sip_instance.len,sip_instance.s); /* not the targeted instance, search some more */ ptr = ptr->next; goto search_valid_contact; } LM_DBG("matched sip instace\n"); } if (call_id.len && call_id.s) { /* decide whether GRUU is expired or not * * first - match call-id */ if (ptr->callid.len != call_id.len || memcmp(ptr->callid.s,call_id.s,call_id.len)) { LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s, call_id.len,call_id.s); ptr = ptr->next; goto search_valid_contact; } /* matched call-id, check if there are newer contacts with * same sip instace bup newer last_modified */ it = ptr->next; while ( it ) { if (VALID_CONTACT(it,act_time)) { if (it->instance.len-2 == sip_instance.len && sip_instance.s && memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0) if (it->last_modified > ptr->last_modified) { /* same instance id, but newer modified -> expired GRUU, no match at all */ break; } } it=it->next; } if (it != NULL) { ret = -1; goto done; } } LM_DBG("found a complete match\n"); ret = 1; if (ptr) { LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s); if (set_ruri(_m, &ptr->c) < 0) { LM_ERR("unable to rewrite Request-URI\n"); ret = -3; goto done; } /* If a Path is present, use first path-uri in favour of * received-uri because in that case the last hop towards the uac * has to handle NAT. - agranig */ if (ptr->path.s && ptr->path.len) { if (get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); ret = -3; goto done; } if (set_path_vector(_m, &ptr->path) < 0) { LM_ERR("failed to set path vector\n"); ret = -3; goto done; } if (set_dst_uri(_m, &path_dst) < 0) { LM_ERR("failed to set dst_uri of Path\n"); ret = -3; goto done; } } else if (ptr->received.s && ptr->received.len) { if (set_dst_uri(_m, &ptr->received) < 0) { ret = -3; goto done; } } set_ruri_q( _m, ptr->q); setbflag( _m, 0, ptr->cflags); if (ptr->sock) _m->force_send_socket = ptr->sock; /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } ptr = ptr->next; } /* Append branches if enabled */ /* If we got to this point and the URI had a ;gr parameter and it was matched * to a contact. No point in branching */ if ( flags®_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done; LM_DBG("looking for branches\n"); do { for( ; ptr ; ptr = ptr->next ) { if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) { path_dst.len = 0; if(ptr->path.s && ptr->path.len && get_path_dst_uri(&ptr->path, &path_dst) < 0) { LM_ERR("failed to get dst_uri for Path\n"); continue; } ua_re_check(continue); /* The same as for the first contact applies for branches * regarding path vs. received. */ LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s); if (append_branch(_m,&ptr->c,path_dst.len?&path_dst:&ptr->received, &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) { LM_ERR("failed to append a branch\n"); /* Also give a chance to the next branches*/ continue; } /* populate the 'attributes' avp */ if (attr_avp_name != -1) { istr.s = ptr->attr; if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) { LM_ERR("Failed to populate attr avp!\n"); } } } } /* 0 branches condition also filled; idx initially -1*/ if (!(flags®_BRANCH_AOR_LOOKUP_FLAG) || idx == nbranches) goto done; /* relsease old aor lock */ ul.unlock_udomain((udomain_t*)_t, &aor); ul.release_urecord(r, 0); /* idx starts from -1 */ uri = branch_uris[idx]; if (extract_aor(&uri, &aor, NULL, &call_id) < 0) { LM_ERR("failed to extract address of record for branch uri\n"); return -3; } /* release old urecord */ /* get lock on new aor */ LM_DBG("getting contacts from aor [%.*s]" "in branch %d\n", aor.len, aor.s, idx); ul.lock_udomain((udomain_t*)_t, &aor); res = ul.get_urecord((udomain_t*)_t, &aor, &r); if (res > 0) { LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s)); goto done; } idx++; ptr = r->contacts; } while (1);
/*! \brief * Calculate the length of buffer needed to * print contacts * - mode specifies if GRUU header params are added */ static inline unsigned int calc_buf_len(ucontact_t* c, str *host, int mode) { unsigned int len; int qlen; len = 0; while(c) { if (VALID_CONTACT(c, act_time)) { if (len) len += CONTACT_SEP_LEN; len += 2 /* < > */ + c->c.len; qlen = len_q(c->q); if (qlen) len += Q_PARAM_LEN + qlen; len += EXPIRES_PARAM_LEN + INT2STR_MAX_LEN; if (rcv_param.len>0 && c->received.s) { len += 1 /* ; */ + rcv_param.len + 1 /* = */ + 1 /* dquote */ + c->received.len + 1 /* dquote */ ; } if (reg_gruu_enabled==1 && c->instance.len>0 && mode==1) { /* pub-gruu */ len += PUB_GRUU_PARAM_LEN + 1 /* " */ + 4 /* sip: */ + c->aor->len + 1 /* @ */ + host->len + GR_PARAM_LEN + c->instance.len + 1 /* " */ ; /* temp-gruu */ len += TMP_GRUU_PARAM_LEN + 1 /* " */ + 4 /* sip: */ + c->ruid.len + 1 /* 'sep' */ + 8 /* max hex int */ + 1 /* @ */ + host->len + GR_PARAM_LEN - 1 /* = */ + 1 /* " */ ; } if (c->instance.len>0) { /* +sip-instance */ len += SIP_INSTANCE_PARAM_LEN + 1 /* " */ + c->instance.len + 1 /* " */ ; } if (c->reg_id>0) { /* reg-id */ len += REG_ID_PARAM_LEN + INT2STR_MAX_LEN; } } c = c->next; } if (len) len += CONTACT_BEGIN_LEN + CRLF_LEN; return len; }
/*! * \brief Expires timer for NO_DB db_mode * * Expires timer for NO_DB db_mode, process all contacts from * the record, delete the expired ones from memory. * \param _r processed record */ static inline void nodb_timer(impurecord_t* _r) { ucontact_t* ptr, *t; unsigned int hash_code = 0; reg_subscriber *s; subs_t* sub_dialog; get_act_time(); s = _r->shead; LM_DBG("Checking validity of IMPU: <%.*s> registration subscriptions\n", _r->public_identity.len, _r->public_identity.s); while (s) { if (!valid_subscriber(s)) { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> expired and removed.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s); delete_subscriber(_r, s); } else { LM_DBG("DBG:registrar_timer: Subscriber with watcher_contact <%.*s> and presentity uri <%.*s> is valid and expires in %d seconds.\n", s->watcher_contact.len, s->watcher_contact.s, s->presentity_uri.len, s->presentity_uri.s, (unsigned int) (s->expires - time(NULL))); hash_code = core_hash(&s->call_id, &s->to_tag, sub_dialog_hash_size); LM_DBG("Hash size: <%i>", sub_dialog_hash_size); LM_DBG("Searching sub dialog hash info with call_id: <%.*s> and ttag <%.*s> ftag <%.*s> and hash code <%i>", s->call_id.len, s->call_id.s, s->to_tag.len, s->to_tag.s, s->from_tag.len, s->from_tag.s, hash_code); /* search the record in hash table */ lock_get(&sub_dialog_table[hash_code].lock); sub_dialog= pres_search_shtable(sub_dialog_table, s->call_id, s->to_tag, s->from_tag, hash_code); if(sub_dialog== NULL) { LM_ERR("DBG:registrar_timer: Subscription has no dialog record in hash table\n"); }else { LM_DBG("DBG:registrar_timer: Subscription has dialog record in hash table with presentity uri <%.*s>\n", sub_dialog->pres_uri.len, sub_dialog->pres_uri.s); } lock_release(&sub_dialog_table[hash_code].lock); } s = s->next; } ptr = _r->contacts; LM_DBG("Checking validity of IMPU: <%.*s> contacts\n", _r->public_identity.len, _r->public_identity.s); while (ptr) { if (!VALID_CONTACT(ptr, act_time)) { /* run callbacks for EXPIRE event */ if (exists_ulcb_type(ptr->cbs, UL_CONTACT_EXPIRE)) run_ul_callbacks(ptr->cbs, UL_CONTACT_EXPIRE, _r, ptr); if (exists_ulcb_type(_r->cbs, UL_IMPU_EXPIRE_CONTACT)) { run_ul_callbacks(_r->cbs, UL_IMPU_EXPIRE_CONTACT, _r, ptr); } LM_DBG("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_mode == WRITE_THROUGH && db_delete_ucontact(_r, t) != 0) { LM_ERR("error removing contact from DB [%.*s]... will still remove from memory\n", t->c.len, t->c.s); } mem_delete_ucontact(_r, t); update_stat(_r->slot->d->expires, 1); } else { LM_DBG("IMPU:<%.*s> - contact:<%.*s> is valid and expires in %d seconds\n", _r->public_identity.len, _r->public_identity.s, ptr->c.len, ptr->c.s, (unsigned int) (ptr->expires - time(NULL))); ptr = ptr->next; } } }