void add_dlg_data_to_contact(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { struct impu_data *impu_data; impurecord_t* implicit_impurecord = 0; struct ucontact* ucontact; str callid = {0, 0}; str path = {0, 0}; LM_DBG("dialog [%p] confirmed, lets add dlg data to contact\n", dlg); if(_params && _params->param){ impu_data = (struct impu_data*)*_params->param; if (!impu_data) { LM_ERR("IMPU data object is NULL...... aborting\n"); return; } LM_DBG("IMPU data is present, contact: <%.*s> identity <%.*s>", impu_data->contact.len, impu_data->contact.s, impu_data->identity.len, impu_data->identity.s); LM_DBG("IMPU data domain <%.*s>", impu_data->d->name->len, impu_data->d->name->s); ul.lock_udomain(impu_data->d, &impu_data->identity); if (ul.get_impurecord(impu_data->d, &impu_data->identity, &implicit_impurecord) != 0) { LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n"); }else { if (ul.get_ucontact(implicit_impurecord, &impu_data->contact, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_PORT_IP_ONLY\n", impu_data->contact.len, impu_data->contact.s); } else {//contact exists so add dialog data to it ul.add_dialog_data_to_contact(ucontact, dlg->h_entry, dlg->h_id); } } ul.unlock_udomain(impu_data->d, &impu_data->identity); } }
/*! \brief * Lookup contact in the database and rewrite Request-URI * \return: 1 : contacts found and returned * -1 : not found * -2 : error */ int lookup_transport(struct sip_msg* _m, udomain_t* _d, str* _uri) { str uri; pcontact_t* pcontact; char tmp[MAX_URI_SIZE]; char srcip[20]; str received_host; str tmp_s; int ret = 1; if (_m->new_uri.s) uri = _m->new_uri; else uri = _m->first_line.u.request.uri; received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; //now lookup in usrloc ul.lock_udomain(_d, &uri, &received_host, _m->rcv.src_port); if (ul.get_pcontact(_d, &uri, &received_host, _m->rcv.src_port, &pcontact) != 0) { //need to insert new contact LM_WARN("received request for contact that we don't know about\n"); ret = -1; goto done; } if (pcontact->received_proto != _m->rcv.proto) { reset_dst_uri(_m); memset(tmp, 0, MAX_URI_SIZE); switch (pcontact->received_proto) { case PROTO_TCP: snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=tcp", pcontact->aor.len, pcontact->aor.s); break; case PROTO_UDP: snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=udp", pcontact->aor.len, pcontact->aor.s); break; default: LM_WARN("unsupported transport [%d]\n", pcontact->received_proto); ret = -2; goto done; } tmp_s.s = tmp; tmp_s.len = strlen(tmp); if (set_dst_uri(_m, &tmp_s) < 0) { LM_ERR("failed to set dst_uri for terminating UE\n"); ret = -2; goto done; } LM_DBG("Changed dst URI transport for UE to [%.*s]\n", tmp_s.len, tmp_s.s); } done: ul.unlock_udomain(_d, &uri, &received_host, _m->rcv.src_port); return ret; }
void remove_dlg_data_from_contact(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params) { struct impu_data *impu_data; impurecord_t* implicit_impurecord = 0; struct ucontact* ucontact; str callid = {0, 0}; str path = {0, 0}; udomain_t* domain_t; LM_DBG("dialog [%p] terminated, lets remove dlg data from contact\n", dlg); if (ul.register_udomain(domain, &domain_t) < 0) { LM_ERR("Unable to register usrloc domain....aborting\n"); return; } if(_params && _params->param){ impu_data = (struct impu_data*)*_params->param; if (!impu_data) { LM_ERR("IMPU data object is NULL...... aborting\n"); return; } LM_DBG("IMPU data is present, contact: <%.*s> identity <%.*s>", impu_data->contact.len, impu_data->contact.s, impu_data->identity.len, impu_data->identity.s); LM_DBG("IMPU data domain <%.*s>", domain_t->name->len, domain_t->name->s); ul.lock_udomain(domain_t, &impu_data->identity); if (ul.get_impurecord(domain_t, &impu_data->identity, &implicit_impurecord) != 0) { LM_DBG("usrloc does not have imprecord for implicity IMPU, ignore\n"); }else { if (ul.get_ucontact(&impu_data->contact, &callid, &path, 0/*cseq*/, &ucontact) != 0) { //contact does not exist LM_DBG("This contact: <%.*s> is not in usrloc, ignore - NOTE: You need S-CSCF usrloc set to match_mode CONTACT_PORT_IP_ONLY\n", impu_data->contact.len, impu_data->contact.s); } else {//contact exists so add dialog data to it ul.remove_dialog_data_from_contact(ucontact, dlg->h_entry, dlg->h_id); ul.release_ucontact(ucontact); } } ul.unlock_udomain(domain_t, &impu_data->identity); free_impu_data(impu_data); } //we referenced the dialog when we registered for callbacks on it... dlgb.release_dlg(dlg); }
int pcscf_unregister(udomain_t* _d, str * uri, str * received_host, int received_port) { int result = -1; struct pcontact * pcontact; struct pcontact_info ci; memset(&ci, 0, sizeof (struct pcontact_info)); pcontact_info_t search_ci; memset(&ci, 0, sizeof(struct pcontact_info)); sip_uri_t contact_uri; if (parse_uri(uri->s, uri->len, &contact_uri) != 0) { LM_WARN("Failed to parse aor [%.*s]\n", uri->len, uri->s); return -1; } search_ci.received_host.s = received_host->s; search_ci.received_host.len = received_host->len; search_ci.received_port = received_port; search_ci.received_proto = contact_uri.proto? contact_uri.proto : PROTO_UDP; search_ci.searchflag = SEARCH_RECEIVED; search_ci.via_host.s = received_host->s; search_ci.via_host.len = received_host->len; search_ci.via_port = received_port; search_ci.via_prot = search_ci.received_proto; search_ci.aor.s = uri->s; search_ci.aor.len = uri->len; search_ci.reg_state = PCONTACT_ANY; if (ul.get_pcontact(_d, &search_ci, &pcontact) == 0) { /* Lock this record while working with the data: */ ul.lock_udomain(_d, &pcontact->via_host, pcontact->via_port, pcontact->via_proto); LM_DBG("Updating contact [%.*s]: setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s); ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH; ci.num_service_routes = 0; if (ul.update_pcontact(_d, &ci, pcontact) == 0) result = 1; /* Unlock domain */ ul.unlock_udomain(_d, &pcontact->via_host, pcontact->via_port, pcontact->via_proto); } return result; }
int unregister(udomain_t* _d, str * uri, str * received_host, int received_port) { int result = -1; struct pcontact * pcontact; struct pcontact_info ci; memset(&ci, 0, sizeof (struct pcontact_info)); if (ul.get_pcontact(_d, uri, received_host, received_port, &pcontact) == 0) { /* Lock this record while working with the data: */ ul.lock_udomain(_d, &pcontact->aor, received_host, received_port); LM_DBG("Updating contact [%.*s]: setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s); ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH; ci.num_service_routes = 0; if (ul.update_pcontact(_d, &ci, pcontact) == 0) result = 1; // if (ul.delete_pcontact(_d, &pc->aor, received_host, received_port, pcontact) == 0) result = 1; /* Unlock domain */ ul.unlock_udomain(_d, &pcontact->aor, received_host, received_port); } return result; }
/** * Add proper asserted identies based on registration */ int assert_identity(struct sip_msg* _m, udomain_t* _d, str identity) { // Get the contact: pcontact_t * c = getContactP(_m, _d); // Public identities of this contact ppublic_t * p; // Contact not found => Identity not asserted. if (c == NULL) return -2; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &c->aor); LM_DBG("Checking identity: %.*s\n", identity.len, identity.s); LM_DBG("AOR of contact: %.*s\n", c->aor.len, c->aor.s); for (p = c->head; p; p = p->next) { LM_DBG("Public identity: %.*s\n", p->public_identity.len, p->public_identity.s); /* Check length: */ if (identity.len == p->public_identity.len) { /* Check contents: */ if (strncasecmp(identity.s, p->public_identity.s, identity.len) != 0) { LM_DBG("Match!\n"); goto success; } } else LM_DBG("Length does not match.\n"); } // We should only get here, if we failed: /* Unlock domain */ ul.unlock_udomain(_d, &c->aor); return -1; success: /* Unlock domain */ ul.unlock_udomain(_d, &c->aor); return 1; }
void async_aar_reg_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) { struct cell *t = 0; pcontact_t* pcontact; unsigned int cdp_result; struct pcontact_info ci; udomain_t* domain_t; int finalReply = 0; AAASession *auth = 0; rx_authsessiondata_t* p_session_data = 0; int result = CSCF_RETURN_ERROR; pcontact_info_t contact_info; LM_DBG("Received AAR callback\n"); saved_transaction_local_t* local_data = (saved_transaction_local_t*) param; saved_transaction_t* data = local_data->global_data; domain_t = data->domain; int is_rereg = local_data->is_rereg; //before we do anything else, lets decrement the reference counter on replies lock_get(data->lock); data->answers_not_received--; if (data->answers_not_received <= 0) { finalReply = 1; } if (data->ignore_replies) { //there was obv. a subsequent error AFTER we had sent one/more AAR's - so we can ignore these replies and just free memory free_saved_transaction_data(local_data); if (finalReply) { free_saved_transaction_global_data(data); } return; } lock_release(data->lock); LM_DBG("received answer and we are waiting for [%d] answers so far failures flag is [%d]\n", data->answers_not_received, data->failed); if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("t_continue: transaction not found\n"); goto error; } //we have T, lets restore our state (esp. for AVPs) set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to); set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to); set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from); set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to); if (is_timeout != 0) { LM_ERR("Error timeout when sending AAR message via CDP\n"); counter_inc(ims_qos_cnts_h.registration_aar_timeouts); goto error; } if (!aaa) { LM_ERR("Error sending message via CDP\n"); goto error; } counter_inc(ims_qos_cnts_h.registration_aars); counter_add(ims_qos_cnts_h.registration_aar_response_time, elapsed_msecs); counter_inc(ims_qos_cnts_h.registration_aar_replies_received); /* Process the response to AAR, retrieving result code and associated Rx session ID */ if (rx_process_aaa(aaa, &cdp_result) < 0) { LM_ERR("Failed to process AAA from PCRF\n"); //puri.host.len, puri.host.s); goto error; } if (cdp_result >= 2000 && cdp_result < 3000) { counter_inc(ims_qos_cnts_h.successful_registration_aars); if (is_rereg) { LM_DBG("this is a re-registration, therefore we don't need to do anything except know that the the subscription was successful\n"); result = CSCF_RETURN_TRUE; create_return_code(result); goto done; } //need to set Rx auth data to say this session has been successfully opened //This is used elsewhere to prevent acting on termination events when the session has not been opened //getting auth session auth = cdpb.AAAGetAuthSession(aaa->sessionId->data); if (!auth) { LM_DBG("Could not get Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s); goto error; } //getting session data p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data; if (!p_session_data) { LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", aaa->sessionId->data.len, aaa->sessionId->data.s); if (auth) cdpb.AAASessionsUnlock(auth->hash); goto error; } p_session_data->session_has_been_opened = 1; counter_inc(ims_qos_cnts_h.active_registration_rx_sessions); if (auth) cdpb.AAASessionsUnlock(auth->hash); LM_DBG("Success, received code: [%i] from PCRF for AAR request (contact: [%.*s]), (auth session id: %.*s)\n", cdp_result, local_data->contact.len, local_data->contact.s, local_data->auth_session_id.len, local_data->auth_session_id.s); LM_DBG("Registering for Usrloc callbacks on DELETE\n"); ul.lock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto); contact_info.received_host = local_data->recv_host; contact_info.received_port = local_data->recv_port; contact_info.received_proto = local_data->recv_proto; contact_info.searchflag = (1 << SEARCH_RECEIVED); contact_info.aor = local_data->contact; contact_info.via_host = local_data->via_host; contact_info.via_port = local_data->via_port; contact_info.via_prot = local_data->via_proto; if (ul.get_pcontact(domain_t, &contact_info, &pcontact) != 0) { LM_ERR("Shouldn't get here, can't find contact....\n"); ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto); goto error; } //at this point we have the contact /*set the contact state to say we have succesfully done ARR for register and that we dont need to do it again * for the duration of the registration. * */ if (ul.update_rx_regsession(domain_t, &local_data->auth_session_id, pcontact) != 0) { LM_ERR("unable to update pcontact......\n"); ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto); goto error; } memset(&ci, 0, sizeof (struct pcontact_info)); ci.reg_state = PCONTACT_REG_PENDING_AAR; ci.num_service_routes = 0; ci.num_public_ids = 0; LM_DBG("impu: [%.*s] updating status to PCONTACT_REG_PENDING\n", pcontact->aor.len, pcontact->aor.s); ul.update_pcontact(domain_t, &ci, pcontact); //register for callbacks on contact ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); ul.unlock_udomain(domain_t, &local_data->via_host, local_data->via_port, local_data->via_proto); result = CSCF_RETURN_TRUE; } else { LM_DBG("Received negative reply from PCRF for AAR Request\n"); counter_inc(ims_qos_cnts_h.failed_registration_aars); result = CSCF_RETURN_FALSE; goto error; } //set success response code AVP create_return_code(result); goto done; error: //set failure response code create_return_code(result); done: if (t) tmb.unref_cell(t); //free memory if (aaa) cdpb.AAAFreeMessage(&aaa); if (finalReply) { tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_global_data(data); } free_saved_transaction_data(local_data); }
/** * Updates the registrar with the new values * @param req - the REGISTER request - to extract NAT info * @param rpl - the REGISTER reply - to extract contact info * @param is_star - whether this was a STAR contact header * @param expires_hdr - value of the Expires header * @param public_id - array of public identities attached to this contact * @param public_id_cnt - size of the public_id array * @param service_route - array of Service-Routes * @param service_route_cnt - size of the service_route array * @param requires_nat - if to create pinholes * @returns the maximum expiration time, -1 on error */ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr, str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat) { int local_time_now, expires=0; struct hdr_field* h; contact_t* c; struct sip_uri puri; struct sip_uri parsed_received; struct pcontact_info ci; pcontact_t* pcontact; char srcip[50]; int_str val; pcscf_act_time(); local_time_now = time_now; if (is_star) { /* first of all, we shouldn't get here... * then, we will update on NOTIFY */ return 0; } // Set the structure to "0", to make sure it's properly initialized memset(&ci, 0, sizeof(struct pcontact_info)); for (h = rpl->contact; h; h = h->next) { if (h->type == HDR_CONTACT_T && h->parsed) for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) { expires = calc_contact_expires(c, expires_hdr, local_time_now); if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) { LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s); continue; } //build contact info ci.expires = expires; ci.public_ids = public_id; ci.num_public_ids = public_id_cnt; ci.service_routes = service_route; ci.num_service_routes = service_route_cnt; ci.reg_state = PCONTACT_REGISTERED; ci.received_host.len = 0; ci.received_host.s = 0; ci.received_port = 0; ci.received_proto = 0; // Received Info: First try AVP, otherwise simply take the source of the request: 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) { LM_ERR("received too long\n"); goto error; } if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) { LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s); continue; } ci.received_host = parsed_received.host; ci.received_port = parsed_received.port_no; ci.received_proto = parsed_received.proto; } else { ci.received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, sizeof(srcip)); ci.received_host.s = srcip; ci.received_port = req->rcv.src_port; ci.received_proto = req->rcv.proto; } // Set to default, if not set: if (ci.received_port == 0) ci.received_port = 5060; ul.lock_udomain(_d, &c->uri); if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact if ((expires-local_time_now)<=0) { //remove contact - de-register LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s); goto next_contact; } LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now); if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { LM_ERR("Failed inserting new pcontact\n"); } else { //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change LM_DBG("registering for UL callback\n"); ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); //we also need to subscribe to reg event of this contact at SCSCF } } else { //contact already exists - update LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state)); if ((expires-local_time_now)<=0) { //remove contact - de-register LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s); if (ul.delete_pcontact(_d, &c->uri, pcontact) != 0) { LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s); } } else { //update contact LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s, pcontact->expires-local_time_now, expires, expires-local_time_now); if (ul.update_pcontact(_d, &ci, pcontact) != 0) { LM_ERR("failed to update pcscf contact\n"); } pcontact->expires = expires; } } next_contact: ul.unlock_udomain(_d, &c->uri); } } return 1; error: return 0; }
/** * Force Service routes (upon request) */ int force_service_routes(struct sip_msg* _m, udomain_t* _d) { struct hdr_field *it; int i; str new_route_header; struct lump* lmp = NULL; char * buf; pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED,0 ,0); // char srcip[20]; // str received_host; struct via_body* vb; unsigned short port; unsigned short proto; // Contact not found => not following service-routes if (c == NULL) return -1; /* we need to be sure we have seen all HFs */ parse_headers(_m, HDR_EOH_F, 0); vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; /* Save current buffer */ buf = _m->buf; // Delete old Route headers: if (_m->route) { for (it = _m->route; it; it = it->next) { if (it->type == HDR_ROUTE_T) { if ((lmp = del_lump(_m, it->name.s - buf, it->len, HDR_ROUTE_T)) == 0) { LM_ERR("del_lump failed \n"); return -1; } } } } /* Reset dst_uri if previously set either by loose route or manually */ if (_m->dst_uri.s && _m->dst_uri.len) { pkg_free(_m->dst_uri.s); _m->dst_uri.s = NULL; _m->dst_uri.len = 0; } // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); // received_host.s = srcip; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &vb->host, port, proto); if (c->num_service_routes > 0) { /* Create anchor for new Route-Header: */ lmp = anchor_lump(_m, _m->headers->name.s - buf,0,0); if (lmp == 0) { LM_ERR("Failed to get anchor lump\n"); goto error; } /* Calculate the length: */ new_route_header.len = route_start.len + route_end.len + (c->num_service_routes-1) * route_sep.len; for(i=0; i< c->num_service_routes; i++) new_route_header.len+=c->service_routes[i].len; /* Allocate the memory for this new header: */ new_route_header.s = pkg_malloc(new_route_header.len); if (!new_route_header.s) { LM_ERR("Error allocating %d bytes\n", new_route_header.len); goto error; } /* Construct new header */ new_route_header.len = 0; STR_APPEND(new_route_header, route_start); for(i=0; i < c->num_service_routes; i++) { if (i) STR_APPEND(new_route_header, route_sep); STR_APPEND(new_route_header, c->service_routes[i]); } STR_APPEND(new_route_header, route_end); LM_DBG("Setting route header to <%.*s> \n", new_route_header.len, new_route_header.s); if ((lmp = insert_new_lump_after(lmp, new_route_header.s, new_route_header.len, HDR_ROUTE_T)) == 0) { LM_ERR("Error inserting new route set\n"); pkg_free(new_route_header.s); goto error; } LM_DBG("Setting dst_uri to <%.*s> \n", c->service_routes[0].len, c->service_routes[0].s); if (set_dst_uri(_m, &c->service_routes[0]) !=0 ) { LM_ERR("Error setting new dst uri\n"); goto error; } } /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return -1; return 1; }
/*main event process function*/ void cdp_cb_event_process() { cdp_cb_event_t *ev; udomain_t* domain; pcontact_t* pcontact; str release_reason = {"QoS released", 12}; /* TODO: This could be a module parameter */ struct pcontact_info ci; memset(&ci, 0, sizeof (struct pcontact_info)); for (;;) { ev = pop_cdp_cb_event(); if (cdp_event_latency) { //track delays unsigned int diff = time(NULL) - ev->registered; if (diff > cdp_event_threshold) { switch (cdp_event_latency_loglevel) { case 0: LM_ERR("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold); break; case 1: LM_WARN("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold); break; case 2: LM_INFO("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold); break; case 3: LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold); break; default: LM_DBG("Unknown log level....printing as debug\n"); LM_DBG("Took to long to pickup CDP callback event [%d] > [%d]\n", diff, cdp_event_threshold); break; } } } LM_DBG("processing event [%d]\n", ev->event); rx_authsessiondata_t *p_session_data = ev->session_data; str *rx_session_id = &ev->rx_session_id; switch (ev->event) { case AUTH_EV_SESSION_TIMEOUT: case AUTH_EV_SESSION_GRACE_TIMEOUT: case AUTH_EV_RECV_ASR: LM_DBG("Received notification of ASR from transport plane or CDP timeout for CDP session with Rx session ID: [%.*s] and associated contact [%.*s]" " and domain [%.*s]\n", rx_session_id->len, rx_session_id->s, p_session_data->registration_aor.len, p_session_data->registration_aor.s, p_session_data->domain.len, p_session_data->domain.s); if (p_session_data->subscribed_to_signaling_path_status) { LM_DBG("This is a subscription to signalling bearer session"); //nothing to do here - just wait for AUTH_EV_SERVICE_TERMINATED event } else { LM_DBG("This is a media bearer session session"); //this is a media bearer session that was terminated from the transport plane - we need to terminate the associated dialog //so we set p_session_data->must_terminate_dialog to 1 and when we receive AUTH_EV_SERVICE_TERMINATED event we will terminate the dialog p_session_data->must_terminate_dialog = 1; } break; case AUTH_EV_SERVICE_TERMINATED: LM_DBG("Received notification of CDP TERMINATE of CDP session with Rx session ID: [%.*s] and associated contact [%.*s]" " and domain [%.*s]\n", rx_session_id->len, rx_session_id->s, p_session_data->registration_aor.len, p_session_data->registration_aor.s, p_session_data->domain.len, p_session_data->domain.s); if (p_session_data->subscribed_to_signaling_path_status) { LM_DBG("This is a subscription to signalling bearer session"); //instead of removing the contact from usrloc_pcscf we just change the state of the contact to TERMINATE_PENDING_NOTIFY //pcscf_registrar sees this, sends a SIP PUBLISH and on SIP NOTIFY the contact is deleted if (ul.register_udomain(p_session_data->domain.s, &domain) < 0) { LM_DBG("Unable to register usrloc domain....aborting\n"); return; } ul.lock_udomain(domain, &p_session_data->registration_aor); if (ul.get_pcontact(domain, &p_session_data->registration_aor, &pcontact) != 0) { LM_DBG("no contact found for terminated Rx reg session..... ignoring\n"); } else { LM_DBG("Updating contact [%.*s] after Rx reg session terminated, setting state to PCONTACT_DEREG_PENDING_PUBLISH\n", pcontact->aor.len, pcontact->aor.s); ci.reg_state = PCONTACT_DEREG_PENDING_PUBLISH; ci.num_service_routes = 0; ul.update_pcontact(domain, &ci, pcontact); } ul.unlock_udomain(domain, &p_session_data->registration_aor); } else { LM_DBG("This is a media bearer session session"); //we only terminate the dialog if this was triggered from the transport plane or timeout - i.e. if must_terminate_dialog is set //if this was triggered from the signalling plane (i.e. someone hanging up) then we don'y need to terminate the dialog if (p_session_data->must_terminate_dialog) { LM_DBG("Terminating dialog with callid, ftag, ttag: [%.*s], [%.*s], [%.*s]\n", p_session_data->callid.len, p_session_data->callid.s, p_session_data->ftag.len, p_session_data->ftag.s, p_session_data->ttag.len, p_session_data->ttag.s); dlgb.terminate_dlg(&p_session_data->callid, &p_session_data->ftag, &p_session_data->ttag, NULL, &release_reason); } } //free callback data if (p_session_data) { shm_free(p_session_data); p_session_data = 0; } break; default: break; } free_cdp_cb_event(ev); } }
/** * Check, if a user-agent follows the indicated service-routes */ int check_service_routes(struct sip_msg* _m, udomain_t* _d) { struct sip_uri uri; int i; struct hdr_field *hdr; rr_t *r; pcontact_t * c = getContactP(_m, _d); /* Contact not found => not following service-routes */ if (c == NULL) return -1; /* Search for the first Route-Header: */ if (find_first_route(_m) < 0) return -1; LM_DBG("Got %i Route-Headers.\n", c->num_service_routes); /* Lock this record while working with the data: */ ul.lock_udomain(_d, &c->aor); /* Check the route-set: */ if (_m->route) { hdr = _m->route; LM_DBG("hdr is %p\n", hdr); /* Check, if the first host is ourself: */ r = (rr_t*)hdr->parsed; if (r) { LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Skip first headers containing myself: */ while (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0 && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) { LM_DBG("Self\n"); /* Check for more headers and fail, if it was the last one Check, if service-routes are indicated. If yes, request is not following service-routes */ if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; if (!r && (c->num_service_routes > 0)) { LM_DBG("Not enough route-headers in Message\n"); goto error; } LM_DBG("hdr is %p\n", hdr); LM_DBG("r is %p\n", r); if (r) LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); } /* Then check the following headers: */ for (i=0; i< c->num_service_routes; i++) { LM_DBG("Route must be: %.*s\n", c->service_routes[i].len, c->service_routes[i].s); /* No more Route-Headers? Not following service-routes */ if (!r) { LM_ERR("No more route headers in message.\n"); goto error; } LM_DBG("Route is: %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Check length: */ if (r->nameaddr.uri.len != c->service_routes[i].len) { LM_DBG("Length does not match.\n"); goto error; } /* Check contents: */ if (strncasecmp(r->nameaddr.uri.s, c->service_routes[i].s, c->service_routes[i].len) != 0) { LM_DBG("String comparison failed.\n"); goto error; } if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; } /* Check, if it was the last route-header in the message: */ if (r) { LM_ERR("Too many route headers in message.\n"); goto error; } } else { LM_WARN("Strange: Route-Header is present, but not parsed?!?"); if (c->num_service_routes > 0) goto error; } } else { LM_ERR("No route header in Message.\n"); /* No route-header? Check, if service-routes are indicated. If yes, request is not following service-routes */ if (c->num_service_routes > 0) goto error; } /* Unlock domain */ ul.unlock_udomain(_d, &c->aor); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &c->aor); return -1; }
/** * Check, if a user-agent follows the indicated service-routes */ int check_service_routes(struct sip_msg* _m, udomain_t* _d) { struct sip_uri uri; int i; struct hdr_field *hdr; rr_t *r; char routes[MAXROUTES][MAXROUTESIZE]; unsigned int num_routes = 0; struct via_body * vb; unsigned short port; unsigned short proto; /* Contact not found => not following service-routes */ // if (c == NULL) return -1; /* Search for the first Route-Header: */ if (find_first_route(_m) < 0) return -1; // LM_DBG("Got %i Route-Headers.\n", c->num_service_routes); vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &vb->host, port, proto); if (_m->route) { hdr = _m->route; r = (rr_t*)hdr->parsed; //get rid of ourselves from route header if (r) { LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); while (r && (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0) && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) { LM_DBG("Self\n"); /* Check for more headers and fail, if it was the last one Check, if service-routes are indicated. If yes, request is not following service-routes */ if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; LM_DBG("hdr is %p\n", hdr); LM_DBG("r is %p\n", r); if (r) LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); } int i = 0; while (r) { memset(routes[i],0,MAXROUTESIZE); memcpy(routes[i], r->nameaddr.uri.s, r->nameaddr.uri.len); if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; i += 1; num_routes += 1; } LM_DBG("num_routes is %d\n", num_routes); for (i=0; i<num_routes; i++) { LM_DBG("route %d for checking is %s\n", i, routes[i]); } pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED, routes, num_routes); if (!c) { LM_DBG("no contact found in usrloc when checking for service route\n"); goto error; } LM_DBG("we have a contact which satisifes the routes...\n"); ul.unlock_udomain(_d, &vb->host, port, proto); return 1; } } else { LM_DBG("Request doesn't have any route headers to check service-route...ignoring\n"); goto error; } pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED, 0, 0); if (!c) { LM_DBG("no contact found in usrloc when checking for service route\n"); goto error; } /* Check the route-set: */ if (_m->route) { hdr = _m->route; LM_DBG("hdr is %p\n", hdr); /* Check, if the first host is ourself: */ r = (rr_t*)hdr->parsed; if (r) { LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Skip first headers containing myself: */ while (r && (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0) && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) { LM_DBG("Self\n"); /* Check for more headers and fail, if it was the last one Check, if service-routes are indicated. If yes, request is not following service-routes */ if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; if (!r && (c->num_service_routes > 0)) { LM_DBG("Not enough route-headers in Message\n"); goto error; } LM_DBG("hdr is %p\n", hdr); LM_DBG("r is %p\n", r); if (r) LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); } LM_DBG("We have %d service-routes\n", c->num_service_routes); /* Then check the following headers: */ for (i=0; i< c->num_service_routes; i++) { LM_DBG("Route must be: %.*s\n", c->service_routes[i].len, c->service_routes[i].s); /* No more Route-Headers? Not following service-routes */ if (!r) { LM_DBG("No more route headers in message.\n"); goto error; } LM_DBG("Route is: %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Check length: */ if (r->nameaddr.uri.len != c->service_routes[i].len) { LM_DBG("Length does not match.\n"); goto error; } /* Check contents: */ if (strncasecmp(r->nameaddr.uri.s, c->service_routes[i].s, c->service_routes[i].len) != 0) { LM_DBG("String comparison failed.\n"); goto error; } if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; } /* Check, if it was the last route-header in the message: */ if (r) { LM_DBG("Too many route headers in message.\n"); goto error; } } else { LM_WARN("Strange: Route-Header is present, but not parsed?!?"); if (c->num_service_routes > 0) goto error; } } else { LM_DBG("No route header in Message.\n"); /* No route-header? Check, if service-routes are indicated. If yes, request is not following service-routes */ if (c->num_service_routes > 0) goto error; } /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return -1; }
int ipsec_create(struct sip_msg* m, udomain_t* d) { pcontact_t* pcontact = NULL; struct pcontact_info ci; int ret = IPSEC_CMD_FAIL; // FAIL by default // Find the contact if(fill_contact(&ci, m) != 0) { LM_ERR("Error filling in contact data\n"); return ret; } ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(d, &ci, &pcontact) != 0) { LM_ERR("Contact doesn't exist\n"); goto cleanup; } // Get security parameters if(pcontact->security_temp == NULL) { LM_ERR("No security parameters found in contact\n"); goto cleanup; } if(pcontact->security_temp->type != SECURITY_IPSEC ) { LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type); goto cleanup; } ipsec_t* s = pcontact->security_temp->data.ipsec; if(update_contact_ipsec_params(s, m) != 0) { goto cleanup; } if(create_ipsec_tunnel(ci.received_host, s) != 0) { goto cleanup; } // TODO: Save security_tmp to security!!!!! if (ul.update_pcontact(d, &ci, pcontact) != 0) { LM_ERR("Error updating contact\n"); goto cleanup; } // Destroy the tunnel, if the contact expires if(ul.register_ulcb(pcontact, PCSCF_CONTACT_EXPIRE|PCSCF_CONTACT_DELETE, on_expire, NULL) != 1) { LM_ERR("Error subscribing for contact\n"); goto cleanup; } if(add_supported_secagree_header(m) != 0) { goto cleanup; } if(add_security_server_header(m, s) != 0) { goto cleanup; } ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit cleanup: // Do not free str* sec_header! It will be freed in data_lump.c -> free_lump() ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); pkg_free(ci.received_host.s); return ret; }
int ipsec_forward(struct sip_msg* m, udomain_t* d) { struct pcontact_info ci; pcontact_t* pcontact = NULL; int ret = IPSEC_CMD_FAIL; // FAIL by default // // Find the contact // if(fill_contact(&ci, m) != 0) { LM_ERR("Error filling in contact data\n"); return ret; } ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(d, &ci, &pcontact) != 0) { LM_ERR("Contact doesn't exist\n"); goto cleanup; } if(pcontact->security_temp == NULL) { LM_ERR("No security parameters found in contact\n"); goto cleanup; } //get security parameters if(pcontact->security_temp->type != SECURITY_IPSEC ) { LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type); goto cleanup; } ipsec_t* s = pcontact->security_temp->data.ipsec; // Update the destination // // from sec-agree // v // sip:host:port // ^ // from URI //int uri_len = 4 /* strlen("sip:") */ + ci.via_host.len + 5 /* max len of port number */ ; if(m->dst_uri.s) { pkg_free(m->dst_uri.s); m->dst_uri.s = NULL; m->dst_uri.len = 0; } char buf[1024]; int buf_len = snprintf(buf, sizeof(buf) - 1, "sip:%.*s:%d", ci.via_host.len, ci.via_host.s, s->port_us); if((m->dst_uri.s = pkg_malloc(buf_len)) == NULL) { LM_ERR("Error allocating memory for dst_uri\n"); goto cleanup; } memcpy(m->dst_uri.s, buf, buf_len); m->dst_uri.len = buf_len; // Set send socket struct socket_info * client_sock = grep_sock_info(&ipsec_listen_addr, ipsec_client_port, PROTO_UDP); if(!client_sock) { LM_ERR("Error calling grep_sock_info() for ipsec client port in ipsec_forward\n"); return -1; } m->force_send_socket = client_sock; // Set destination info struct dest_info dst_info; dst_info.send_sock = client_sock; #ifdef USE_DNS_FAILOVER if (!uri2dst(NULL, &dst_info, m, &m->dst_uri, PROTO_UDP)) { #else if (!uri2dst(&dst_info, m, &m->dst_uri, PROTO_UDP)) { #endif LM_ERR("Error converting dst_uri (%.*s) to struct dst_info\n", m->dst_uri.len, m->dst_uri.s); goto cleanup; } // Update dst_info in message if(m->first_line.type == SIP_REPLY) { struct cell *t = tmb.t_gett(); if (!t) { LM_ERR("Error getting transaction\n"); goto cleanup; } t->uas.response.dst = dst_info; } LM_DBG("Destination changed to %.*s\n", m->dst_uri.len, m->dst_uri.s); ret = IPSEC_CMD_SUCCESS; // all good, return SUCCESS if(add_supported_secagree_header(m) != 0) { goto cleanup; } if(add_security_server_header(m, s) != 0) { goto cleanup; } ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit cleanup: ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); pkg_free(ci.received_host.s); return ret; } int ipsec_destroy(struct sip_msg* m, udomain_t* d) { struct pcontact_info ci; pcontact_t* pcontact = NULL; int ret = IPSEC_CMD_FAIL; // FAIL by default // // Find the contact // if(fill_contact(&ci, m) != 0) { LM_ERR("Error filling in contact data\n"); return ret; } ul.lock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(d, &ci, &pcontact) != 0) { LM_ERR("Contact doesn't exist\n"); goto cleanup; } if(pcontact->security_temp == NULL) { LM_ERR("No security parameters found in contact\n"); goto cleanup; } //get security parameters if(pcontact->security_temp->type != SECURITY_IPSEC ) { LM_ERR("Unsupported security type: %d\n", pcontact->security_temp->type); goto cleanup; } destroy_ipsec_tunnel(ci.received_host, pcontact->security_temp->data.ipsec); ret = IPSEC_CMD_SUCCESS; // all good, set ret to SUCCESS, and exit cleanup: ul.unlock_udomain(d, &ci.via_host, ci.via_port, ci.via_prot); pkg_free(ci.received_host.s); return ret; } int ipsec_cleanall() { struct mnl_socket* nlsock = init_mnl_socket(); if(!nlsock) { return -1; } if(clean_sa(nlsock) != 0) { LM_WARN("Error cleaning IPSec Security associations during startup.\n"); } if(clean_policy(nlsock) != 0) { LM_WARN("Error cleaning IPSec Policies during startup.\n"); } close_mnl_socket(nlsock); return 0; }
AAAMessage* cxdx_process_rtr(AAAMessage *rtr) { LM_DBG("Processing RTR"); AAAMessage *rta_msg; AAA_AVP* avp; str public_id; impurecord_t* r; int res = 0; udomain_t* udomain; impu_contact_t *impucontact; rta_msg = cdpb.AAACreateResponse(rtr);//session ID? if (!rta_msg) return 0; avp = cxdx_get_next_public_identity(rtr,0,AVP_IMS_Public_Identity,IMS_vendor_id_3GPP,__FUNCTION__); if(avp==0){ LM_WARN("RTR received with only IMPI (username AVP) - currently S-CSCF does not support this kind of RTR\n"); return 0; //TODO add support for receiving RTR with IMPI //get all impus related to this impu //get all contacts related to each impu //set the contact expire for each contact to now }else{ public_id=avp->data; LM_DBG("RTR received with IMPU [%.*s] in public identity AVP - this is supported\n", public_id.len, public_id.s); //TODO this should be a configurable module param if (ul.register_udomain(domain, &udomain) < 0) { LM_ERR("Unable to register usrloc domain....aborting\n"); return 0; } ul.lock_udomain(udomain, &public_id); res = ul.get_impurecord(udomain, &public_id, &r); if (res != 0) { LM_WARN("Strange, '%.*s' Not found in usrloc\n", public_id.len, public_id.s); ul.unlock_udomain(udomain, &public_id); //no point in continuing return 0; } impucontact = r->linked_contacts.head; while (impucontact) { LM_DBG("Deleting contact with AOR [%.*s]\n", impucontact->contact->aor.len, impucontact->contact->aor.s); ul.lock_contact_slot_i(impucontact->contact->sl); impucontact->contact->state = CONTACT_DELETE_PENDING; if (r->shead) { //send NOTIFY to all subscribers of this IMPU. notify_subscribers(r, 0, 0); } impucontact->contact->state = CONTACT_DELETED; ul.unlock_contact_slot_i(impucontact->contact->sl); impucontact = impucontact->next; } ul.unlock_udomain(udomain, &public_id); while(cdpb.AAAGetNextAVP(avp) && (avp=cxdx_get_next_public_identity(rtr,cdpb.AAAGetNextAVP(avp),AVP_IMS_Public_Identity,IMS_vendor_id_3GPP,__FUNCTION__))!=0){ public_id=avp->data; LM_DBG("RTR also has public id [%.*s]\n", public_id.len, public_id.s); ul.lock_udomain(udomain, &public_id); res = ul.get_impurecord(udomain, &public_id, &r); if (res != 0) { LM_WARN("Strange, '%.*s' Not found in usrloc\n", public_id.len, public_id.s); ul.unlock_udomain(udomain, &public_id); //no point in continuing return 0; } impucontact = r->linked_contacts.head; while (impucontact) { LM_DBG("Deleting contact with AOR [%.*s]\n", impucontact->contact->aor.len, impucontact->contact->aor.s); ul.lock_contact_slot_i(impucontact->contact->sl); impucontact->contact->state = CONTACT_DELETE_PENDING; if (r->shead) { //send NOTIFY to all subscribers of this IMPU. notify_subscribers(r, 0, 0); } impucontact->contact->state = CONTACT_DELETED; ul.unlock_contact_slot_i(impucontact->contact->sl); impucontact = impucontact->next; } ul.unlock_udomain(udomain, &public_id); } } cxdx_add_vendor_specific_appid(rta_msg,IMS_vendor_id_3GPP,IMS_Cx,0 /*IMS_Cx*/); cxdx_add_auth_session_state(rta_msg,1); /* send an RTA back to the HSS */ cxdx_add_result_code(rta_msg,DIAMETER_SUCCESS); return rta_msg; }
/** * Handle third party registration * @param msg - the SIP REGISTER message * @param m - the isc_match that matched with info about where to forward it * @param mark - the isc_mark that should be used to mark the message * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark, udomain_t* d) { r_third_party_registration r; str path, path_received; int expires = 0; str req_uri = {0, 0}; str to = {0, 0}; str pvni = {0, 0}; str pani = {0, 0}; str cv = {0, 0}; str s = {0, 0}; impurecord_t *p; struct hdr_field *hdr; LM_DBG("isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); if (cscf_get_originating_user(msg, &s)) { isc_ulb.lock_udomain(d, &s); if ( isc_ulb.get_impurecord(d,&s,&p) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to get IMPU domain from usrloc\n"); goto no_pai; } if ( build_p_associated_uri(p->s) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to build P-Associated URI for 3rd party reg\n"); goto no_pai; } isc_ulb.unlock_udomain(d, &s); } /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ no_pai: expires = cscf_get_max_expires(msg, 0); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); if (build_path_vector(msg, &path, &path_received) < 0) { LM_ERR("Failed to parse PATH header for third-party reg\n"); return ISC_RETURN_FALSE; } LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s) { memset(&r, 0, sizeof (r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; if (m->service_info.s && m->service_info.len) { r.body.content_type = CT_SERVICE_INFO; r.body.content = m->service_info; } else if (m->include_register_request) { r.body.content_type = CT_REGISTER_REQ; r.body.content.s = msg->first_line.u.request.method.s; r.body.content.len = msg->len; } else if (m->include_register_response) { struct bookmark dummy_bm; r.body.content_type = CT_REGISTER_RESP; r.body.content.s = build_res_buf_from_sip_req(200, ®_resp_200OK, 0, msg, (unsigned int*)&r.body.content.len, &dummy_bm); if (!r.body.content.s) { LM_DBG("response building failed for body of third party register request"); r.body.content_type = CT_NONE; } } else { r.body.content_type = CT_NONE; } r.path = path; if (expires <= 0) r_send_third_party_reg(&r, 0); else r_send_third_party_reg(&r, expires + isc_expires_grace); return ISC_RETURN_TRUE; } else { return ISC_RETURN_FALSE; } }
/* Wrapper to send AAR from config file - only used for registration */ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) { int ret = CSCF_RETURN_ERROR; struct pcontact_info ci; struct cell *t; contact_t* c; struct hdr_field* h; pcontact_t* pcontact; contact_body_t* cb = 0; AAASession* auth; rx_authsessiondata_t* rx_regsession_data_p; cfg_action_t* cfg_action = 0; str route_name; char* p; int aar_sent = 0; saved_transaction_local_t* local_data = 0; //data to be shared across all async calls saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) { LM_ERR("no async route block for assign_server_unreg\n"); return -1; } LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s); int ri = route_get(&main_rt, route_name.s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s); return -1; } cfg_action = main_rt.rlist[ri]; if (cfg_action == NULL) { LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s); return -1; } udomain_t* domain_t = (udomain_t*) str1; int is_rereg = 0; //is this a reg/re-reg LM_DBG("Rx AAR Register called\n"); //create the default return code AVP create_return_code(ret); memset(&ci, 0, sizeof (struct pcontact_info)); /** If this is a response then let's check the status before we try and do an AAR. * We will only do AAR for register on success response and of course if message is register */ if (msg->first_line.type == SIP_REPLY) { //check this is a response to a register /* Get the SIP request from this transaction */ t = tmb.t_gett(); if (!t) { LM_ERR("Cannot get transaction for AAR based on SIP Request\n"); goto error; } if ((strncmp(t->method.s, "REGISTER", 8) != 0)) { LM_ERR("Method is not a response to a REGISTER\n"); goto error; } if (msg->first_line.u.reply.statuscode < 200 || msg->first_line.u.reply.statuscode >= 300) { LM_DBG("Message is not a 2xx OK response to a REGISTER\n"); goto error; } tmb.t_release(msg); } else { //SIP Request /* in case of request make sure it is a REGISTER */ if (msg->first_line.u.request.method_value != METHOD_REGISTER) { LM_DBG("This is not a register request\n"); goto error; } if ((cscf_get_max_expires(msg, 0) == 0)) { //if ((cscf_get_expires(msg) == 0)) { LM_DBG("This is a de registration\n"); LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n"); create_return_code(CSCF_RETURN_TRUE); return CSCF_RETURN_TRUE; } } //before we continue, make sure we have a transaction to work with (viz. cdp async) t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for UAR async\n"); return CSCF_RETURN_ERROR; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); return CSCF_RETURN_ERROR; } } saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t)); if (!saved_t_data) { LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n"); return CSCF_RETURN_ERROR; } memset(saved_t_data, 0, sizeof (saved_transaction_t)); saved_t_data->act = cfg_action; saved_t_data->domain = domain_t; saved_t_data->lock = lock_alloc(); if (saved_t_data->lock == NULL) { LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } if (lock_init(saved_t_data->lock) == NULL) { LM_ERR("unable to init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_transaction_global_data(saved_t_data); return CSCF_RETURN_ERROR; } LM_DBG("Successfully suspended transaction\n"); //now get the contacts in the REGISTER and do AAR for each one. cb = cscf_parse_contacts(msg); if (!cb || (!cb->contacts && !cb->star)) { LM_DBG("No contact headers in Register message\n"); goto error; } lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously for (h = msg->contact; h; h = h->next) { if (h->type == HDR_CONTACT_T && h->parsed) { for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) { ul.lock_udomain(domain_t, &c->uri); if (ul.get_pcontact(domain_t, &c->uri, &pcontact) != 0) { LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } else if (pcontact->reg_state == PCONTACT_REG_PENDING || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n" , pcontact->aor.len, pcontact->aor.s); //get IP address from contact struct sip_uri puri; if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) { LM_ERR("failed to parse Contact\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } LM_DBG("Parsed URI of from host is [%.*s]\n", puri.host.len, puri.host.s); uint16_t ip_version = AF_INET; //TODO IPv6!!!? //check for existing Rx session if (pcontact->rx_session_id.len > 0 && pcontact->rx_session_id.s && (auth = cdpb.AAAGetAuthSession(pcontact->rx_session_id))) { LM_DBG("Rx session already exists for this user\n"); if (memcmp(pcontact->rx_session_id.s, auth->id.s, auth->id.len) != 0) { LM_ERR("Rx session mismatch when URI is [%.*s].......Aborting\n", puri.host.len, puri.host.s); if (auth) cdpb.AAASessionsUnlock(auth->hash); lock_release(saved_t_data->lock); goto error; } //re-registration - update auth lifetime auth->u.auth.lifetime = time(NULL) + rx_auth_expiry; is_rereg = 1; } else { LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s); int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &rx_regsession_data_p); if (!ret) { LM_ERR("Unable to create regsession data parcel when URI is [%.*s]...Aborting\n", puri.host.len, puri.host.s); ul.unlock_udomain(domain_t, &c->uri); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } auth = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_regsession_data_p); //returns with a lock if (!auth) { LM_ERR("Rx: unable to create new Rx Reg Session when URI is [%.*s]\n", puri.host.len, puri.host.s); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } ul.unlock_udomain(domain_t, &c->uri); if (auth) cdpb.AAASessionsUnlock(auth->hash); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } } //we are ready to send the AAR async. lets save the local data data int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len; local_data = shm_malloc(local_data_len); if (!local_data) { LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n"); lock_release(saved_t_data->lock); goto error; } memset(local_data, 0, local_data_len); local_data->is_rereg = is_rereg; local_data->global_data = saved_t_data; p = (char*) (local_data + 1); local_data->contact.s = p; local_data->contact.len = c->uri.len; memcpy(p, c->uri.s, c->uri.len); p += c->uri.len; local_data->auth_session_id.s = p; local_data->auth_session_id.len = auth->id.len; memcpy(p, auth->id.s, auth->id.len); p += auth->id.len; if (p != (((char*) local_data) + local_data_len)) { LM_CRIT("buffer overflow\n"); free_saved_transaction_data(local_data); goto error; } LM_DBG("Calling send aar register"); //TODOD remove - no longer user AOR parm //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object ul.unlock_udomain(domain_t, &c->uri); if (!ret) { LM_ERR("Failed to send AAR\n"); lock_release(saved_t_data->lock); free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here) goto error; } else { aar_sent = 1; //before we send - bump up the reply counter saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above } } else { //contact exists - this is a re-registration, for now we just ignore this LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n"); ul.unlock_udomain(domain_t, &c->uri); //now we loop for any other contacts. } } } else { if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error LM_ERR("Failed to parse contact header\n"); lock_release(saved_t_data->lock); goto error; } } } //all requests sent at this point - we can unlock the reply lock lock_release(saved_t_data->lock); /*if we get here, we have either: * 1. Successfully sent AAR's for ALL contacts, or * 2. haven't needed to send ANY AAR's for ANY contacts */ if (aar_sent) { LM_DBG("Successful async send of AAR\n"); return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process } else { create_return_code(CSCF_RETURN_TRUE); tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data } //return CSCF_RETURN_ERROR; return CSCF_RETURN_TRUE; } error: LM_ERR("Error trying to send AAR\n"); if (!aar_sent) { tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free //otherwise the callback will segfault } } return CSCF_RETURN_ERROR; //return CSCF_RETURN_FALSE; }
/* UPDATED + CHECKED */ static inline char *run_lookup( struct cpl_interpreter *intr ) { unsigned short attr_name; unsigned short n; unsigned char clear; char *p; char *kid; char *failure_kid = 0; char *success_kid = 0; char *notfound_kid = 0; int i; time_t tc; urecord_t* r; ucontact_t* contact; clear = NO_VAL; /* check the params */ for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) { get_basic_attr(p,attr_name,n,intr,script_error); switch (attr_name) { case CLEAR_ATTR: if (n!=YES_VAL && n!=NO_VAL) LOG(L_WARN,"WARNING:run_lookup: invalid value (%u) found" " for param. CLEAR in LOOKUP node -> using " "default (%u)!\n",n,clear); else clear = n; break; default: LOG(L_ERR,"ERROR:run_lookup: unknown attribute (%d) in " "LOOKUP node\n",attr_name); goto script_error; } } /* check the kids */ for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) { kid = intr->ip + KID_OFFSET(intr->ip,i); check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error); switch ( NODE_TYPE(kid) ) { case SUCCESS_NODE : success_kid = kid; break; case NOTFOUND_NODE: notfound_kid = kid; break; case FAILURE_NODE: failure_kid = kid; break; default: LOG(L_ERR,"ERROR:run_lookup: unknown output node type" " (%d) for LOOKUP node\n",NODE_TYPE(kid)); goto script_error; } } kid = failure_kid; if (cpl_domain) { /* fetch user's contacts via usrloc */ tc = time(0); cpl_ulb.lock_udomain( cpl_domain ); i = cpl_ulb.get_urecord( cpl_domain, &intr->user, &r); if (i < 0) { /* failure */ LOG(L_ERR, "ERROR:run_lookup: Error while querying usrloc\n"); cpl_ulb.unlock_udomain( cpl_domain ); } else if (i > 0) { /* not found */ DBG("DBG:cpl-c:run_lookup: '%.*s' Not found in usrloc\n", intr->user.len, intr->user.s); cpl_ulb.unlock_udomain( cpl_domain ); kid = notfound_kid; } else { contact = r->contacts; /* skip expired contacts */ while ((contact) && ((contact->expires <= tc) || (contact->state >= CS_ZOMBIE_N))) contact = contact->next; /* any contacts left? */ if (contact) { /* clear loc set if requested */ if (clear) empty_location_set( &(intr->loc_set) ); /* add first location to set */ DBG("DBG:cpl-c:run_lookup: adding <%.*s>q=%d\n", contact->c.len,contact->c.s,(int)(10*contact->q)); if (add_location( &(intr->loc_set), &contact->c, (int)(10*contact->q), CPL_LOC_DUPL|((contact->flags & FL_NAT)*CPL_LOC_NATED) )==-1) { LOG(L_ERR,"ERROR:cpl-c:run_lookup: unable to add " "location to set :-(\n"); cpl_ulb.unlock_udomain( cpl_domain ); goto runtime_error; } /* set the flag for modifing the location set */ intr->flags |= CPL_LOC_SET_MODIFIED; /* we found a valid contact */ kid = success_kid; } else { /* no valid contact found */ kid = notfound_kid; } cpl_ulb.unlock_udomain( cpl_domain ); } } if (kid) return get_first_child(kid); return DEFAULT_ACTION; runtime_error: return CPL_RUNTIME_ERROR; script_error: return CPL_SCRIPT_ERROR; }
/** * Save contact based on REGISTER request. this will be a pending save, until we receive response * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE */ int save_pending(struct sip_msg* _m, udomain_t* _d) { contact_body_t* cb = 0; int cexpires = 0; pcontact_t* pcontact; contact_t* c; struct pcontact_info ci; struct via_body* vb; unsigned short port, proto; int_str val; struct sip_uri parsed_received; char srcip[50]; memset(&ci, 0, sizeof(struct pcontact_info)); vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; cb = cscf_parse_contacts(_m); if (!cb || (!cb->contacts)) { LM_ERR("No contact headers\n"); goto error; } c = cb->contacts; //TODO: need support for multiple contacts - currently assume one contact //make sure this is not a de-registration int expires_hdr = cscf_get_expires_hdr(_m, 0); if (expires_hdr < 0) { //no global header we have to check the contact expiry if (c && c->expires && c->expires->body.len) { str2int(&(c->expires->body), (unsigned int*) &cexpires); } if (!cexpires){ //assume de-registration LM_DBG("not doing pending reg on de-registration\n"); return 1; } } pcscf_act_time(); int local_time_now = time_now; int expires = calc_contact_expires(c, expires_hdr, local_time_now); if (expires <= 0) { LM_DBG("not doing pending reg on de-registration\n"); return 1; } LM_DBG("Save Pending"); LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now); /*populate CI with bare minimum*/ ci.via_host = vb->host; ci.via_port = port; ci.via_prot = proto; ci.aor = c->uri; ci.num_public_ids=0; ci.num_service_routes=0; ci.expires=local_time_now + pending_reg_expires; ci.reg_state=PCONTACT_ANY; ci.searchflag=SEARCH_RECEIVED; //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending. // Received Info: First try AVP, otherwise simply take the source of the request: 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) { LM_ERR("received too long\n"); goto error; } if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) { LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s); goto error; } ci.received_host = parsed_received.host; ci.received_port = parsed_received.port_no; ci.received_proto = parsed_received.proto; } else { ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); ci.received_host.s = srcip; ci.received_port = _m->rcv.src_port; ci.received_proto = _m->rcv.proto; } // Set to default, if not set: if (ci.received_port == 0) ci.received_port = 5060; ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s); ci.reg_state=PCONTACT_REG_PENDING; if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { LM_ERR("Failed inserting new pcontact\n"); } else { LM_DBG("registering for UL callback\n"); ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL); } } else { //contact already exists - update LM_DBG("Contact already exists - not doing anything for now\n"); } ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot); return 1; error: LM_DBG("Error saving pending contact\n"); return -1; }
/** * Updates the registrar with the new values * @param req - the REGISTER request - to extract NAT info * @param rpl - the REGISTER reply - to extract contact info * @param is_star - whether this was a STAR contact header * @param expires_hdr - value of the Expires header * @param public_id - array of public identities attached to this contact * @param public_id_cnt - size of the public_id array * @param service_route - array of Service-Routes * @param service_route_cnt - size of the service_route array * @param requires_nat - if to create pinholes * @returns the maximum expiration time, -1 on error */ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udomain_t* _d, unsigned char is_star,int expires_hdr, str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat) { int local_time_now, expires=0; struct hdr_field* h; contact_t* c; struct sip_uri puri; struct pcontact_info ci; pcontact_t* pcontact; unsigned short port, proto; char *alias_start, *p, *port_s, *proto_s; char portbuf[5]; str alias_s; pcscf_act_time(); local_time_now = time_now; if (is_star) { /* first of all, we shouldn't get here... * then, we will update on NOTIFY */ return 0; } // Set the structure to "0", to make sure it's properly initialized memset(&ci, 0, sizeof(struct pcontact_info)); for (h = rpl->contact; h; h = h->next) { if (h->type == HDR_CONTACT_T && h->parsed) { for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) { expires = calc_contact_expires(c, expires_hdr, local_time_now); if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) { LM_DBG("Error parsing Contact URI <%.*s>\n", c->uri.len, c->uri.s); continue; } //build contact info ci.aor = c->uri; ci.expires = expires; ci.public_ids = public_id; ci.num_public_ids = public_id_cnt; ci.service_routes = service_route; ci.num_service_routes = service_route_cnt; ci.reg_state = PCONTACT_REGISTERED|PCONTACT_REG_PENDING|PCONTACT_REG_PENDING_AAR; //we don't want to add contacts that did not come through us (pcscf) ci.received_host.len = 0; ci.received_host.s = 0; ci.received_port = 0; ci.received_proto = 0; port = puri.port_no ? puri.port_no : 5060; ci.via_host = puri.host; ci.via_port = port; ci.via_prot = puri.proto; ci.searchflag = SEARCH_NORMAL; /* this must be reset for each contact iteration */ if (puri.params.len > 6 && (alias_start = _strnistr(puri.params.s, "alias=", puri.params.len)) != NULL) { LM_DBG("contact has an alias [%.*s] - we can use that as the received\n", puri.params.len, puri.params.s); alias_s.len = puri.params.len - (alias_start - puri.params.s) - 6; alias_s.s = alias_start + 6; LM_DBG("alias [%.*s]\n", alias_s.len, alias_s.s); p = _strnistr(alias_s.s, "~", alias_s.len); if (p!=NULL) { ci.received_host.s = alias_s.s; ci.received_host.len = p - alias_s.s; LM_DBG("alias(host) [%.*s]\n", ci.received_host.len, ci.received_host.s); port_s = p+1; p = _strnistr(port_s, "~", alias_s.len - ci.received_host.len); if (p!=NULL) { LM_DBG("alias(port) [%.*s]\n", (int)(p - port_s) , port_s); memset(portbuf, 0, 5); memcpy(portbuf, port_s, (p-port_s)); port = atoi(portbuf); LM_DBG("alias(port) [%d]\n", port); proto_s = p + 1; memset(portbuf, 0, 5); memcpy(portbuf, proto_s, 1); proto = atoi(portbuf); LM_DBG("alias(proto) [%d]\n", proto); ci.received_port = port; ci.received_proto = proto; ci.searchflag = SEARCH_RECEIVED; } } } ul.lock_udomain(_d, &puri.host, port, puri.proto); if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact if ((expires-local_time_now)<=0) { //remove contact - de-register LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s); goto next_contact; } LM_DBG("We don't add contact from the 200OK that did not go through us (ie, not present in explicit REGISTER that went through us\n"); // LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now); // ci.reg_state = PCONTACT_REGISTERED; // if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { // LM_ERR("Failed inserting new pcontact\n"); // } else { // //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change // LM_DBG("registering for UL callback\n"); // ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); // //we also need to subscribe to reg event of this contact at SCSCF // } } else { //contact already exists - update LM_DBG("contact already exists and is in state (%d) : [%s]\n",pcontact->reg_state, reg_state_to_string(pcontact->reg_state)); if ((expires-local_time_now)<=0) { //remove contact - de-register LM_DBG("This is a de-registration for contact <%.*s>\n", c->uri.len, c->uri.s); if (ul.delete_pcontact(_d, pcontact) != 0) { LM_ERR("failed to delete pcscf contact <%.*s>\n", c->uri.len, c->uri.s); } //TODO_LATEST replace above } else { //update contact LM_DBG("Updating contact: <%.*s>, old expires: %li, new expires: %i which is in %i seconds\n", c->uri.len, c->uri.s, pcontact->expires-local_time_now, expires, expires-local_time_now); ci.reg_state = PCONTACT_REGISTERED; if (ul.update_pcontact(_d, &ci, pcontact) != 0) { LM_ERR("failed to update pcscf contact\n"); } pcontact->expires = expires; } } next_contact: ul.unlock_udomain(_d, &puri.host, port, puri.proto); } } } return 1; }
/** * Check, if a user-agent follows the indicated service-routes */ int check_service_routes(struct sip_msg* _m, udomain_t* _d) { struct sip_uri uri; int i; struct hdr_field *hdr; rr_t *r; // char srcip[20]; // str received_host; struct via_body * vb; unsigned short port; unsigned short proto; /* Contact not found => not following service-routes */ if (c == NULL) return -1; /* Search for the first Route-Header: */ if (find_first_route(_m) < 0) return -1; LM_DBG("Got %i Route-Headers.\n", c->num_service_routes); // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); // received_host.s = srcip; vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; /* Lock this record while working with the data: */ ul.lock_udomain(_d, &vb->host, port, proto); pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED); if (!c) { LM_DBG("no contact found in usrloc when checking for service route\n"); goto error; } /* Check the route-set: */ if (_m->route) { hdr = _m->route; LM_DBG("hdr is %p\n", hdr); /* Check, if the first host is ourself: */ r = (rr_t*)hdr->parsed; if (r) { LM_DBG("Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Skip first headers containing myself: */ while (r && (parse_uri(r->nameaddr.uri.s, r->nameaddr.uri.len, &uri) == 0) && check_self(&uri.host,uri.port_no?uri.port_no:SIP_PORT,0)) { LM_DBG("Self\n"); /* Check for more headers and fail, if it was the last one Check, if service-routes are indicated. If yes, request is not following service-routes */ if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; if (!r && (c->num_service_routes > 0)) { LM_DBG("Not enough route-headers in Message\n"); goto error; } LM_DBG("hdr is %p\n", hdr); LM_DBG("r is %p\n", r); if (r) LM_DBG("Next Route is %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); } LM_DBG("We have %d service-routes\n", c->num_service_routes); /* Then check the following headers: */ for (i=0; i< c->num_service_routes; i++) { LM_DBG("Route must be: %.*s\n", c->service_routes[i].len, c->service_routes[i].s); /* No more Route-Headers? Not following service-routes */ if (!r) { LM_DBG("No more route headers in message.\n"); goto error; } LM_DBG("Route is: %.*s\n", r->nameaddr.uri.len, r->nameaddr.uri.s); /* Check length: */ if (r->nameaddr.uri.len != c->service_routes[i].len) { LM_DBG("Length does not match.\n"); goto error; } /* Check contents: */ if (strncasecmp(r->nameaddr.uri.s, c->service_routes[i].s, c->service_routes[i].len) != 0) { LM_DBG("String comparison failed.\n"); goto error; } if (find_next_route(_m, &hdr) != 0) r = NULL; else r = (rr_t*)hdr->parsed; } /* Check, if it was the last route-header in the message: */ if (r) { LM_DBG("Too many route headers in message.\n"); goto error; } } else { LM_WARN("Strange: Route-Header is present, but not parsed?!?"); if (c->num_service_routes > 0) goto error; } } else { LM_DBG("No route header in Message.\n"); /* No route-header? Check, if service-routes are indicated. If yes, request is not following service-routes */ if (c->num_service_routes > 0) goto error; } /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return 1; error: /* Unlock domain */ ul.unlock_udomain(_d, &vb->host, port, proto); return -1; }
int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) { pcontact_t* pcontact; struct pcontact_info ci; int local_time_now; int ret = RESULT_CONTACTS_FOUND; pcscf_act_time(); local_time_now = time_now; //get contact //if does not exist then add it //if it does exist check if state it terminated - if so delete it, if not update it memset(&ci, 0, sizeof(struct pcontact_info)); ci.num_public_ids=0; ci.num_service_routes=0; expires = local_time_now + expires; //turn expires into correct time since epoch format LM_DBG("Changed expires to format time since the epoch: %d", expires); ci.expires=expires; ci.reg_state = PCONTACT_REGISTERED; ul.lock_udomain(_d, &contact_uri); if (ul.get_pcontact(_d, &contact_uri, &pcontact) != 0) { //contact does not exist if (contact_state == STATE_TERMINATED) { LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s); ret = RESULT_CONTACTS_FOUND; goto done; } LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now); if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) { LM_ERR("Failed inserting new pcontact\n"); ret = RESULT_ERROR; goto done; } else { //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change LM_DBG("registering for UL callback\n"); ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); } } else {//contact exists if (contact_state == STATE_TERMINATED) { //delete contact LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s); if (ul.delete_pcontact(_d, &contact_uri, pcontact) != 0) { LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s); } } else {//state is active //update this contact LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s, pcontact->expires, expires, expires-local_time_now); if (ul.update_pcontact(_d, &ci, pcontact) != 0) { LM_ERR("failed to update pcscf contact\n"); ret = RESULT_ERROR; goto done; } pcontact->expires = expires; } } done: ul.unlock_udomain(_d, &contact_uri); return ret; }
int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) { char bufport[5], *rest, *sep, *val, *port, *trans; pcontact_t* pcontact; struct pcontact_info ci; struct sip_uri puri, uri; unsigned int received_proto, received_port_len; int local_time_now, rest_len, val_len, has_alias; int ret = RESULT_CONTACTS_FOUND; pcscf_act_time(); local_time_now = time_now; has_alias = 0; //get contact //if does not exist then add it //if it does exist check if state it terminated - if so delete it, if not update it memset(&ci, 0, sizeof (struct pcontact_info)); ci.num_public_ids = 0; ci.num_service_routes = 0; LM_DBG("Processing contact using contact from NOTIFY [%.*s]\n", contact_uri.len, contact_uri.s); if (parse_uri(contact_uri.s, contact_uri.len, &puri) < 0) { LM_DBG("Error parsing Contact URI <%.*s>\n", contact_uri.len, contact_uri.s); return RESULT_ERROR; } expires = local_time_now + expires; //turn expires into correct time since epoch format LM_DBG("Changed expires to format time since the epoch: %d", expires); ci.expires = expires; ci.reg_state = PCONTACT_REGISTERED; ul.lock_udomain(_d, &puri.host, puri.port_no, puri.proto); ci.aor = contact_uri; ci.via_host = puri.host; ci.via_prot = puri.proto; ci.via_port = puri.port_no; /* parse the uri in the NOTIFY */ if (parse_uri(contact_uri.s, contact_uri.len, &uri) != 0) { LM_ERR("Unable to parse contact in SIP notify [%.*s]\n", contact_uri.len, contact_uri.s); return RESULT_ERROR; } /*check for alias - NAT */ rest = uri.sip_params.s; rest_len = uri.sip_params.len; while (rest_len >= ALIAS_LEN) { if (strncmp(rest, ALIAS, ALIAS_LEN) == 0) { has_alias = 1; break; } sep = memchr(rest, 59 /* ; */, rest_len); if (sep == NULL) { LM_DBG("no alias param\n"); break; } else { rest_len = rest_len - (sep - rest + 1); rest = sep + 1; } } if (has_alias) { val = rest + ALIAS_LEN; val_len = rest_len - ALIAS_LEN; port = memchr(val, 126 /* ~ */, val_len); if (port == NULL) { LM_ERR("no '~' in alias param value\n"); return RESULT_ERROR; } port++; // received_port = atoi(port); trans = memchr(port, 126 /* ~ */, val_len - (port - val)); if (trans == NULL) { LM_ERR("no second '~' in alias param value\n"); return RESULT_ERROR; } received_port_len = trans - port; trans = trans + 1; received_proto = *trans - 48 /* char 0 */; memcpy(bufport, port, received_port_len); bufport[received_port_len]=0; ci.received_host.s = val; ci.received_host.len = port - val - 1; LM_DBG("Setting received host in search to [%.*s]\n", ci.received_host.len, ci.received_host.s); ci.received_port = atoi(bufport); LM_DBG("Setting received port in search to %d\n", ci.received_port); ci.received_proto = received_proto; LM_DBG("Setting received proto in search to %d\n", ci.received_proto); ci.searchflag = SEARCH_RECEIVED; } else { LM_DBG("Contact in NOTIFY does not have an alias....\n"); } if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //contact does not exist if (contact_state == STATE_TERMINATED) { LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s); ret = RESULT_CONTACTS_FOUND; goto done; } LM_WARN("This contact: <%.*s> is in state active and is not in usrloc - must be another contact on a different P so going to ignore\n", contact_uri.len, contact_uri.s); // LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now); // if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) { // LM_ERR("Failed inserting new pcontact\n"); // ret = RESULT_ERROR; // goto done; // } else { // //register for callbacks on this contact so we can send PUBLISH to SCSCF should status change // LM_DBG("registering for UL callback\n"); // ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL); // } } else {//contact exists if (contact_state == STATE_TERMINATED) { //delete contact LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s); if (ul.delete_pcontact(_d, pcontact) != 0) { LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s); } /*TODO_LATEST - put this back */ } else {//state is active //update this contact LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s, pcontact->expires, expires, expires - local_time_now); if (ul.update_pcontact(_d, &ci, pcontact) != 0) { LM_ERR("failed to update pcscf contact\n"); ret = RESULT_ERROR; goto done; } pcontact->expires = expires; } } done: ul.unlock_udomain(_d, &puri.host, puri.port_no, puri.proto); return ret; }