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; }
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; }
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; }
/*! \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, 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; }
/* * 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; }
/* * 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; rcv_avp.n=rcv_avp_no; if (isflagset(_m, nat_flag) == 1) flags = FL_NAT; else flags = FL_NONE; 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 (ul.insert_ucontact(r, &_c->uri, e, q, &callid, cseq, flags, &c, ua, recv) < 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 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, 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; }
/* * 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; }
/* * 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, str* aor, contact_t* _c, udomain_t* _d, str* _u, str *ua, str* aor_filter) { urecord_t* r = 0; ucontact_t* c; int e, cseq; qvalue_t q; str callid; unsigned int flags; str *recv, *inst; int num; if (isflagset(_m, save_nat_flag) == 1) flags = FL_NAT; else flags = FL_NONE; 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, _u); return -1; } num++; if (r == 0) { if (ul.insert_urecord(_d, _u, &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, _u); 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, _u); return -4; } if (_c->received) { recv = &_c->received->body; } else if (flags & FL_NAT) { if (create_rcv_uri(&recv, _m) < 0) { ERR("Error while creating rcv URI\n"); ul.delete_urecord(_d, _u); return -4; } } else { recv = 0; } if(_c->instance) { inst = &_c->instance->body; } else { inst = 0; } if (ul.insert_ucontact(r, aor, &_c->uri, e, q, &callid, cseq, flags, &c, ua, recv, _m->rcv.bind_address, inst) < 0) { rerrno = R_UL_INS_C; LOG(L_ERR, "insert(): Error while inserting contact\n"); ul.delete_urecord(_d, _u); return -5; } skip: _c = get_next_contact(_c); } if (r) { if (!r->contacts) { ul.delete_urecord(_d, _u); } else { build_contact(r->contacts, aor_filter); } } return 0; }
static void received_contact_add_request(gint fd) { gchar *vcard; gchar *msg; gboolean add_successful; ItemPerson *person; add_successful = FALSE; vcard = get_next_contact(); if (vcard) { AlertValue val; val = G_ALERTALTERNATE; if (opensync_config.contact_ask_add) { msg = g_strdup_printf(_("Really add contact:\n%s?"),vcard); val = alertpanel(_("OpenSync plugin"),msg, GTK_STOCK_CANCEL,GTK_STOCK_ADD,NULL); g_free(msg); } if (!opensync_config.contact_ask_add || (val != G_ALERTDEFAULT)) { gchar *path = NULL; AddressDataSource *book = NULL; ItemFolder *folder = NULL; AddressBookFile *abf = NULL; if(opensync_config.addrbook_choice == OPENSYNC_ADDRESS_BOOK_INDIVIDUAL) path = addressbook_folder_selection(NULL); if(!path) path = g_strdup(opensync_config.addrbook_folderpath); if (addressbook_peek_folder_exists(path, &book, &folder) && book) { abf = book->rawDataSource; person = addrbook_add_contact(abf, folder, "", "", ""); person->status = ADD_ENTRY; update_ItemPerson_from_vcard(abf, person, vcard); add_successful = TRUE; } else g_warning("addressbook folder not found '%s'\n", path); g_free(path); } else { g_print("Error: User refused to add contact '%s'\n", vcard); } } else { g_print("Error: Not able to get the contact to add\n"); } if(add_successful) { gchar *return_vcard; return_vcard = vcard_get_from_ItemPerson(person); sock_send(fd, ":start_contact:\n"); msg = g_strdup_printf("%s\n", return_vcard); g_free(return_vcard); sock_send(fd, msg); g_free(msg); sock_send(fd, ":end_contact:\n"); } else { sock_send(fd, ":failure:\n"); } g_free(vcard); }
/* * 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; }