static int pv_get_sruid_val(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { if(res==NULL) return -1; if(sruid_next(&_kex_sruid)<0) return pv_get_null(msg, param, res); return pv_get_strval(msg, param, res, &_kex_sruid.uid); }
/*! * \brief Add a new contact for an address of record * \param cmd mi_root containing the parameter * \param param not used * \note Expects 7 nodes: table name, AOR, contact, expires, Q, * useless - backward compatible, flags, cflags, methods * \return mi_root with the result */ struct mi_root* mi_usrloc_add(struct mi_root *cmd, void *param) { ucontact_info_t ci; urecord_t* r; ucontact_t* c; struct mi_node *node; udomain_t *dom; str *aor, *contact; unsigned int ui_val; int n; for( n=0,node = cmd->node.kids; n<9 && node ; n++,node=node->next ); if (n!=9 || node!=0) return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); node = cmd->node.kids; /* look for table (param 1) */ dom = mi_find_domain( &node->value ); if (dom==NULL) return init_mi_tree( 404, "Table not found", 15); /* process the aor (param 2) */ node = node->next; aor = &node->value; if ( mi_fix_aor(aor)!=0 ) return init_mi_tree( 400, "Domain missing in AOR", 21); /* contact (param 3) */ node = node->next; contact = &node->value; memset( &ci, 0, sizeof(ucontact_info_t)); /* expire (param 4) */ node = node->next; if (str2int( &node->value, &ui_val) < 0) goto bad_syntax; ci.expires = ui_val; /* q value (param 5) */ node = node->next; if (str2q( &ci.q, node->value.s, node->value.len) < 0) goto bad_syntax; /* unused value (param 6) FIXME */ node = node->next; /* flags value (param 7) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.flags) < 0) goto bad_syntax; /* branch flags value (param 8) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.cflags) < 0) goto bad_syntax; /* methods value (param 9) */ node = node->next; if (str2int( &node->value, (unsigned int*)&ci.methods) < 0) goto bad_syntax; if(sruid_next(&_ul_sruid)<0) goto error; ci.ruid = _ul_sruid.uid; lock_udomain( dom, aor); n = get_urecord( dom, aor, &r); if ( n==1) { if (insert_urecord( dom, aor, &r) < 0) goto lock_error; c = 0; } else { if (get_ucontact( r, contact, &mi_ul_cid, &mi_ul_path, MI_UL_CSEQ+1, &c) < 0) goto lock_error; } get_act_time(); ci.callid = &mi_ul_cid; ci.user_agent = &mi_ul_ua; ci.cseq = MI_UL_CSEQ; /* 0 expires means permanent contact */ if (ci.expires!=0) ci.expires += act_time; if (c) { if (update_ucontact( r, c, &ci) < 0) goto release_error; } else { if ( insert_ucontact( r, contact, &ci, &c) < 0 ) goto release_error; } release_urecord(r); unlock_udomain( dom, aor); return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); bad_syntax: return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); release_error: release_urecord(r); lock_error: unlock_udomain( dom, aor); error: return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN); }
int process_contact(udomain_t * domain, urecord_t ** ul_record, str aor, str callid, int cseq, int expires, int event, str contact_uri) { str no_str = {0, 0}; static str no_ua = str_init("n/a"); static ucontact_info_t ci; ucontact_t * ul_contact; if (*ul_record == NULL) { switch(event) { case EVENT_REGISTERED: case EVENT_CREATED: case EVENT_REFRESHED: /* In case, no record exists and new one should be created, create a new entry for this user in the usrloc-DB */ if (ul.insert_urecord(domain, &aor, ul_record) < 0) { LM_ERR("failed to insert new user-record\n"); return RESULT_ERROR; } break; default: /* No entry in usrloc and the contact is expired, deleted, unregistered, whatever: We do not need to do anything. */ return RESULT_NO_CONTACTS; break; } } /* Make sure, no crap is in the structure: */ memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ ci.callid = &callid; /* Get CSeq number of the message */ ci.cseq = cseq; ci.sock = NULL; /* additional info from message */ ci.user_agent = &no_ua; ci.last_modified = time(0); /* set expire time */ ci.expires = time(0) + expires; /* set ruid */ if(sruid_next(&_reginfo_sruid) < 0) { LM_ERR("failed to generate ruid"); } else { ci.ruid = _reginfo_sruid.uid; } /* Now we start looking for the contact: */ if (((*ul_record)->contacts == 0) || (ul.get_ucontact(*ul_record, &contact_uri, &callid, &no_str, cseq+1, &ul_contact) != 0)) { if (ul.insert_ucontact(*ul_record, &contact_uri, &ci, &ul_contact) < 0) { LM_ERR("failed to insert new contact\n"); return RESULT_ERROR; } } else { if (ul.update_ucontact(*ul_record, ul_contact, &ci) < 0) { LM_ERR("failed to update contact\n"); return RESULT_ERROR; } } ul_contact = (*ul_record)->contacts; while (ul_contact) { if (VALID_CONTACT(ul_contact, time(0))) return RESULT_CONTACTS_FOUND; ul_contact = ul_contact->next; } return RESULT_NO_CONTACTS; }
int msrp_cmap_save(msrp_frame_t *mf) { unsigned int idx; unsigned int hid; str fpeer; #define MSRP_SBUF_SIZE 256 char sbuf[MSRP_SBUF_SIZE]; str srcaddr; str srcsock; int msize; int expires; msrp_citem_t *it; msrp_citem_t *itb; if(_msrp_cmap_head==NULL || mf==NULL) return -1; if(mf->fline.rtypeid!=MSRP_REQ_AUTH) { LM_DBG("save can be used only for AUTH\n"); return -2; } if(msrp_frame_get_expires(mf, &expires)<0) expires = msrp_auth_max_expires; if(expires<msrp_auth_min_expires) { LM_DBG("expires is lower than min value\n"); srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Min-Expires: %d\r\n", msrp_auth_min_expires); msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text, &srcaddr); return -3; } if(expires>msrp_auth_max_expires) { LM_DBG("expires is greater than max value\n"); srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Max-Expires: %d\r\n", msrp_auth_max_expires); msrp_reply(mf, &msrp_reply_423_code, &msrp_reply_423_text, &srcaddr); return -4; } if(msrp_frame_get_first_from_path(mf, &fpeer)<0) { LM_ERR("cannot get first path uri\n"); return -1; } if(sruid_next(&_msrp_sruid)<0) { LM_ERR("cannot get next msrp uid\n"); return -1; } hid = msrp_get_hashid(&_msrp_sruid.uid); idx = msrp_get_slot(hid, _msrp_cmap_head->mapsize); srcaddr.s = sbuf; if (msrp_tls_module_loaded) { memcpy(srcaddr.s, "msrps://", 8); srcaddr.s+=8; } else { memcpy(srcaddr.s, "msrp://", 7); srcaddr.s+=7; } strcpy(srcaddr.s, ip_addr2a(&mf->tcpinfo->rcv->src_ip)); strcat(srcaddr.s, ":"); strcat(srcaddr.s, int2str(mf->tcpinfo->rcv->src_port, NULL)); srcaddr.s = sbuf; srcaddr.len = strlen(srcaddr.s); srcsock = mf->tcpinfo->rcv->bind_address->sock_str; LM_DBG("saving connection info for [%.*s] [%.*s] (%u/%u)\n", fpeer.len, fpeer.s, _msrp_sruid.uid.len, _msrp_sruid.uid.s, idx, hid); LM_DBG("frame received from [%.*s] via [%.*s]\n", srcaddr.len, srcaddr.s, srcsock.len, srcsock.s); msize = sizeof(msrp_citem_t) + (_msrp_sruid.uid.len + fpeer.len + srcaddr.len + srcsock.len + 4)*sizeof(char); /* build the item */ it = (msrp_citem_t*)shm_malloc(msize); if(it==NULL) { LM_ERR("no more shm\n"); return -1; } memset(it, 0, msize); it->citemid = hid; it->sessionid.s = (char*)it + + sizeof(msrp_citem_t); it->sessionid.len = _msrp_sruid.uid.len; memcpy(it->sessionid.s, _msrp_sruid.uid.s, _msrp_sruid.uid.len); it->sessionid.s[it->sessionid.len] = '\0'; it->peer.s = it->sessionid.s + it->sessionid.len + 1; it->peer.len = fpeer.len; memcpy(it->peer.s, fpeer.s, fpeer.len); it->peer.s[it->peer.len] = '\0'; it->addr.s = it->peer.s + it->peer.len + 1; it->addr.len = srcaddr.len; memcpy(it->addr.s, srcaddr.s, srcaddr.len); it->addr.s[it->addr.len] = '\0'; it->sock.s = it->addr.s + it->addr.len + 1; it->sock.len = srcsock.len; memcpy(it->sock.s, srcsock.s, srcsock.len); it->sock.s[it->sock.len] = '\0'; it->expires = time(NULL) + expires; it->conid = mf->tcpinfo->con->id; /* insert item in cmap */ lock_get(&_msrp_cmap_head->cslots[idx].lock); if(_msrp_cmap_head->cslots[idx].first==NULL) { _msrp_cmap_head->cslots[idx].first = it; } else { for(itb=_msrp_cmap_head->cslots[idx].first; itb; itb=itb->next) { if(itb->citemid>it->citemid || itb->next==NULL) { if(itb->next==NULL) { itb->next=it; it->prev = itb; } else { it->next = itb; if(itb->prev==NULL) { _msrp_cmap_head->cslots[idx].first = it; } else { itb->prev->next = it; } it->prev = itb->prev; itb->prev = it; } break; } } } _msrp_cmap_head->cslots[idx].lsize++; lock_release(&_msrp_cmap_head->cslots[idx].lock); if(mf->tcpinfo->rcv->proto==PROTO_TLS || mf->tcpinfo->rcv->proto==PROTO_WSS) { srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Use-Path: msrps://%.*s/%.*s;tcp\r\nExpires: %d\r\n", (msrp_use_path_addr.s)?msrp_use_path_addr.len:(srcsock.len-4), (msrp_use_path_addr.s)?msrp_use_path_addr.s:(srcsock.s+4), _msrp_sruid.uid.len, _msrp_sruid.uid.s, expires); } else { srcaddr.len = snprintf(sbuf, MSRP_SBUF_SIZE, "Use-Path: msrp://%.*s/%.*s;tcp\r\nExpires: %d\r\n", (msrp_use_path_addr.s)?msrp_use_path_addr.len:(srcsock.len-4), (msrp_use_path_addr.s)?msrp_use_path_addr.s:(srcsock.s+4), _msrp_sruid.uid.len, _msrp_sruid.uid.s, expires); } srcaddr.s = sbuf; if(msrp_reply(mf, &msrp_reply_200_code, &msrp_reply_200_text, &srcaddr)<0) return -5; return 0; }
/*! \brief * Fills the common part (for all contacts) of the info structure */ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid) { static ucontact_info_t ci; static str no_ua = str_init("n/a"); static str callid; static str path_received = {0,0}; static str path; static str received = {0,0}; static int received_found; static unsigned int allowed, allow_parsed; static struct sip_msg *m = 0; int_str val; if (_m!=0) { memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); if (callid.len > CALLID_MAX_SIZE) { rerrno = R_CALLID_LEN; LM_ERR("callid too long\n"); goto error; } ci.callid = &callid; /* Get CSeq number of the message */ if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) { rerrno = R_INV_CSEQ; LM_ERR("failed to convert cseq number\n"); goto error; } /* set received socket */ if (_m->flags&sock_flag) { ci.sock = get_sock_val(_m); if (ci.sock==0) ci.sock = _m->rcv.bind_address; } else { ci.sock = _m->rcv.bind_address; } /* set tcp connection id */ if (_m->rcv.proto==PROTO_TCP || _m->rcv.proto==PROTO_TLS || _m->rcv.proto==PROTO_WS || _m->rcv.proto==PROTO_WSS) { ci.tcpconn_id = _m->rcv.proto_reserved1; } else { ci.tcpconn_id = -1; } /* additional info from message */ if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent && _m->user_agent->body.len>0 && _m->user_agent->body.len<MAX_UA_SIZE) { ci.user_agent = &_m->user_agent->body; } else { ci.user_agent = &no_ua; } /* extract Path headers */ if (path_enabled) { if (build_path_vector(_m, &path, &path_received) < 0) { rerrno = R_PARSE_PATH; goto error; } if (path.len && path.s) { ci.path = &path; if (path_mode != PATH_MODE_OFF) { /* save in msg too for reply */ if (set_path_vector(_m, &path) < 0) { rerrno = R_PARSE_PATH; goto error; } } } } ci.last_modified = act_time; /* set flags */ ci.flags = _f; getbflagsval(0, &ci.cflags); /* get received */ if (path_received.len && path_received.s) { ci.cflags |= ul.nat_flag; ci.received = path_received; } allow_parsed = 0; /* not parsed yet */ received_found = 0; /* not found yet */ m = _m; /* remember the message */ } else { memset( &ci.instance, 0, sizeof(str)); } if(_c!=0) { /* hook uri address - should be more than 'sip:' chars */ if(_c->uri.s!=NULL && _c->uri.len>4) ci.c = &_c->uri; /* Calculate q value of the contact */ if (m && m->id == q_override_msg_id) { ci.q = q_override_value; } else if (calc_contact_q(_c->q, &ci.q) < 0) { rerrno = R_INV_Q; LM_ERR("failed to calculate q\n"); goto error; } /* set expire time */ ci.expires = _e; /* Get methods of contact */ if (_c->methods) { if (parse_methods(&(_c->methods->body), &ci.methods) < 0) { rerrno = R_PARSE; LM_ERR("failed to parse contact methods\n"); goto error; } } else { /* check on Allow hdr */ if (allow_parsed == 0) { if (m && parse_allow( m ) != -1) { allowed = get_allow_methods(m); } else { allowed = ALL_METHODS; } allow_parsed = 1; } ci.methods = allowed; } /* get received */ if (ci.received.len==0) { if (_c->received) { ci.received = _c->received->body; } else { if (received_found==0) { memset(&val, 0, sizeof(int_str)); if (rcv_avp_name.n!=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) { if (val.s.len>RECEIVED_MAX_SIZE) { rerrno = R_CONTACT_LEN; LM_ERR("received too long\n"); goto error; } received = val.s; } else { received.s = 0; received.len = 0; } received_found = 1; } ci.received = received; } } if(_c->instance!=NULL && _c->instance->body.len>0) ci.instance = _c->instance->body; if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) { if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0) { LM_ERR("invalid reg-id value\n"); goto error; } } if(sruid_next(&_reg_sruid)<0) goto error; ci.ruid = _reg_sruid.uid; LM_DBG("generated ruid is: %.*s\n", ci.ruid.len, ci.ruid.s); } return &ci; error: return 0; }
/* returns : -1 - error * 0 - ok, but no contact added * n - ok and n contacts added */ static int shmcontact2dset(struct sip_msg *req, struct sip_msg *sh_rpl, long max, struct acc_param *reason, unsigned int bflags) { static struct sip_msg dup_rpl; static contact_t *scontacts[MAX_CONTACTS_PER_REPLY]; static qvalue_t sqvalues[MAX_CONTACTS_PER_REPLY]; struct hdr_field *hdr; struct hdr_field *contact_hdr; contact_t *contacts; int n,i; int added; int dup; int ret; /* dup can be: * 0 - sh reply but nothing duplicated * 1 - sh reply but only contact body parsed * 2 - sh reply and contact header and body parsed * 3 - private reply */ dup = 0; /* sh_rpl not duplicated */ ret = 0; /* success and no contact added */ contact_hdr = 0; if (sh_rpl==0 || sh_rpl==FAKED_REPLY) return 0; if (sh_rpl->contact==0) { /* contact header is not parsed */ if ( sh_rpl->msg_flags&FL_SHM_CLONE ) { /* duplicate the reply into private memory to be able * to parse it and afterwards to free the parsed mems */ memcpy( &dup_rpl, sh_rpl, sizeof(struct sip_msg) ); dup = 2; /* ok -> force the parsing of contact header */ if ( parse_headers( &dup_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("dup_rpl parse failed\n"); ret = -1; goto restore; } if (dup_rpl.contact==0) { LM_DBG("contact hdr not found in dup_rpl\n"); goto restore; } contact_hdr = dup_rpl.contact; } else { dup = 3; /* force the parsing of contact header */ if ( parse_headers( sh_rpl, HDR_EOH_F, 0)<0 ) { LM_ERR("sh_rpl parse failed\n"); ret = -1; goto restore; } if (sh_rpl->contact==0) { LM_DBG("contact hdr not found in sh_rpl\n"); goto restore; } contact_hdr = sh_rpl->contact; } } else { contact_hdr = sh_rpl->contact; } /* parse the body of contact headers */ hdr = contact_hdr; while(hdr) { if (hdr->type == HDR_CONTACT_T) { if (hdr->parsed==0) { if(parse_contact(hdr) < 0) { LM_ERR("failed to parse Contact body\n"); ret = -1; goto restore; } if (dup==0) dup = 1; } } hdr = hdr->next; } /* we have the contact header and its body parsed -> sort the contacts * based on the q value */ contacts = ((contact_body_t*)contact_hdr->parsed)->contacts; if (contacts==0) { LM_DBG("contact hdr has no contacts\n"); goto restore; } n = sort_contacts(contact_hdr, scontacts, sqvalues); if (n==0) { LM_DBG("no contacts left after filtering\n"); goto restore; } i=0; /* more branches than requested in the parameter * - add only the last ones from sorted array, * because the order is by increasing q */ if (max!=-1 && n>max) i = n - max; added = 0; /* add the sortet contacts as branches in dset and log this! */ for ( ; i<n ; i++ ) { LM_DBG("adding contact <%.*s>\n", scontacts[i]->uri.len, scontacts[i]->uri.s); if(sruid_next(&_redirect_sruid)==0) { if(append_branch( 0, &scontacts[i]->uri, 0, 0, sqvalues[i], bflags, 0, &_redirect_sruid.uid, 0, &_redirect_sruid.uid, &_redirect_sruid.uid)<0) { LM_ERR("failed to add contact to dset\n"); } else { added++; if (rd_acc_fct!=0 && reason) { /* log the redirect */ req->new_uri = scontacts[i]->uri; //FIXME rd_acc_fct( req, (char*)reason, acc_db_table); } } } else { LM_ERR("failed to generate ruid for a new branch\n"); } } ret = (added==0)?-1:added; restore: if (dup==1) { free_contact( (contact_body_t**)(void*)(&contact_hdr->parsed) ); } else if (dup==2) { /* are any new headers found? */ if (dup_rpl.last_header!=sh_rpl->last_header) { /* identify in the new headere list (from dup_rpl) * the sh_rpl->last_header and start remove everything after */ hdr = sh_rpl->last_header; free_hdr_field_lst(hdr->next); hdr->next=0; } } return ret; }