/* * 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(struct sip_msg* _m, contact_t* _c, udomain_t* _d, str* _a, str *ua) { urecord_t* r = 0; ucontact_t* c; int e, cseq; qvalue_t q; str callid; unsigned int flags; str* recv; int_str rcv_avp; int_str val; int num; struct socket_info *sock; rcv_avp.n=rcv_avp_no; /* is nated flag */ if (nat_flag!=-1 && _m->flags&nat_flag) flags = FL_NAT; else flags = FL_NONE; /* nat type flag */ if (sip_natping_flag!=-1 && _m->flags&sip_natping_flag) flags |= FL_NAT_SIPPING; flags |= mem_only; num = 0; while(_c) { if (calc_contact_expires(_m, _c->expires, &e) < 0) { LOG(L_ERR, "insert(): Error while calculating expires\n"); return -1; } /* Skip contacts with zero expires */ if (e == 0) goto skip; if (max_contacts && (num >= max_contacts)) { rerrno = R_TOO_MANY; ul.delete_urecord(_d, _a); return -1; } num++; if (r == 0) { if (ul.insert_urecord(_d, _a, &r) < 0) { rerrno = R_UL_NEW_R; LOG(L_ERR, "insert(): Can't insert new record structure\n"); return -2; } } /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "insert(): Error while calculating q\n"); ul.delete_urecord(_d, _a); return -3; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&get_cseq(_m)->number, (unsigned int*)&cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "insert(): Error while converting cseq number\n"); ul.delete_urecord(_d, _a); return -4; } if (_c->received) { recv = &_c->received->body; } else if (search_first_avp(0, rcv_avp, &val)) { recv = val.s; } else { recv = 0; } if (sock_flag!=-1 && (_m->flags&sock_flag)!=0) { sock = get_sock_hdr(_m); if (sock==0) sock = _m->rcv.bind_address; } else { sock = _m->rcv.bind_address; } if (ul.insert_ucontact(r, &_c->uri, e, q, &callid, cseq, flags, &c, ua, recv, sock) < 0) { rerrno = R_UL_INS_C; LOG(L_ERR, "insert(): Error while inserting contact\n"); ul.delete_urecord(_d, _a); return -5; } skip: _c = get_next_contact(_c); } if (r) { if (!r->contacts) { ul.delete_urecord(_d, _a); } else { build_contact(r->contacts); } } return 0; }
/*! \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) { 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))==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 alredy 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; }
/*! \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; int e_max; int tcp_check; struct sip_uri uri; cflags = (_sctx->flags®_SAVE_MEMORY_FLAG)?FL_MEM:FL_NONE; if (is_tcp_based_proto(_m->rcv.proto) && (_m->flags&tcp_persistent_flag)) { e_max = 0; tcp_check = 1; } else { e_max = tcp_check = 0; } for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) { /* calculate expires */ calc_contact_expires(_m, _c->expires, &e, _sctx); /* 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)!=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) < 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) < 0) { rerrno = R_UL_INS_C; LM_ERR("failed to insert contact\n"); goto error; } } else { 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) { LM_WARN("multiple TCP contacts on single REGISTER\n"); if (e>e_max) e_max = e; } else { e_max = e; } } } } if (r) { if (r->contacts) { build_contact(r->contacts,_m); } ul.release_urecord(r, 0); } if ( tcp_check && e_max>0 ) { e_max -= act_time; trans_set_dst_attr( &_m->rcv, DST_FCNTL_SET_LIFETIME, (void*)(long)(e_max + 10) ); } return 0; error: if (r) ul.delete_urecord(_d, _a, r, 0); return -1; }