/*! \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 * Message contained some contacts, but record with same address * of record was not found so we have to create a new record * and insert all contacts from the message that have expires * > 0 */ static inline int insert_contacts(struct sip_msg* _m, contact_t* _c, udomain_t* _d, str* _a, struct save_ctx *_sctx) { ucontact_info_t* ci; urecord_t* r; ucontact_t* c; unsigned int cflags; int num; int e; #ifdef USE_TCP int e_max; int tcp_check; struct sip_uri uri; #endif cflags = (_sctx->flags®_SAVE_MEMORY_FLAG)?FL_MEM:FL_NONE; #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) { e_max = 0; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &e); /* Skip contacts with zero expires */ if (e == 0) continue; 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 (%d) for AOR <%.*s>, max=%d\n", num, _a->len, _a->s, _sctx->max_contacts); rerrno = R_TOO_MANY; goto error; } } else { num++; } if (r==0) { if (ul.insert_urecord(_d, _a, &r) < 0) { rerrno = R_UL_NEW_R; LM_ERR("failed to insert new record structure\n"); goto error; } } /* pack the contact_info */ if ( (ci=pack_ci( (ci==0)?_m:0, _c, e, cflags, _sctx->flags))==0 ) { LM_ERR("failed to extract contact info\n"); goto error; } if ( r->contacts==0 || ul.get_ucontact(r, &_c->uri, ci->callid, ci->cseq+1, &c)!=0 ) { 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 { 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) { LM_WARN("multiple TCP contacts on single REGISTER\n"); if (e>e_max) e_max = e; } else { e_max = e; } } } #endif } if (r) { if (r->contacts) build_contact(r->contacts); ul.release_urecord(r); } #ifdef USE_TCP if ( tcp_check && e_max>0 ) { e_max -= act_time; force_tcp_conn_lifetime( &_m->rcv , e_max + 10 ); } #endif return 0; error: if (r) ul.delete_urecord(_d, _a, r); return -1; }
/*! \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, int _mode, int _use_regid) { ucontact_info_t *ci; ucontact_t *c, *ptr, *ptr0; int expires, ret, updated; unsigned int flags; #ifdef USE_TCP int e_max, tcp_check; struct sip_uri uri; #endif int rc; contact_t* _c; int maxc; /* mem flag */ flags = mem_only; rc = 0; /* pack the contact_info */ if ( (ci=pack_ci( _m, 0, 0, flags, _use_regid))==0 ) { LM_ERR("failed to initial pack contact info\n"); goto error; } if (!_mode) { maxc = reg_get_crt_max_contacts(); if(maxc>0) { _c = get_first_contact(_m); if(test_max_contacts(_m, _r, _c, ci, maxc) != 0) goto error; } } #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) { e_max = -1; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif _c = get_first_contact(_m); updated=0; for( ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &expires); /* pack the contact info */ if ( (ci=pack_ci( 0, _c, expires, 0, _use_regid))==0 ) { LM_ERR("failed to pack contact specific info\n"); goto error; } /* search for the contact*/ ret = ul.get_ucontact_by_instance( _r, &_c->uri, ci, &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) { if(expires!=0 && _mode) break; continue; } if ( ret > 0 ) { /* Contact not found -> expired? */ if (expires==0) continue; if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } rc = 1; if(_mode) { ptr=_r->contacts; while(ptr) { ptr0 = ptr->next; if(ptr!=c) ul.delete_ucontact(_r, ptr); ptr=ptr0; } updated=1; } } else { /* Contact found */ if (expires == 0) { /* it's expired */ if (mem_only) { 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; } rc = 3; } else { /* do update */ if(_mode) { ptr=_r->contacts; while(ptr) { ptr0 = ptr->next; if(ptr!=c) ul.delete_ucontact(_r, ptr); ptr=ptr0; } updated=1; } /* If call-id has changed then delete all records with this sip.instance then insert new record */ if (ci->instance.s != NULL && (ci->callid->len != c->callid.len || strncmp(ci->callid->s, c->callid.s, ci->callid->len) != 0)) { ptr = _r->contacts; while (ptr) { ptr0 = ptr->next; if ((ptr != c) && ptr->instance.len == c->instance.len && strncmp(ptr->instance.s, c->instance.s, ptr->instance.len) == 0) { ul.delete_ucontact(_r, ptr); } ptr = ptr0; } updated = 1; } if (ul.update_ucontact(_r, c, ci) < 0) { rerrno = R_UL_UPD_C; LM_ERR("failed to update contact\n"); goto error; } rc = 2; } } #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 || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) { if (e_max>0) { LM_WARN("multiple TCP contacts on single REGISTER\n"); } if (expires>e_max) e_max = expires; } } #endif /* have one contact only -- break */ if(updated) break; } #ifdef USE_TCP if ( tcp_check && e_max>-1 ) { if (e_max) e_max -= act_time; /*FIXME: Do we want this in the sr core? */ /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/ } #endif return rc; error: return -1; }
/*! \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; }
/*! \brief * Message contained some contacts, but record with same address * of record was not found so we have to create a new record * and insert all contacts from the message that have expires * > 0 */ static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a, int _use_regid) { ucontact_info_t* ci; urecord_t* r = NULL; ucontact_t* c; contact_t* _c; unsigned int flags; int num, expires; int maxc; #ifdef USE_TCP int e_max, tcp_check; struct sip_uri uri; #endif sip_uri_t *u; u = parse_to_uri(_m); if(u==NULL) goto error; flags = mem_only; #ifdef USE_TCP if ( (_m->flags&tcp_persistent_flag) && (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS ||_m->rcv.proto==PROTO_WS||_m->rcv.proto==PROTO_WSS)) { e_max = 0; tcp_check = 1; } else { e_max = tcp_check = 0; } #endif _c = get_first_contact(_m); maxc = reg_get_crt_max_contacts(); for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &expires); /* Skip contacts with zero expires */ if (expires == 0) continue; if (maxc > 0 && num >= maxc) { LM_INFO("too many contacts (%d) for AOR <%.*s>\n", num, _a->len, _a->s); rerrno = R_TOO_MANY; goto error; } num++; if (r==0) { if (ul.insert_urecord(_d, _a, &r) < 0) { rerrno = R_UL_NEW_R; LM_ERR("failed to insert new record structure\n"); goto error; } } /* pack the contact_info */ if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags, _use_regid))==0 ) { LM_ERR("failed to extract contact info\n"); goto error; } /* hack to work with buggy clients having many contacts with same * address in one REGISTER - increase CSeq to detect if there was * one already added, then update */ ci->cseq++; if ( r->contacts==0 || ul.get_ucontact_by_instance(r, &_c->uri, ci, &c) != 0) { ci->cseq--; 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 { ci->cseq--; 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 || uri.proto==PROTO_WS || uri.proto==PROTO_WSS) { if (e_max) { LM_WARN("multiple TCP contacts on single REGISTER\n"); if (expires>e_max) e_max = expires; } else { e_max = expires; } } } #endif } if (r) { if (r->contacts) build_contact(_m, r->contacts, &u->host); ul.release_urecord(r); } else { /* No contacts found */ build_contact(_m, NULL, &u->host); } #ifdef USE_TCP if ( tcp_check && e_max>0 ) { e_max -= act_time; /*FIXME: Do we want this in the sr core?*/ /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/ } #endif return 0; error: if (r) ul.delete_urecord(_d, _a, r); return -1; }