/* * Process REGISTER request and save it's contacts */ static inline int save_real(struct sip_msg* _m, udomain_t* _t, char* _s, int doreply) { contact_t* c; int st; str aor, ua; rerrno = R_FINE; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } get_act_time(); c = get_first_contact(_m); if (extract_aor(&get_to(_m)->uri, &aor) < 0) { LOG(L_ERR, "save(): Error while extracting Address Of Record\n"); goto error; } ua.len = 0; if (parse_headers(_m, HDR_USERAGENT, 0) != -1 && _m->user_agent && _m->user_agent->body.len > 0) { ua.len = _m->user_agent->body.len; ua.s = _m->user_agent->body.s; } if (ua.len == 0) { ua.len = UA_DUMMY_LEN; ua.s = UA_DUMMY_STR; } if (c == 0) { if (st) { if (star(_t, &aor) < 0) goto error; } else { if (no_contacts(_t, &aor) < 0) goto error; } } else { if (contacts(_m, c, _t, &aor, &ua) < 0) goto error; } if (doreply && (send_reply(_m) < 0)) return -1; else return 1; error: if (doreply) send_reply(_m); return 0; }
int save(struct sip_msg* _m, char* _d, char* _f, char* _s) { struct sip_msg* msg = _m; struct cell* t = NULL; contact_t* _c; contact_t* reply_c = NULL; contact_t* request_c = NULL; int st; int ret; int requested_exp = 0; int enforced_exp = 0; int_str val; struct lump* l; char* p; char forced_binding_buf[MAX_FORCED_BINDING_LEN]; str forced_binding = {NULL, 0}; str *binding_uri; if(_m->first_line.type != SIP_REPLY) return save_aux(_m, NULL, _d, _f, _s); memset(&val, 0, sizeof(int_str)); if(!tmb.t_gett) { LM_ERR("TM module not loaded - can not save on reply\n"); return -1; } t = tmb.t_gett(); if(!t || t==T_UNDEFINED) { LM_ERR("Transaction not created on Register - can not save on reply\n"); return -1; } msg = t->uas.request; if(!msg) { LM_ERR("NULL request - can not save on reply\n"); return -1; } if (parse_message(_m) < 0) return -1; if (check_contacts(_m, &st) > 0) return -1; if (parse_message(msg) < 0) return -1; if (check_contacts(msg, &st) > 0) return -1; /* msg - request _m - reply */ request_c = get_first_contact(msg); if(request_c) { /* For now, we deal only with the first contact * FIXME: implement multiple contact handling - see check_contacts() */ if(!request_c->expires || !request_c->expires->body.len) { if (((exp_body_t*)(msg->expires->parsed))->valid) { requested_exp = ((exp_body_t*)(msg->expires->parsed))->val; } else { LM_WARN("No expired defined\n"); } } else { if (str2int(&(request_c->expires->body), (unsigned int*)&requested_exp)<0) { LM_ERR("unable to get expires from [%.*s]\n", request_c->expires->body.len, request_c->expires->body.s); return -1; } } LM_DBG("Binding received from client [%.*s] with requested expires [%d]\n", request_c->uri.len, request_c->uri.s, requested_exp); /* We will use the Contact from request: * - check if a modified contact was set in avp */ if (mct_avp_name >= 0 && search_first_avp(mct_avp_type,mct_avp_name,&val,0) && val.s.len > 0) { LM_DBG("Binding sent to upper registrar [%.*s]\n", val.s.len, val.s.s); binding_uri = &val.s; } else { binding_uri = &request_c->uri; } if (requested_exp) { /* Let's get the contact from reply */ _c = get_first_contact(_m); while (_c) { if (compare_uris(binding_uri, NULL, &_c->uri, NULL) == 0) { if(_c->expires && _c->expires->body.len) { if(str2int(&(_c->expires->body), (unsigned int*)&enforced_exp)<0) { LM_ERR("unable to get expires from [%.*s]\n", _c->expires->body.len, _c->expires->body.s); return -1; } LM_DBG("Binding received from upper registrar" " [%.*s] with imposed expires [%d]\n", _c->uri.len, _c->uri.s, enforced_exp); reply_c = _c; forced_binding.len = request_c->uri.len + 11 + reply_c->expires->body.len; if (forced_binding.len <= MAX_FORCED_BINDING_LEN) { forced_binding.s = forced_binding_buf; forced_binding_buf[0] = '<'; memcpy(&forced_binding_buf[1], request_c->uri.s, request_c->uri.len); memcpy(&forced_binding_buf[request_c->uri.len + 1], ">;expires=", 10); memcpy(&forced_binding_buf[request_c->uri.len + 11], reply_c->expires->body.s, reply_c->expires->body.len); LM_DBG("forcing binding [%.*s]\n", forced_binding.len, forced_binding.s); break; } else { LM_ERR("forced binding to BIG:" " %d > MAX_FORCED_BINDING_LEN\n", forced_binding.len); return -1; } } } else { LM_DBG("Unmatched binding [%.*s]\n", _c->uri.len, _c->uri.s); } _c = get_next_contact(_c); } } ret = save_aux(msg, forced_binding.s?&forced_binding:NULL, _d, _f, _s); } else { LM_DBG("No Contact in request => this is an interogation\n"); ret = 1; } /* if the contact was changed in register - put the modif value */ if(request_c && requested_exp && val.s.s) { if(reply_c) { LM_DBG("replacing contact uri [%.*s] with [%.*s]\n", reply_c->uri.len, reply_c->uri.s, request_c->uri.len, request_c->uri.s); /* replace with what was received in Register */ /* reply_c->uri - now contains the initial received value */ if((l=del_lump(_m, reply_c->uri.s - _m->buf, reply_c->uri.len, 0))==0) { LM_ERR("Failed to delete contact uri lump\n"); ret = -1; goto done; } p = pkg_malloc( request_c->uri.len); if (p==0) { LM_ERR("no more pkg mem\n"); ret = -1; goto done; } memcpy( p, request_c->uri.s, request_c->uri.len ); if (insert_new_lump_after( l, p, request_c->uri.len, 0)==0) { LM_ERR("insert new lump failed\n"); pkg_free(p); ret =-1; goto done; } } } done: clean_msg_clone(t->uas.request, t->uas.request, t->uas.end_request); return ret; }
int save_aux(struct sip_msg* _m, str* forced_binding, char* _d, char* _f, char* _s) { struct save_ctx sctx; contact_t* c; contact_t* forced_c; int st; str uri; str flags_s; pv_value_t val; rerrno = R_FINE; memset( &sctx, 0 , sizeof(sctx)); sctx.max_contacts = -1; sctx.flags = 0; if (_f && _f[0]!=0) { if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) { LM_ERR("invalid flags parameter"); return -1; } for( st=0 ; st< flags_s.len ; st++ ) { switch (flags_s.s[st]) { case 'm': sctx.flags |= REG_SAVE_MEMORY_FLAG; break; case 'r': sctx.flags |= REG_SAVE_NOREPLY_FLAG; break; case 's': sctx.flags |= REG_SAVE_SOCKET_FLAG; break; case 'v': sctx.flags |= REG_SAVE_PATH_RECEIVED_FLAG; break; case 'f': sctx.flags |= REG_SAVE_FORCE_REG_FLAG; break; case 'c': sctx.max_contacts = 0; while (st<flags_s.len-1 && isdigit(flags_s.s[st+1])) { sctx.max_contacts = sctx.max_contacts*10 + flags_s.s[st+1] - '0'; st++; } break; case 'p': if (st<flags_s.len-1) { st++; if (flags_s.s[st]=='2') { sctx.flags |= REG_SAVE_PATH_STRICT_FLAG; break; } if (flags_s.s[st]=='1') { sctx.flags |= REG_SAVE_PATH_LAZY_FLAG; break; } if (flags_s.s[st]=='0') { sctx.flags |= REG_SAVE_PATH_OFF_FLAG; break; } } default: LM_WARN("unsuported flag %c \n",flags_s.s[st]); } } } if(route_type == ONREPLY_ROUTE) sctx.flags |= REG_SAVE_NOREPLY_FLAG; /* if no max_contact per AOR is defined, use the global one */ if (sctx.max_contacts == -1) sctx.max_contacts = max_contacts; if (parse_message(_m) < 0) { goto error; } if (forced_binding) { if (parse_contacts(forced_binding, &forced_c) < 0) { LM_ERR("Unable to parse forced binding [%.*s]\n", forced_binding->len, forced_binding->s); goto error; } /* prevent processing all the headers from the message */ reset_first_contact(); st = 0; c = forced_c; } else { if (check_contacts(_m, &st) > 0) { goto error; } c = get_first_contact(_m); } get_act_time(); 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 { uri = get_to(_m)->uri; } if (extract_aor( &uri, &sctx.aor) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } if (c == 0) { if (st) { if (star((udomain_t*)_d, &sctx) < 0) goto error; } else { if (no_contacts((udomain_t*)_d, &sctx.aor) < 0) goto error; } } else { if (add_contacts(_m, c, (udomain_t*)_d, &sctx) < 0) goto error; } update_stat(accepted_registrations, 1); if (!is_cflag_set(REG_SAVE_NOREPLY_FLAG) && (send_reply(_m,sctx.flags)<0)) return -1; return 1; error: update_stat(rejected_registrations, 1); if ( !is_cflag_set(REG_SAVE_NOREPLY_FLAG) ) send_reply(_m,sctx.flags); return 0; }
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri) { contact_t* c; int st, mode; str aor; int ret; sip_uri_t *u; rr_t *route; struct sip_uri puri; param_hooks_t hooks; param_t *params; contact_t *contact; int use_ob = 1, use_regid = 1; u = parse_to_uri(_m); if(u==NULL) goto error; rerrno = R_FINE; ret = 1; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } if (parse_supported(_m) == 0) { if (!(get_supported(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) { LM_WARN("Outbound required by server and not supported by UAC\n"); rerrno = R_OB_UNSUP; goto error; } } if (parse_require(_m) == 0) { if ((get_require(_m) & F_OPTION_TAG_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_NONE) { LM_WARN("Outbound required by UAC and not supported by server\n"); rerrno = R_OB_REQD; goto error; } } if (reg_outbound_mode != REG_OUTBOUND_NONE && _m->contact && _m->contact->parsed && !(parse_headers(_m, HDR_VIA2_F, 0) == -1 || _m->via2 == 0 || _m->via2->error != PARSE_OK)) { /* Outbound supported on server, and more than one Via: - not the first hop */ if (!(parse_headers(_m, HDR_PATH_F, 0) == -1 || _m->path == 0)) { route = (rr_t *)0; if (parse_rr_body(_m->path->body.s, _m->path->body.len, &route) < 0) { LM_ERR("Failed to parse Path: header body\n"); goto error; } if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) { LM_ERR("Failed to parse Path: URI\n"); goto error; } if (parse_params(&puri.params, CLASS_URI, &hooks, ¶ms) != 0) { LM_ERR("Failed to parse Path: URI parameters\n"); goto error; } if (!hooks.uri.ob) { /* No ;ob parameter to top Path: URI - no outbound */ use_ob = 0; } } else { /* No Path: header - no outbound */ use_ob = 0; } contact = ((contact_body_t *) _m->contact->parsed)->contacts; if (!contact) { LM_ERR("empty Contact:\n"); goto error; } if ((use_ob == 0) && (reg_regid_mode == REG_REGID_OUTBOUND)) { if ((get_supported(_m) & F_OPTION_TAG_OUTBOUND) && contact->reg_id) { LM_WARN("Outbound used by UAC but not supported by edge proxy\n"); rerrno = R_OB_UNSUP_EDGE; goto error; } else { /* ignore ;reg-id parameter */ use_regid = 0; } } } get_act_time(); c = get_first_contact(_m); if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE; if (c == 0) { if (st) { if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=3; } else { if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=4; } } else { mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0; if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode, use_regid)) < 0) goto error; ret = (ret==0)?1:ret; } update_stat(accepted_registrations, 1); /* Only send reply upon request, not upon reply */ if ((is_route_type(REQUEST_ROUTE) || is_route_type(FAILURE_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0)) return -1; return ret; error: update_stat(rejected_registrations, 1); if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) ) reg_send_reply(_m); return 0; }
/* * 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(struct sip_msg* _m, urecord_t* _r, contact_t* _c, str* _ua) { ucontact_t* c, *c2; str callid; int cseq, e, ret; int set, reset; qvalue_t q; unsigned int nated; str* recv; int_str rcv_avp; int_str val; rcv_avp.n=rcv_avp_no; if (isflagset(_m, nat_flag) == 1) { nated = FL_NAT; } else { nated = FL_NONE; } if (max_contacts) { ret = test_max_contacts(_m, _r, _c); if (ret != 0) { build_contact(_r->contacts); return -1; } } _c = get_first_contact(_m); while(_c) { if (calc_contact_expires(_m, _c->expires, &e) < 0) { build_contact(_r->contacts); LOG(L_ERR, "update(): Error while calculating expires\n"); return -1; } if (ul.get_ucontact(_r, &_c->uri, &c) > 0) { /* Contact not found */ if (e != 0) { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -2; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*) &cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "update(): Error while converting cseq number\n"); return -3; } if (_c->received) { recv = &_c->received->body; } else if (search_first_avp(0, rcv_avp, &val)) { recv = val.s; } else { recv = 0; } if (ul.insert_ucontact(_r, &_c->uri, e, q, &callid, cseq, nated | mem_only, &c2, _ua, recv) < 0) { rerrno = R_UL_INS_C; LOG(L_ERR, "update(): Error while inserting contact\n"); return -4; } } } else { if (e == 0) { if (mem_only) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c) < 0) { rerrno = R_UL_DEL_C; LOG(L_ERR, "update(): Error while deleting contact\n"); return -5; } } else { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -6; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*)&cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "update(): Error while converting cseq number\n"); return -7; } if (_c->received) { recv = &_c->received->body; } else if (search_first_avp(0, rcv_avp, &val)) { recv = val.s; } else { recv = 0; } set = nated | mem_only; reset = ~(nated | mem_only) & (FL_NAT | FL_MEM); if (ul.update_ucontact(c, e, q, &callid, cseq, set, reset, _ua, recv) < 0) { rerrno = R_UL_UPD_C; LOG(L_ERR, "update(): Error while updating contact\n"); return -8; } if (desc_time_order) { move_on_top(_r, c); } } } _c = get_next_contact(_c); } 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, 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; }
/*! \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; }
/* * Process REGISTER request and save it's contacts */ static inline int save_real(struct sip_msg* _m, udomain_t* _t, char* aor_filt, int doreply) { contact_t* c; int st; str uid, ua, aor_filter; rerrno = R_FINE; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } if (aor_filt) { if (get_str_fparam(&aor_filter, _m, (fparam_t*)aor_filt) != 0) { ERR("registrar:save: Unable to get the AOR value\n"); return -1; } } else { aor_filter.s = 0; aor_filter.len = 0; } get_act_time(); c = get_first_contact(_m); if (get_to_uid(&uid, _m) < 0) goto error; ua.len = 0; if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent && _m->user_agent->body.len > 0) { ua.len = _m->user_agent->body.len; ua.s = _m->user_agent->body.s; } if (ua.len == 0) { ua.len = UA_DUMMY_LEN; ua.s = UA_DUMMY_STR; } if (c == 0) { if (st) { if (star(_t, &uid, &aor_filter) < 0) goto error; } else { if (no_contacts(_t, &uid, &aor_filter) < 0) goto error; } } else { if (contacts(_m, c, _t, &uid, &ua, &aor_filter) < 0) goto error; } if (doreply) { if (send_reply(_m) < 0) return -1; } else { /* No reply sent, create attributes with values * of reply code, reason text, and contacts */ if (setup_attrs(_m) < 0) return -1; } return 1; error: if (doreply) { send_reply(_m); return 0; } return -2; }
/* * 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(struct sip_msg* _m, urecord_t* _r, str* aor, contact_t* _c, str* _ua, str* aor_filter) { ucontact_t* c, *c2; str callid; int cseq, e, ret; int set, reset; qvalue_t q; unsigned int nated; str* recv, *inst; if (isflagset(_m, save_nat_flag) == 1) { nated = FL_NAT; } else { nated = FL_NONE; } if (max_contacts) { ret = test_max_contacts(_m, _r, _c); if (ret != 0) { build_contact(_r->contacts, aor_filter); return -1; } } _c = get_first_contact(_m); while(_c) { if (calc_contact_expires(_m, _c->expires, &e) < 0) { build_contact(_r->contacts, aor_filter); LOG(L_ERR, "update(): Error while calculating expires\n"); return -1; } if(_c->instance) { inst = &_c->instance->body; } else { inst = 0; } if (ul.get_ucontact_by_instance(_r, &_c->uri, inst, &c) > 0) { /* Contact not found */ if (e != 0) { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -2; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*) &cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "update(): Error while converting cseq number\n"); return -3; } if (_c->received) { recv = &_c->received->body; } else if (nated & FL_NAT) { if (create_rcv_uri(&recv, _m) < 0) { ERR("Error while creating rcv URI\n"); rerrno = R_UL_INS_C; return -4; } } else { recv = 0; } if (ul.insert_ucontact(_r, aor, &_c->uri, e, q, &callid, cseq, nated | mem_only, &c2, _ua, recv, _m->rcv.bind_address, inst) < 0) { rerrno = R_UL_INS_C; LOG(L_ERR, "update(): Error while inserting contact\n"); return -4; } } } else { if (e == 0) { if (mem_only) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c) < 0) { rerrno = R_UL_DEL_C; LOG(L_ERR, "update(): Error while deleting contact\n"); return -5; } } else { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -6; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*)&cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "update(): Error while converting cseq number\n"); return -7; } if (_c->received) { recv = &_c->received->body; } else if (nated & FL_NAT) { if (create_rcv_uri(&recv, _m) < 0) { ERR("Error while creating rcv URI\n"); rerrno = R_UL_UPD_C; return -4; } } else { recv = 0; } set = nated | mem_only; reset = ~(nated | mem_only) & (FL_NAT | FL_MEM); if (ul.update_ucontact(c, &_c->uri, aor, e, q, &callid, cseq, set, reset, _ua, recv, _m->rcv.bind_address, inst) < 0) { rerrno = R_UL_UPD_C; LOG(L_ERR, "update(): Error while updating contact\n"); return -8; } } } _c = get_next_contact(_c); } return 0; }
int save_aux(struct sip_msg* _m, str* forced_binding, void* _d, str* flags_s, str* uri, str* _owtag) { struct save_ctx sctx; contact_t* c; contact_t* forced_c = NULL; int st; rerrno = R_FINE; memset( &sctx, 0 , sizeof(sctx)); sctx.max_contacts = -1; sctx.flags = 0; sctx.min_expires = min_expires; sctx.max_expires = max_expires; if ( flags_s ) { for( st=0 ; st< flags_s->len ; st++ ) { switch (flags_s->s[st]) { case 'm': sctx.flags |= REG_SAVE_MEMORY_FLAG; break; case 'r': sctx.flags |= REG_SAVE_NOREPLY_FLAG; break; case 's': sctx.flags |= REG_SAVE_SOCKET_FLAG; break; case 'v': sctx.flags |= REG_SAVE_PATH_RECEIVED_FLAG; break; case 'f': sctx.flags |= REG_SAVE_FORCE_REG_FLAG; break; case 'c': sctx.max_contacts = 0; while (st<flags_s->len-1 && isdigit(flags_s->s[st+1])) { sctx.max_contacts = sctx.max_contacts*10 + flags_s->s[st+1] - '0'; st++; } break; case 'e': sctx.min_expires = 0; while (st<flags_s->len-1 && isdigit(flags_s->s[st+1])) { sctx.min_expires = sctx.min_expires*10 + flags_s->s[st+1] - '0'; st++; } break; case 'E': sctx.max_expires = 0; while (st<flags_s->len-1 && isdigit(flags_s->s[st+1])) { sctx.max_expires = sctx.max_expires*10 + flags_s->s[st+1] - '0'; st++; } break; case 'p': if (st<flags_s->len-1) { st++; if (flags_s->s[st]=='2') { sctx.flags |= REG_SAVE_PATH_STRICT_FLAG; break; } if (flags_s->s[st]=='1') { sctx.flags |= REG_SAVE_PATH_LAZY_FLAG; break; } if (flags_s->s[st]=='0') { sctx.flags |= REG_SAVE_PATH_OFF_FLAG; break; } } default: LM_WARN("unsupported flag %c \n",flags_s->s[st]); } } } if(route_type == ONREPLY_ROUTE) sctx.flags |= REG_SAVE_NOREPLY_FLAG; /* if no max_contact per AOR is defined, use the global one */ if (sctx.max_contacts == -1) sctx.max_contacts = max_contacts; if (parse_reg_headers(_m) < 0) { goto error; } if (forced_binding) { if (parse_contacts(forced_binding, &forced_c) < 0) { LM_ERR("Unable to parse forced binding [%.*s]\n", forced_binding->len, forced_binding->s); goto error; } /* prevent processing all the headers from the message */ reset_first_contact(); st = 0; c = forced_c; } else { if (check_contacts(_m, &st) > 0) { goto error; } c = get_first_contact(_m); } update_act_time(); if (!uri) uri = &(get_to(_m)->uri); if (_owtag) sctx.ownership_tag = *_owtag; if (extract_aor(uri, &sctx.aor,0,0) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } if (c == 0) { if (st) { if (star((udomain_t*)_d, &sctx,_m) < 0) goto error; } else { if (no_contacts((udomain_t*)_d, &sctx.aor,_m) < 0) goto error; } } else { if (add_contacts(_m, c, (udomain_t*)_d, &sctx) < 0) goto error; } update_stat(accepted_registrations, 1); if (!is_cflag_set(REG_SAVE_NOREPLY_FLAG) && (send_reply(_m,sctx.flags)<0)) goto return_minus_one; if (forced_c) free_contacts(&forced_c); return 1; error: update_stat(rejected_registrations, 1); if ( !is_cflag_set(REG_SAVE_NOREPLY_FLAG) ) send_reply(_m,sctx.flags); if (forced_c) free_contacts(&forced_c); return -2; return_minus_one: if (forced_c) free_contacts(&forced_c); return -1; }
int save(struct sip_msg* _m, udomain_t* _d, int _cflags, str *_uri) { contact_t* c; int st, mode; str aor; int ret; sip_uri_t *u; u = parse_to_uri(_m); if(u==NULL) goto error; rerrno = R_FINE; ret = 1; if (parse_message(_m) < 0) { goto error; } if (check_contacts(_m, &st) > 0) { goto error; } if (parse_supported(_m) == 0) { if (!(((struct supported_body *)_m->supported->parsed)->supported_all & F_SUPPORTED_OUTBOUND) && reg_outbound_mode == REG_OUTBOUND_REQUIRE) { LM_WARN("Outbound required by server and not supported by UAC\n"); rerrno = R_OB_UNSUP; goto error; } } get_act_time(); c = get_first_contact(_m); if (extract_aor((_uri)?_uri:&get_to(_m)->uri, &aor, NULL) < 0) { LM_ERR("failed to extract Address Of Record\n"); goto error; } mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE; if (c == 0) { if (st) { if (star(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=3; } else { if (no_contacts(_m, (udomain_t*)_d, &aor, &u->host) < 0) goto error; else ret=4; } } else { mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0; if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0) goto error; ret = (ret==0)?1:ret; } update_stat(accepted_registrations, 1); /* Only send reply upon request, not upon reply */ if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0)) return -1; return ret; error: update_stat(rejected_registrations, 1); if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) ) reg_send_reply(_m); return 0; }
/* * 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(struct sip_msg* _m, urecord_t* _r, contact_t* _c, str* _ua) { ucontact_t* c, *c2; str callid; int cseq, e; int set, reset; qvalue_t q; unsigned int flags; str* recv; int_str rcv_avp; int_str val; 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; if (max_contacts) { if (test_max_contacts(_m, _r, _c) != 0 ) return -1; } _c = get_first_contact(_m); while(_c) { if (calc_contact_expires(_m, _c->expires, &e) < 0) { LOG(L_ERR, "update(): Error while calculating expires\n"); return -1; } if (ul.get_ucontact(_r, &_c->uri, &c) > 0) { /* Contact not found */ if (e != 0) { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -2; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*) &cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR, "update(): Error while converting cseq number\n"); return -3; } 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 | mem_only, &c2, _ua, recv, sock) < 0) { rerrno = R_UL_INS_C; LOG(L_ERR, "update(): Error while inserting contact\n"); return -4; } } } else { if (e == 0) { if (mem_only) { c->flags |= FL_MEM; } else { c->flags &= ~FL_MEM; } if (ul.delete_ucontact(_r, c) < 0) { rerrno = R_UL_DEL_C; LOG(L_ERR, "update(): Error while deleting contact\n"); return -5; } } else { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &q) < 0) { LOG(L_ERR, "update(): Error while calculating q\n"); return -6; } /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); /* Get CSeq number of the message */ if (str2int(&(((struct cseq_body*)_m->cseq->parsed)->number), (unsigned int*)&cseq) < 0) { rerrno = R_INV_CSEQ; LOG(L_ERR,"update(): Error while converting cseq number\n"); return -7; } 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; } set = flags | mem_only; reset = ~(flags | mem_only) & (FL_NAT|FL_MEM|FL_NAT_SIPPING); if (ul.update_ucontact(c, e, q, &callid, cseq, set, reset, _ua, recv, sock) < 0) { rerrno = R_UL_UPD_C; LOG(L_ERR, "update(): Error while updating contact\n"); return -8; } if (desc_time_order) { move_on_top(_r, c); } } } _c = get_next_contact(_c); } return 0; }