void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code ) { struct tmcb_params params; struct tm_callback *cbp; struct usr_avp **backup; struct cell *trans_backup = get_t(); params.req = req; params.rpl = 0; params.code = code; params.extra1 = tmcb_extra1; params.extra2 = tmcb_extra2; if (req_in_tmcb_hl->first==0) return; backup = set_avp_list( &trans->user_avps ); for (cbp=req_in_tmcb_hl->first; cbp; cbp=cbp->next) { LM_DBG("trans=%p, callback type %d, id %d entered\n", trans, cbp->types, cbp->id ); params.param = &(cbp->param); cbp->callback( trans, cbp->types, ¶ms ); } set_avp_list( backup ); tmcb_extra1 = tmcb_extra2 = 0; set_t(trans_backup); }
/*if msg is set -> it will fake the env. vars conforming with the msg; if NULL * the env. will be restore to original */ static inline void faked_env( struct cell *t,struct sip_msg *msg) { static struct cell *backup_t; static struct usr_avp **backup_list; static struct socket_info* backup_si; static int backup_route_type; if (msg) { swap_route_type( backup_route_type, FAILURE_ROUTE); /* tm actions look in beginning whether transaction is * set -- whether we are called from a reply-processing * or a timer process, we need to set current transaction; * otherwise the actions would attempt to look the transaction * up (unnecessary overhead, refcounting) */ /* backup */ backup_t = get_t(); /* fake transaction */ set_t(t); /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* set default send address to the saved value */ backup_si = bind_address; bind_address = t->uac[0].request.dst.send_sock; } else { /* restore original environment */ set_t(backup_t); set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); bind_address = backup_si; } }
void run_trans_callbacks( int type , struct cell *trans, struct sip_msg *req, struct sip_msg *rpl, int code ) { struct tmcb_params params; struct tm_callback *cbp; struct usr_avp **backup; struct cell *trans_backup = get_t(); params.req = req; params.rpl = rpl; params.code = code; params.extra1 = tmcb_extra1; params.extra2 = tmcb_extra2; if (trans->tmcb_hl.first==0 || ((trans->tmcb_hl.reg_types)&type)==0 ) return; backup = set_avp_list( &trans->user_avps ); for (cbp=trans->tmcb_hl.first; cbp; cbp=cbp->next) { if ( (cbp->types)&type ) { LM_DBG("trans=%p, callback type %d, id %d entered\n", trans, type, cbp->id ); params.param = &(cbp->param); cbp->callback( trans, type, ¶ms ); } } /* env cleanup */ set_avp_list( backup ); tmcb_extra1 = tmcb_extra2 = 0; set_t(trans_backup); }
int evi_raise_event(event_id_t id, evi_params_t* params) { int status; struct sip_msg* req= NULL; struct usr_avp *event_avps = 0; struct usr_avp **bak_avps = 0; /* * because these might be nested, a different message has * to be generated each time */ req = (struct sip_msg*)pkg_malloc(sizeof(struct sip_msg)); if(req == NULL) { LM_ERR("No more memory\n"); return -1; } memset(req, 0, sizeof(struct sip_msg)); req->first_line.type = SIP_REQUEST; req->first_line.u.request.method.s= "DUMMY"; req->first_line.u.request.method.len= 5; req->first_line.u.request.uri.s= "sip:[email protected]"; req->first_line.u.request.uri.len= 19; bak_avps = set_avp_list(&event_avps); status = evi_raise_event_msg(req, id, params); /* clean whatever extra structures were added by script functions */ free_sip_msg(req); pkg_free(req); /* remove all avps added */ destroy_avp_list(&event_avps); set_avp_list(bak_avps); return status; }
static int lookup_domain(struct sip_msg* msg, char* flags, char* fp) { str domain, tmp; domain_t* d; unsigned int track; int ret = -1; track = 0; if (get_str_fparam(&domain, msg, (fparam_t*)fp) != 0) { ERR("Cannot get domain name to lookup\n"); return -1; } tmp.s = pkg_malloc(domain.len); if (!tmp.s) { ERR("No memory left\n"); return -1; } memcpy(tmp.s, domain.s, domain.len); tmp.len = domain.len; strlower(&tmp); if (db_mode) { if (hash_lookup(&d, *active_hash, &tmp) == 1) { set_avp_list((unsigned long)flags, &d->attrs); ret = 1; } } else { if (db_load_domain(&d, (unsigned long)flags, &tmp) == 0) { set_avp_list((unsigned long)flags, &d->attrs); ret = 1; } } pkg_free(tmp.s); return ret; }
void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elapsed_msecs) { struct cell *t = 0; unsigned int cdp_result; int result = CSCF_RETURN_ERROR; LM_DBG("Received AAR callback\n"); saved_transaction_t* data = (saved_transaction_t*) param; LM_DBG("received AAA answer"); if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("t_continue: transaction not found\n"); goto error; } else { LM_DBG("t_continue: transaction found\n"); } //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.media_aar_timeouts); goto error; } if (!aaa) { LM_ERR("Error sending message via CDP\n"); goto error; } counter_inc(ims_qos_cnts_h.media_aars); counter_add(ims_qos_cnts_h.media_aar_response_time, elapsed_msecs); counter_inc(ims_qos_cnts_h.media_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) { LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result); counter_inc(ims_qos_cnts_h.successful_media_aars); LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s); if(!data->aar_update) { LM_DBG("This is an AAA response to an initial AAR"); counter_inc(ims_qos_cnts_h.active_media_rx_sessions); str * passed_rx_session_id = shm_malloc(sizeof (struct _str)); passed_rx_session_id->s = 0; passed_rx_session_id->len = 0; STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id"); LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s); dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_CONFIRMED | DLGCB_FAILED, callback_dialog, (void*) (passed_rx_session_id), free_dialog_data); } result = CSCF_RETURN_TRUE; } else { LM_DBG("Received negative reply from PCRF for AAR Request\n"); counter_inc(ims_qos_cnts_h.failed_media_aars); //we don't free rx_authdata_p here - it is free-ed when the CDP session expires goto error; // if its not a success then that means i want to reject this call! } //set success response code AVP create_return_code(result); goto done; out_of_memory: error : //set failure response code create_return_code(result); done: if (t) tmb.unref_cell(t); //free memory if (aaa) cdpb.AAAFreeMessage(&aaa); tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_global_data(data); }
/* function triggered from reactor in order to continue the processing */ int t_resume_async(int *fd, void *param) { static struct sip_msg faked_req; static struct ua_client uac; async_ctx *ctx = (async_ctx *)param; struct cell *backup_t; struct cell *backup_cancelled_t; struct cell *backup_e2eack_t; struct usr_avp **backup_list; struct socket_info* backup_si; struct cell *t= ctx->t; int route; LM_DBG("resuming on fd %d, transaction %p \n",*fd, t); if (current_processing_ctx) { LM_CRIT("BUG - a context already set!\n"); abort(); } /* prepare for resume route */ uac.br_flags = getb0flags( t->uas.request ) ; uac.uri = *GET_RURI( t->uas.request ); if (!fake_req( &faked_req /* the fake msg to be built*/, t->uas.request, /* the template msg saved in transaction */ &t->uas, /*the UAS side of the transaction*/ &uac, /* the fake UAC */ 1 /* copy dst_uri too */) ) { LM_ERR("fake_req failed\n"); return 0; } /* enviroment setting */ current_processing_ctx = ctx->msg_ctx; backup_t = get_t(); backup_e2eack_t = get_e2eack_t(); backup_cancelled_t = get_cancelled_t(); /* fake transaction */ set_t( t ); set_cancelled_t(ctx->cancelled_t); set_e2eack_t(ctx->e2eack_t); reset_kr(); set_kr(ctx->kr); /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* set default send address to the saved value */ backup_si = bind_address; bind_address = t->uac[0].request.dst.send_sock; async_status = ASYNC_DONE; /* assume default status as done */ /* call the resume function in order to read and handle data */ return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param ); if (async_status==ASYNC_CONTINUE) { /* do not run the resume route */ goto restore; } else if (async_status==ASYNC_CHANGE_FD) { if (return_code<0) { LM_ERR("ASYNC_CHANGE_FD: given file descriptor shall be positive!\n"); goto restore; } else if (return_code > 0 && return_code == *fd) { /*trying to add the same fd; shall continue*/ LM_CRIT("You are trying to replace the old fd with the same fd!" "Will act as in ASYNC_CONTINUE!\n"); goto restore; } /* remove the old fd from the reactor */ reactor_del_reader( *fd, -1, IO_FD_CLOSING); *fd=return_code; /* insert the new fd inside the reactor */ if (reactor_add_reader( *fd, F_SCRIPT_ASYNC, RCT_PRIO_ASYNC, (void*)ctx)<0 ) { LM_ERR("failed to add async FD to reactor -> act in sync mode\n"); do { return_code = ctx->resume_f( *fd, &faked_req, ctx->resume_param ); if (async_status == ASYNC_CHANGE_FD) *fd=return_code; } while(async_status==ASYNC_CONTINUE||async_status==ASYNC_CHANGE_FD); goto route; } /* changed fd; now restore old state */ goto restore; } /* remove from reactor, we are done */ reactor_del_reader( *fd, -1, IO_FD_CLOSING); route: if (async_status == ASYNC_DONE_CLOSE_FD) close(*fd); /* run the resume_route (some type as the original one) */ swap_route_type(route, ctx->route_type); run_resume_route( ctx->resume_route, &faked_req); set_route_type(route); /* no need for the context anymore */ shm_free(ctx); /* free also the processing ctx if still set * NOTE: it may become null if inside the run_resume_route * another async jump was made (and context attached again * to transaction) */ if (current_processing_ctx) { context_destroy(CONTEXT_GLOBAL, current_processing_ctx); pkg_free(current_processing_ctx); } restore: /* restore original environment */ set_t(backup_t); set_cancelled_t(backup_cancelled_t); set_e2eack_t(backup_e2eack_t); /* restore original avp list */ set_avp_list( backup_list ); bind_address = backup_si; free_faked_req( &faked_req, t); current_processing_ctx = NULL; return 0; }
void async_cdp_uar_callback(int is_timeout, void *param, AAAMessage *uaa, long elapsed_msecs) { struct run_act_ctx ra_ctx; str server_name; int *m_capab = 0, m_capab_cnt = 0; int *o_capab = 0, o_capab_cnt = 0; str *p_server_names = 0; int p_server_names_cnt = 0; int rc = -1, experimental_rc = -1; saved_uar_transaction_t* data = (saved_uar_transaction_t*) param; struct cell *t = 0; int result = CSCF_RETURN_TRUE; scscf_entry *list = 0; if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("ERROR: t_continue: transaction not found\n"); //result = CSCF_RETURN_ERROR;//not needed we set by default to error! goto error; } if (is_timeout != 0) { LM_ERR("Error timeout when sending message via CDP\n"); update_stat(stat_uar_timeouts, 1); goto error; } //update stats on response time update_stat(uar_replies_received, 1); update_stat(uar_replies_response_time, elapsed_msecs); if (!uaa) { LM_ERR("Error sending message via CDP\n"); //result = CSCF_RETURN_ERROR;//not needed we set by default to error! goto error; } server_name = cxdx_get_server_name(uaa); if (!server_name.len) { cxdx_get_capabilities(uaa, &m_capab, &m_capab_cnt, &o_capab, &o_capab_cnt, &p_server_names, &p_server_names_cnt); } cxdx_get_result_code(uaa, &rc); cxdx_get_experimental_result_code(uaa, &experimental_rc); if (rc && !experimental_rc) { LM_ERR("No result code or experimental result code - responding 480\n"); cscf_reply_transactional_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP); result = CSCF_RETURN_FALSE; goto done; } switch (rc) { case -1: switch (experimental_rc) { case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN: /* Check, if route is set: */ if (route_uar_user_unknown_no >= 0) { /* exec routing script */ init_run_actions_ctx(&ra_ctx); if (run_actions(&ra_ctx, main_rt.rlist[route_uar_user_unknown_no], t->uas.request) < 0) { LM_DBG("ims_icscf: error while trying script\n"); } } else { cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_USER_UNKNOWN); } LM_ERR("RC_IMS_DIAMETER_ERROR_USER_UNKNOWN\n"); result = CSCF_RETURN_FALSE; goto done; case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH: LM_ERR("RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_IDENTITIES_DONT_MATCH); result = CSCF_RETURN_FALSE; goto done; case RC_IMS_DIAMETER_ERROR_ROAMING_NOT_ALLOWED: LM_ERR("RC_IMS_DIAMETER_ERROR_ROAMING_NOT_ALLOWED returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_ROAMING_NOT_ALLOWED); result = CSCF_RETURN_FALSE; goto done; case RC_IMS_DIAMETER_ERROR_IDENTITY_NOT_REGISTERED: LM_ERR("RC_IMS_DIAMETER_ERROR_IDENTITY_NOT_REGISTERED returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_IDENTITY_NOT_REGISTERED); result = CSCF_RETURN_FALSE; goto done; case RC_IMS_DIAMETER_FIRST_REGISTRATION: goto success; case RC_IMS_DIAMETER_SUBSEQUENT_REGISTRATION: goto success; case RC_IMS_DIAMETER_SERVER_SELECTION: goto success; default: LM_ERR("MSG_403_UNKOWN_EXPERIMENTAL_RC returning 500\n"); cscf_reply_transactional_async(t, t->uas.request, 500, MSG_500_UNKOWN_EXPERIMENTAL_RC); result = CSCF_RETURN_FALSE; goto done; } break; case AAA_AUTHORIZATION_REJECTED: LM_ERR("AAA_AUTHORIZATION_REJECTED returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_AUTHORIZATION_REJECTED); result = CSCF_RETURN_FALSE; goto done; case AAA_UNABLE_TO_COMPLY: LM_ERR("AAA_UNABLE_TO_COMPLY returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 500, MSG_500_UNABLE_TO_COMPLY); result = CSCF_RETURN_FALSE; goto done; case AAA_SUCCESS: goto success; default: LM_ERR("MSG_403_UNKOWN_RC returning 403\n"); cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC); result = CSCF_RETURN_FALSE; goto done; } success: LM_DBG("successful UAA response\n"); list = I_get_capab_ordered(server_name, m_capab, m_capab_cnt, o_capab, o_capab_cnt, p_server_names, p_server_names_cnt, 0); if (!list) { LM_ERR("Empty capability list returning 600\n"); cscf_reply_transactional_async(t, t->uas.request, 600, MSG_600_EMPTY_LIST); result = CSCF_RETURN_FALSE; goto done; } if (!data->callid.len || !add_scscf_list(data->callid, list)) { LM_ERR("Error saving capability list 500\n"); cscf_reply_transactional_async(t, t->uas.request, 500, MSG_500_ERROR_SAVING_LIST); result = CSCF_RETURN_FALSE; goto done; } result = CSCF_RETURN_TRUE; done: //free capabilities if they exist if (m_capab) shm_free(m_capab); if (o_capab) shm_free(o_capab); if (p_server_names) shm_free(p_server_names); LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n"); 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); create_uaa_return_code(result); if (t)tmb.unref_cell(t); //free memory if (uaa) cdpb.AAAFreeMessage(&uaa); tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_uar_transaction_data(data); return; error: if (t)tmb.unref_cell(t); //free memory if (uaa) cdpb.AAAFreeMessage(&uaa); tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_uar_transaction_data(data); }
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); }
static inline int pre_print_uac_request( struct cell *t, int branch, struct sip_msg *request) { int backup_route_type; struct usr_avp **backup_list; char *p; /* ... we calculate branch ... */ if (!t_calc_branch(t, branch, request->add_to_branch_s, &request->add_to_branch_len )) { LOG(L_ERR, "ERROR:pre_print_uac_request: branch computation failed\n"); goto error; } /* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to * be able to remove them later --bogdan */ set_init_lump_flags(LUMPFLAG_BRANCH); /********** run route & callback ************/ /* run branch route, if any; run it before RURI's DNS lookup * to allow to be changed --bogdan */ if (t->on_branch) { /* need to pkg_malloc the dst_uri */ if ( request->dst_uri.len ) { if ( (p=pkg_malloc(request->dst_uri.len))==0 ) { LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->dst_uri.s, request->dst_uri.len); request->dst_uri.s = p; } /* need to pkg_malloc the new_uri */ if ( (p=pkg_malloc(request->new_uri.len))==0 ) { LOG(L_ERR,"ERROR:tm:pre_print_uac_request: no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->new_uri.s, request->new_uri.len); request->new_uri.s = p; /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* run branch route */ swap_route_type( backup_route_type, BRANCH_ROUTE); if (run_actions(branch_rlist[t->on_branch], request)==0 && (action_flags&ACT_FL_DROP) ) { DBG("DEBUG:tm:pre_print_uac_request: dropping branch <%.*s>\n", request->dst_uri.len, request->dst_uri.s); goto error; } set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); } /* run the specific callbacks for this transaction */ run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0, -request->REQ_METHOD); return 0; error: return -1; }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su; struct cell *new_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; unsigned int hi; struct socket_info* send_sock; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error2; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su, PROTO_NONE); if (send_sock==0) { ret=ser_error; LM_ERR("no socket found\n"); goto error2; } /* if a send socket defined verify if the same protocol */ if(dialog->send_sock) { if(send_sock->proto != dialog->send_sock->proto) { dialog->send_sock = send_sock; } } else { dialog->send_sock = send_sock; } new_cell = build_cell(0); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; request->dst.to = to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer"); } else { /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* transfer current message context back to t */ new_cell->uac[0].br_flags = req->flags; /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer * we ignore any change on RURI and DSTURI and they should not * be changed -bogdan */ if (req->new_uri.s) { pkg_free(req->new_uri.s); req->new_uri.s=0; req->new_uri.len=0; } if (req->dst_uri.s) { pkg_free(req->dst_uri.s); req->dst_uri.s=0; req->dst_uri.len=0; } if (req->add_rm || req->body_lumps) { LM_DBG("re-building the buffer (sip_msg changed) - lumps are" "%p %p\n",req->add_rm, req->body_lumps); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req,(unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG ); if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ } else { shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } } free_sip_msg(req); } } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: return ret; }
static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs) { Ro_CCA_t *ro_cca_data = NULL; struct cell *t = NULL; struct session_setup_data *ssd = (struct session_setup_data *) param; int error_code = RO_RETURN_ERROR; if (is_timeout) { counter_inc(ims_charging_cnts_h.ccr_timeouts); LM_ERR("Transaction timeout - did not get CCA\n"); error_code = RO_RETURN_ERROR; goto error0; } counter_inc(ims_charging_cnts_h.ccr_replies_received); counter_add(ims_charging_cnts_h.ccr_response_time, elapsed_msecs); if (!cca) { LM_ERR("Error reserving credit for CCA.\n"); error_code = RO_RETURN_ERROR; goto error0; } if (!ssd) { LM_ERR("Session lookup data is NULL.\n"); error_code = RO_RETURN_ERROR; goto error0; } // we make sure the transaction exists if (tmb.t_lookup_ident(&t, ssd->tindex, ssd->tlabel) < 0) { LM_ERR("t_continue: transaction not found\n"); error_code = RO_RETURN_ERROR; goto error0; } // we bring the list of AVPs of the transaction to the current context 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); ro_cca_data = Ro_parse_CCA_avps(cca); if (!ro_cca_data) { LM_ERR("Could not parse CCA message response.\n"); error_code = RO_RETURN_ERROR; create_cca_result_code(0); goto error0; } create_cca_result_code((int)ro_cca_data->resultcode); if (ro_cca_data->resultcode != 2001) { LM_ERR("Got bad CCA result code - reservation failed"); error_code = RO_RETURN_FALSE; goto error1; } LM_DBG("Valid CCA response with time chunk of [%i] and validity [%i]\n", ro_cca_data->mscc->granted_service_unit->cc_time, ro_cca_data->mscc->validity_time); if (ro_cca_data->mscc->granted_service_unit->cc_time <= 0) { LM_DBG("got zero GSU.... reservation failed"); error_code = RO_RETURN_FALSE; goto error1; } ssd->ro_session->last_event_timestamp = get_current_time_micro(); ssd->ro_session->event_type = pending; ssd->ro_session->reserved_secs = ro_cca_data->mscc->granted_service_unit->cc_time; ssd->ro_session->valid_for = ro_cca_data->mscc->validity_time; ssd->ro_session->is_final_allocation = 0; if (ro_cca_data->mscc->final_unit_action && (ro_cca_data->mscc->final_unit_action->action == 0)) ssd->ro_session->is_final_allocation = 1; Ro_free_CCA(ro_cca_data); LM_DBG("Freeing CCA message\n"); cdpb.AAAFreeMessage(&cca); link_ro_session(ssd->ro_session, 0); if (ro_db_mode == DB_MODE_REALTIME) { ssd->ro_session->flags |= RO_SESSION_FLAG_NEW; if (update_ro_dbinfo(ssd->ro_session) != 0) { LM_ERR("Failed to update ro_session in database... continuing\n"); }; } unref_ro_session(ssd->ro_session, 1); /* release our reference */ create_cca_return_code(RO_RETURN_TRUE); if (t) tmb.unref_cell(t); tmb.t_continue(ssd->tindex, ssd->tlabel, ssd->action); shm_free(ssd); counter_inc(ims_charging_cnts_h.successful_initial_ccrs); return; error1: Ro_free_CCA(ro_cca_data); error0: LM_DBG("Trying to reserve credit on initial INVITE failed on cdp callback\n"); // counter_add(ims_charging_cnts_h.active_ro_sessions, -1); /*we bumped active on the original initial ccr sent */ counter_inc(ims_charging_cnts_h.failed_initial_ccrs); /* drop by one as theoretically this is failed initial ccr */ create_cca_return_code(error_code); if (!is_timeout && cca) { cdpb.AAAFreeMessage(&cca); } if (t) tmb.unref_cell(t); tmb.t_continue(ssd->tindex, ssd->tlabel, ssd->action); shm_free(ssd); }
/* * Send a request using data from the dialog structure */ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, transaction_cb cb, void* cbp,release_tmcb_param release_func) { union sockaddr_union to_su, new_to_su; struct cell *new_cell; struct cell *backup_cell; struct retr_buf *request; static struct sip_msg *req; struct usr_avp **backup; char *buf, *buf1; int buf_len, buf_len1; int ret, flags, sflag_bk; int backup_route_type; int sip_msg_len; unsigned int hi; struct socket_info *new_send_sock; str h_to, h_from, h_cseq, h_callid; struct proxy_l *proxy, *new_proxy; unsigned short dst_changed; ret=-1; /*** added by dcm * - needed by external ua to send a request within a dlg */ if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0) goto error3; if(dialog->obp.s) dialog->hooks.next_hop = &dialog->obp; LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); /* calculate the socket corresponding to next hop */ proxy = uri2proxy( dialog->hooks.next_hop, dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE ); if (proxy==0) { ret=E_BAD_ADDRESS; goto error3; } /* use the first address */ hostent2su( &to_su, &proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT); /* check/discover the send socket */ if (dialog->send_sock) { /* if already set, the protocol of send sock must have the the same type as the proto required by destination URI */ if (proxy->proto != dialog->send_sock->proto) dialog->send_sock = NULL; } if (dialog->send_sock==NULL) { /* get the send socket */ dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto); if (!dialog->send_sock) { LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family); ser_error = E_NO_SOCKET; goto error2; } } LM_DBG("sending socket is %.*s \n", dialog->send_sock->name.len,dialog->send_sock->name.s); /* ***** Create TRANSACTION and all related ***** */ new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/); if (!new_cell) { ret=E_OUT_OF_MEM; LM_ERR("short of cell shmem\n"); goto error2; } /* pass the transaction flags from dialog to transaction */ new_cell->flags |= dialog->T_flags; /* add the callback the transaction for LOCAL_COMPLETED event */ flags = TMCB_LOCAL_COMPLETED; /* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */ if (pass_provisional_replies || pass_provisional(new_cell)) flags |= TMCB_LOCAL_RESPONSE_OUT; if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){ ret=E_OUT_OF_MEM; LM_ERR("short of tmcb shmem\n"); goto error2; } if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0) new_cell->flags |= T_IS_INVITE_FLAG; new_cell->flags |= T_IS_LOCAL_FLAG; request = &new_cell->uac[0].request; if (dialog->forced_to_su.s.sa_family == AF_UNSPEC) request->dst.to = to_su; else request->dst.to = dialog->forced_to_su; request->dst.send_sock = dialog->send_sock; request->dst.proto = dialog->send_sock->proto; request->dst.proto_reserved1 = 0; hi=dlg2hash(dialog); LOCK_HASH(hi); insert_into_hash_table_unsafe(new_cell, hi); UNLOCK_HASH(hi); /* copy AVPs into transaction */ new_cell->user_avps = dialog->avps; dialog->avps = NULL; /* ***** Create the message buffer ***** */ buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len); if (!buf) { LM_ERR("failed to build message\n"); ret=E_OUT_OF_MEM; goto error1; } if (local_rlist.a) { LM_DBG("building sip_msg from buffer\n"); req = buf_to_sip_msg(buf, buf_len, dialog); if (req==NULL) { LM_ERR("failed to build sip_msg from buffer\n"); } else { /* set this transaction as active one */ backup_cell = get_t(); set_t( new_cell ); /* set transaction AVP list */ backup = set_avp_list( &new_cell->user_avps ); /* backup script flags */ sflag_bk = getsflags(); /* disable parallel forking */ set_dset_state( 0 /*disable*/); /* run the route */ swap_route_type( backup_route_type, LOCAL_ROUTE); run_top_route( local_rlist.a, req); set_route_type( backup_route_type ); /* transfer current message context back to t */ new_cell->uac[0].br_flags = getb0flags(req); /* restore the prevoius active transaction */ set_t( backup_cell ); set_dset_state( 1 /*enable*/); setsflagsval(sflag_bk); set_avp_list( backup ); /* check for changes - if none, do not regenerate the buffer */ dst_changed = 1; if (req->new_uri.s || req->force_send_socket!=dialog->send_sock || req->dst_uri.len != dialog->hooks.next_hop->len || memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) || (dst_changed=0)==0 || req->add_rm || req->body_lumps){ new_send_sock = NULL; /* do we also need to change the destination? */ if (dst_changed) { /* calculate the socket corresponding to next hop */ new_proxy = uri2proxy( req->dst_uri.s ? &(req->dst_uri) : &req->new_uri, PROTO_NONE ); if (new_proxy==0) goto abort_update; /* use the first address */ hostent2su( &new_to_su, &new_proxy->host, new_proxy->addr_idx, new_proxy->port ? new_proxy->port:SIP_PORT); /* get the send socket */ new_send_sock = get_send_socket( req, &new_to_su, new_proxy->proto); if (!new_send_sock) { free_proxy( new_proxy ); pkg_free( new_proxy ); LM_ERR("no socket found for the new destination\n"); goto abort_update; } } /* if interface change, we need to re-build the via */ if (new_send_sock && new_send_sock != dialog->send_sock) { LM_DBG("Interface change in local route -> " "rebuilding via\n"); if (!del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len,0)) { LM_ERR("Failed to remove initial via \n"); goto abort_update; } memcpy(req->add_to_branch_s,req->via1->branch->value.s, req->via1->branch->value.len); req->add_to_branch_len = req->via1->branch->value.len; /* update also info about new destination and send sock */ dialog->send_sock = new_send_sock; free_proxy( proxy ); pkg_free( proxy ); proxy = new_proxy; request->dst.send_sock = new_send_sock; request->dst.proto = new_send_sock->proto; request->dst.proto_reserved1 = 0; /* build the shm buffer now */ set_init_lump_flags(LUMPFLAG_BRANCH); buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, new_send_sock, new_send_sock->proto, MSG_TRANS_SHM_FLAG); reset_init_lump_flags(); del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH); } else { LM_DBG("Change in local route -> rebuilding buffer\n"); /* build the shm buffer now */ buf1 = build_req_buf_from_sip_req(req, (unsigned int*)&buf_len1, dialog->send_sock, dialog->send_sock->proto, MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG); /* now as it used, hide the original VIA header */ del_lump(req,req->h_via1->name.s - req->buf, req->h_via1->len, 0); } if (!buf1) { LM_ERR("no more shm mem\n"); /* keep original buffer */ goto abort_update; } /* update shortcuts */ if(!req->add_rm && !req->new_uri.s) { /* headers are not affected, simply tranlate */ new_cell->from.s = new_cell->from.s - buf + buf1; new_cell->to.s = new_cell->to.s - buf + buf1; new_cell->callid.s = new_cell->callid.s - buf + buf1; new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1; } else { /* use heavy artilery :D */ if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to, &h_cseq, &h_callid)!=0 ) { LM_ERR("failed to update shortcut pointers\n"); shm_free(buf1); goto abort_update; } new_cell->from = h_from; new_cell->to = h_to; new_cell->callid = h_callid; new_cell->cseq_n = h_cseq; } /* here we rely on how build_uac_req() builds the first line */ new_cell->uac[0].uri.s = buf1 + req->first_line.u.request.method.len + 1; new_cell->uac[0].uri.len = GET_RURI(req)->len; /* update also info about new destination and send sock */ if (new_send_sock) request->dst.to = new_to_su; shm_free(buf); buf = buf1; buf_len = buf_len1; /* use new buffer */ } else { /* no changes over the message, buffer is already generated, just hide the original VIA for potential further branches */ del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0); } abort_update: /* save the SIP message into transaction */ new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1); if (new_cell->uas.request==NULL) { /* reset any T triggering */ new_cell->on_negative = 0; new_cell->on_reply = 0; } else { new_cell->uas.end_request= ((char*)new_cell->uas.request)+sip_msg_len; } /* no parallel support in UAC transactions */ new_cell->on_branch = 0; free_sip_msg(req); } } /* for DNS based failover, copy the DNS proxy into transaction */ if (!disable_dns_failover) { new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/); if (new_cell->uac[0].proxy==NULL) LM_ERR("failed to store DNS info -> no DNS based failover\n"); } new_cell->method.s = buf; new_cell->method.len = method->len; request->buffer.s = buf; request->buffer.len = buf_len; new_cell->nr_of_outgoings++; if(last_localT) { *last_localT = new_cell; REF_UNSAFE(new_cell); } if (SEND_BUFFER(request) == -1) { LM_ERR("attempt to send to '%.*s' failed\n", dialog->hooks.next_hop->len, dialog->hooks.next_hop->s); } if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) { t_release_transaction(new_cell); } else { start_retr(request); } free_proxy( proxy ); pkg_free( proxy ); return 1; error1: LOCK_HASH(hi); remove_from_hash_table_unsafe(new_cell); UNLOCK_HASH(hi); free_cell(new_cell); error2: free_proxy( proxy ); pkg_free( proxy ); error3: return ret; }
int pv_get_tm_branch_avp(struct sip_msg *msg, pv_param_t *param, pv_value_t *val) { int avp_name; int_str avp_value; unsigned short name_type; int idx, idxf, res=0; struct usr_avp **old_list=NULL; struct usr_avp **avp_list=NULL; struct usr_avp *avp; int_str avp_value0; struct usr_avp *avp0; int n=0; char *p; if (!msg || !val) goto error; avp_list = get_bavp_list(); if (!avp_list) { pv_get_null(msg, param, val); goto success; } if (!param) { LM_ERR("bad parameters\n"); goto error; } if (pv_get_avp_name(msg, param, &avp_name, &name_type)) { LM_ALERT("BUG in getting bavp name\n"); goto error; } /* get the index */ if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) { LM_ERR("invalid index\n"); goto error; } /* setting the avp head */ old_list = set_avp_list(avp_list); if (!old_list) { LM_CRIT("no bavp head list found\n"); goto error; } if ((avp=search_first_avp(name_type, avp_name, &avp_value, 0))==0) { pv_get_null(msg, param, val); goto success; } val->flags = PV_VAL_STR; if ( (idxf==0 || idxf==PV_IDX_INT) && idx==0) { if(avp->flags & AVP_VAL_STR) { val->rs = avp_value.s; } else { val->rs.s = sint2str(avp_value.n, &val->rs.len); val->ri = avp_value.n; val->flags |= PV_VAL_INT|PV_TYPE_INT; } goto success; } if(idxf==PV_IDX_ALL) { p = pv_local_buf; do { if(avp->flags & AVP_VAL_STR) { val->rs = avp_value.s; } else { val->rs.s = sint2str(avp_value.n, &val->rs.len); } if(p-pv_local_buf+val->rs.len+1>PV_LOCAL_BUF_SIZE) { LM_ERR("local buffer length exceeded!\n"); pv_get_null(msg, param, val); goto success; } memcpy(p, val->rs.s, val->rs.len); p += val->rs.len; if(p-pv_local_buf+PV_FIELD_DELIM_LEN+1>PV_LOCAL_BUF_SIZE) { LM_ERR("local buffer length exceeded\n"); pv_get_null(msg, param, val); goto success; } memcpy(p, PV_FIELD_DELIM, PV_FIELD_DELIM_LEN); p += PV_FIELD_DELIM_LEN; } while ((avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0); *p = 0; val->rs.s = pv_local_buf; val->rs.len = p - pv_local_buf; goto success; } /* we have a numeric index */ if(idx<0) { n = 1; avp0 = avp; while ((avp0=search_first_avp(name_type, avp_name, &avp_value0, avp0))!=0) n++; idx = -idx; if(idx>n) { LM_DBG("index out of range\n"); pv_get_null(msg, param, val); goto success; } idx = n - idx; if(idx==0) { if(avp->flags & AVP_VAL_STR) { val->rs = avp_value.s; } else { val->rs.s = sint2str(avp_value.n, &val->rs.len); val->ri = avp_value.n; val->flags |= PV_VAL_INT|PV_TYPE_INT; } goto success; } } n=0; while(n<idx && (avp=search_first_avp(name_type, avp_name, &avp_value, avp))!=0) n++; if(avp!=0) { if(avp->flags & AVP_VAL_STR) { val->rs = avp_value.s; } else { val->rs.s = sint2str(avp_value.n, &val->rs.len); val->ri = avp_value.n; val->flags |= PV_VAL_INT|PV_TYPE_INT; } } goto success; error: res = -1; success: if (old_list) set_avp_list(old_list); return res; }
int pv_set_tm_branch_avp(struct sip_msg *msg, pv_param_t *param, int op, pv_value_t *val) { int avp_name; int_str avp_val; int flags, res=0; unsigned short name_type; int idx, idxf; struct usr_avp **old_list=NULL; struct usr_avp **avp_list=NULL; if (!msg || !val) goto error; avp_list = get_bavp_list(); if (!avp_list) { pv_get_null(msg, param, val); goto success; } if (!param) { LM_ERR("bad parameters\n"); goto error; } if (pv_get_avp_name(msg, param, &avp_name, &name_type)) { LM_ALERT("BUG in getting bavp name\n"); goto error; } /* get the index */ if(pv_get_spec_index(msg, param, &idx, &idxf)!=0) { LM_ERR("invalid index\n"); goto error; } /* setting the avp head */ old_list = set_avp_list(avp_list); if (!old_list) { LM_CRIT("no bavp head list found\n"); goto error; } if(val == NULL) { if(op == COLONEQ_T || idxf == PV_IDX_ALL) destroy_avps(name_type, avp_name, 1); else { if(idx < 0) { LM_ERR("index with negative value\n"); goto error; } destroy_index_avp(name_type, avp_name, idx); } /* restoring head */ goto success; } if(op == COLONEQ_T || idxf == PV_IDX_ALL) destroy_avps(name_type, avp_name, 1); flags = name_type; if(val->flags&PV_TYPE_INT) { avp_val.n = val->ri; } else { avp_val.s = val->rs; flags |= AVP_VAL_STR; } if(idxf == PV_IDX_INT || idxf == PV_IDX_PVAR) { if(replace_avp(flags, avp_name, avp_val, idx)< 0) { LM_ERR("failed to replace bavp\n"); goto error; } } else { if (add_avp(flags, avp_name, avp_val)<0) { LM_ERR("error - cannot add bavp\n"); goto error; } } goto success; error: res = -1; success: if (old_list) set_avp_list(old_list); return res; }
inline static int w_t_new_request(struct sip_msg* msg, char *p_method, char *p_ruri, char *p_from, char *p_to, char *p_body, char *p_ctx) { #define CONTENT_TYPE_HDR "Content-Type: " #define CONTENT_TYPE_HDR_LEN (sizeof(CONTENT_TYPE_HDR)-1) static dlg_t dlg; struct usr_avp **avp_list; str ruri; str method; str body; str headers; str s; int_str ctx; char *p; memset( &dlg, 0, sizeof(dlg_t)); /* evaluate the parameters */ /* method */ if ( fixup_get_svalue(msg, (gparam_p)p_method, &method)<0 ) { LM_ERR("failed to extract METHOD param\n"); return -1; } LM_DBG("setting METHOD to <%.*s>\n", method.len, method.s); /* ruri - next hop is the same as RURI */ dlg.hooks.next_hop = dlg.hooks.request_uri = &ruri; if ( fixup_get_svalue(msg, (gparam_p)p_ruri, &ruri)<0 ) { LM_ERR("failed to extract RURI param\n"); return -1; } LM_DBG("setting RURI to <%.*s>\n", dlg.hooks.next_hop->len, dlg.hooks.next_hop->s); /* FROM URI + display */ if ( fixup_get_svalue(msg, (gparam_p)p_from, &s)<0 ) { LM_ERR("failed to extract FROM param\n"); return -1; } if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) { /* no display, only FROM URI */ dlg.loc_uri = s; dlg.loc_dname.s = NULL; dlg.loc_dname.len = 0; } else { /* display + URI */ dlg.loc_uri.s = p+1; dlg.loc_uri.len = s.s+s.len - dlg.loc_uri.s; dlg.loc_dname.s = s.s; dlg.loc_dname.len = p - s.s; } LM_DBG("setting FROM to <%.*s> + <%.*s>\n", dlg.loc_dname.len, dlg.loc_dname.s, dlg.loc_uri.len, dlg.loc_uri.s); /* TO URI + display */ if ( fixup_get_svalue(msg, (gparam_p)p_to, &s)<0 ) { LM_ERR("failed to extract TO param\n"); return -1; } if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) { /* no display, only TO URI */ dlg.rem_uri = s; dlg.rem_dname.s = NULL; dlg.rem_dname.len = 0; } else { /* display + URI */ dlg.rem_uri.s = p+1; dlg.rem_uri.len = s.s+s.len - dlg.rem_uri.s; dlg.rem_dname.s = s.s; dlg.rem_dname.len = p - s.s; } LM_DBG("setting TO to <%.*s> + <%.*s>\n", dlg.rem_dname.len, dlg.rem_dname.s, dlg.rem_uri.len, dlg.rem_uri.s); /* BODY and Content-Type */ if (p_body!=NULL) { if ( fixup_get_svalue(msg, (gparam_p)p_body, &body)<0 ) { LM_ERR("failed to extract BODY param\n"); return -1; } if ( (p=q_memchr(body.s, ' ', body.len))==NULL ) { LM_ERR("Content Type not found in the beginning of body <%.*s>\n", body.len, body.s); return -1; } /* build the Content-type header */ headers.len = CONTENT_TYPE_HDR_LEN + (p-body.s) + CRLF_LEN; if ( (headers.s=(char*)pkg_malloc(headers.len))==NULL ) { LM_ERR("failed to get pkg mem (needed %d)\n",headers.len); return -1; } memcpy( headers.s, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN); memcpy( headers.s+CONTENT_TYPE_HDR_LEN, body.s, p-body.s); memcpy( headers.s+CONTENT_TYPE_HDR_LEN+(p-body.s), CRLF, CRLF_LEN); /* set the body */ body.len = body.s + body.len - (p+1); body.s = p + 1; LM_DBG("setting BODY to <%.*s> <%.*s>\n", headers.len, headers.s, body.len, body.s ); } else { body.s = NULL; body.len = 0; headers.s = NULL; headers.len = 0; } /* context value */ if (p_ctx!=NULL) { if ( fixup_get_svalue(msg, (gparam_p)p_ctx, &ctx.s)<0 ) { LM_ERR("failed to extract BODY param\n"); if (p_body) pkg_free(headers.s); return -1; } LM_DBG("setting CTX AVP to <%.*s>\n", ctx.s.len, ctx.s.s); avp_list = set_avp_list( &dlg.avps ); if (!add_avp( AVP_VAL_STR, uac_ctx_avp_id, ctx)) LM_ERR("failed to add ctx AVP, ignorring...\n"); set_avp_list( avp_list ); } /* add cseq */ dlg.loc_seq.value = DEFAULT_CSEQ; dlg.loc_seq.is_set = 1; /* add callid */ generate_callid(&dlg.id.call_id); /* add FROM tag */ generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id); /* TO tag is empty as this is a initial request */ dlg.id.rem_tag.s = NULL; dlg.id.rem_tag.len = 0; /* do the actual sending now */ if ( t_uac( &method, headers.s?&headers:NULL, body.s?&body:NULL, &dlg, 0, 0, 0) <= 0 ) { LM_ERR("failed to send the request out\n"); if (headers.s) pkg_free(headers.s); if (dlg.avps) destroy_avp_list(&dlg.avps); return -1; } /* success -> do cleanup */ if (headers.s) pkg_free(headers.s); return 1; }
void async_cdp_callback(int is_timeout, void *param, AAAMessage *saa, long elapsed_msecs) { struct cell *t = 0; int rc = -1, experimental_rc = -1; int result = CSCF_RETURN_TRUE; saved_transaction_t* data = 0; struct sip_msg* req; str xml_data = {0, 0}, ccf1 = {0, 0}, ccf2 = {0, 0}, ecf1 = {0, 0}, ecf2 = {0, 0}; ims_subscription* s = 0; rerrno = R_FINE; if (!param) { LM_DBG("No transaction data this must have been called from usrloc cb impu deleted - just log result code and then exit"); cxdx_get_result_code(saa, &rc); cxdx_get_experimental_result_code(saa, &experimental_rc); if (saa) cdpb.AAAFreeMessage(&saa); if (!rc && !experimental_rc) { LM_ERR("bad SAA result code\n"); return; } switch (rc) { case -1: LM_DBG("Received Diameter error\n"); return; case AAA_UNABLE_TO_COMPLY: LM_DBG("Unable to comply\n"); return; case AAA_SUCCESS: LM_DBG("received AAA success\n"); return; default: LM_ERR("Unknown error\n"); return; } } else { LM_DBG("There is transaction data this must have been called from save or assign server unreg"); data = (saved_transaction_t*) param; if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("t_continue: transaction not found and t is now pointing to %p and will be set to NULL\n", t); t = NULL; rerrno = R_SAR_FAILED; goto error_no_send; } 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); get_act_time(); req = get_request_from_tx(t); if (!req) { LM_ERR("Failed to get SIP Request from Transaction\n"); goto error_no_send; } if (is_timeout) { update_stat(stat_sar_timeouts, 1); LM_ERR("Transaction timeout - did not get SAA\n"); rerrno = R_SAR_FAILED; goto error; } if (!saa) { LM_ERR("Error sending message via CDP\n"); rerrno = R_SAR_FAILED; goto error; } update_stat(sar_replies_received, 1); update_stat(sar_replies_response_time, elapsed_msecs); /* check and see that all the required headers are available and can be parsed */ if (parse_message_for_register(req) < 0) { LM_ERR("Unable to parse register message correctly\n"); rerrno = R_SAR_FAILED; goto error; } cxdx_get_result_code(saa, &rc); cxdx_get_experimental_result_code(saa, &experimental_rc); cxdx_get_charging_info(saa, &ccf1, &ccf2, &ecf1, &ecf2); if (!rc && !experimental_rc) { LM_ERR("bad SAA result code\n"); rerrno = R_SAR_FAILED; goto error; } switch (rc) { case -1: LM_DBG("Received Diameter error\n"); rerrno = R_SAR_FAILED; goto error; case AAA_UNABLE_TO_COMPLY: LM_DBG("Unable to comply\n"); rerrno = R_SAR_FAILED; goto error; case AAA_SUCCESS: LM_DBG("received AAA success for SAR - SAA\n"); break; default: LM_ERR("Unknown error\n"); rerrno = R_SAR_FAILED; goto error; } //success //if this is from a save (not a server assign unreg) and expires is zero we don't update usrloc as this is a dereg and usrloc was updated previously if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER && data->expires == 0) { LM_DBG("no need to update usrloc - already done for de-reg\n"); result = CSCF_RETURN_TRUE; goto success; } xml_data = cxdx_get_user_data(saa); /*If there is XML user data we must be able to parse it*/ if (xml_data.s && xml_data.len > 0) { LM_DBG("Parsing user data string from SAA\n"); s = parse_user_data(xml_data); if (!s) { LM_ERR("Unable to parse user data XML string\n"); rerrno = R_SAR_FAILED; goto error; } LM_DBG("Successfully parse user data XML setting ref to 1 (we are referencing it)\n"); s->ref_count = 1; //no need to lock as nobody else will be referencing this piece of memory just yet } else { if (data->require_user_data) { LM_ERR("We require User data for this assignment/register and none was supplied\n"); rerrno = R_SAR_FAILED; result = CSCF_RETURN_FALSE; goto done; } } if (data->sar_assignment_type == AVP_IMS_SAR_REGISTRATION || data->sar_assignment_type == AVP_IMS_SAR_RE_REGISTRATION) { if (s) { if (build_p_associated_uri(s) != 0) { LM_ERR("Unable to build p_associated_uri\n"); rerrno = R_SAR_FAILED; goto error; } } } if (s) { //here we update the contacts and also build the new contact header for the 200 OK reply if (update_contacts(req, data->domain, &data->public_identity, data->sar_assignment_type, &s, &ccf1, &ccf2, &ecf1, &ecf2, &data->contact_header) <= 0) { LM_ERR("Error processing REGISTER\n"); rerrno = R_SAR_FAILED; goto error; } } if (data->contact_header) { LM_DBG("Updated contacts: %.*s\n", data->contact_header->data_len, data->contact_header->buf); } else { LM_DBG("Updated unreg contact\n"); } } success: update_stat(accepted_registrations, 1); done: if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER) reg_send_reply_transactional(req, data->contact_header, t); LM_DBG("DBG:SAR Async CDP callback: ... Done resuming transaction\n"); create_return_code(result); //release our reference on subscription (s) if (s) ul.unref_subscription(s); //free memory if (saa) cdpb.AAAFreeMessage(&saa); if (t) { // del_nonshm_lump_rpl(&req->reply_lump); tmb.unref_cell(t); } //free path vector pkg memory // reset_path_vector(req); tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); return; error: create_return_code(-2); if (data->sar_assignment_type != AVP_IMS_SAR_UNREGISTERED_USER) reg_send_reply_transactional(req, data->contact_header, t); error_no_send: //if we don't have the transaction then we can't send a transaction response update_stat(rejected_registrations, 1); //free memory if (saa) cdpb.AAAFreeMessage(&saa); if (t) { // del_nonshm_lump_rpl(&req->reply_lump); tmb.unref_cell(t); } tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); return; }
void run_reqin_callbacks( struct cell *trans, struct sip_msg *req, int code ) { static struct tmcb_params params = {0,0,0,0}; struct tm_callback *cbp; avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to; params.req = req; params.code = code; if (req_in_tmcb_hl->first==0) return; backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from ); backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to ); backup_from = set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, &trans->user_avps_from ); backup_to = set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, &trans->user_avps_to ); backup_dom_from = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, &trans->domain_avps_from); backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, &trans->domain_avps_to); for (cbp=req_in_tmcb_hl->first; cbp; cbp=cbp->next) { DBG("DBG: trans=%p, callback type %d, id %d entered\n", trans, cbp->types, cbp->id ); params.param = &(cbp->param); cbp->callback( trans, cbp->types, ¶ms ); } set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, backup_uri_to ); set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, backup_uri_from ); set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, backup_dom_to ); set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, backup_dom_from ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, backup_to ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, backup_from ); }
void async_cdp_callback(int is_timeout, void *param, AAAMessage *maa, long elapsed_msecs) { int i, j; int rc = -1, experimental_rc = -1; saved_transaction_t* data = (saved_transaction_t*) param; struct cell *t = 0; int result = CSCF_RETURN_TRUE; int sip_number_auth_items; struct auth_data_item_list *adi_list = 0; AAA_AVP *auth_data; auth_data = 0; int item_number; str authenticate = {0, 0}, authorization2 = {0, 0}, ck = {0, 0}, ik = {0, 0}, ip = {0, 0}, ha1 = {0, 0}; str line_identifier = {0, 0}; str response_auth = {0, 0}, digest_realm = {0, 0}; auth_vector *av = 0, **avlist = 0; HASHHEX ha1_hex; HASHHEX result_hex; str etsi_nonce = {0, 0}; str private_identity, public_identity; str algorithm; if (is_timeout) { update_stat(stat_mar_timeouts, 1); LM_ERR("Transaction timeout - did not get MAA\n"); result = CSCF_RETURN_ERROR; goto error; } if (!maa) { LM_ERR("Error sending message via CDP\n"); result = CSCF_RETURN_ERROR; goto error; } update_stat(mar_replies_received, 1); update_stat(mar_replies_response_time, elapsed_msecs); if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) { LM_ERR("t_continue: transaction not found\n"); result = CSCF_RETURN_ERROR; goto error; } /* get the private_identity */ private_identity = get_private_identity(t->uas.request, data->realm, data->is_proxy_auth); if (!private_identity.len) { LM_ERR("No private identity specified (Authorization: username)\n"); stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PRIVATE); result = CSCF_RETURN_FALSE; goto error; } /* get the public_identity */ public_identity = get_public_identity(t->uas.request); if (!public_identity.len) { LM_ERR("No public identity specified (To:)\n"); stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_PUBLIC); result = CSCF_RETURN_FALSE; goto error; } //get each individual element from the MAA cxdx_get_result_code(maa, &rc); cxdx_get_experimental_result_code(maa, &experimental_rc); cxdx_get_sip_number_auth_items(maa, &sip_number_auth_items); //now assign the auth_data_item elements //there can be many of these in the MAA struct auth_data_item *adi; int adi_len; char *p; while ((cxdx_get_auth_data_item_answer(maa, &auth_data, &item_number, &algorithm, &authenticate, &authorization2, &ck, &ik, &ip, &ha1, &response_auth, &digest_realm, &line_identifier))) { //create an auth_data_item for each entry in the MAA adi_len = sizeof (struct auth_data_item) +authenticate.len + authorization2.len + ck.len + ik.len + ip.len + ha1.len + line_identifier.len + response_auth.len + digest_realm.len + algorithm.len; adi = (struct auth_data_item*) shm_malloc(adi_len); if (!adi) { LM_CRIT("Out of memory!\n"); result = CSCF_RETURN_ERROR; goto done; } memset(adi, 0, adi_len); //put all elements in the auth_data_item entry p = (char*) (adi + 1); adi->authenticate.s = p; adi->authenticate.len = authenticate.len; memcpy(p, authenticate.s, authenticate.len); p += authenticate.len; adi->authorization.s = p; adi->authorization.len = authorization2.len; memcpy(p, authorization2.s, authorization2.len); p += authorization2.len; adi->auth_scheme.s = p; adi->auth_scheme.len = algorithm.len; memcpy(p, algorithm.s, algorithm.len); p += algorithm.len; adi->ck.s = p; adi->ck.len = ck.len; memcpy(p, ck.s, ck.len); p += ck.len; adi->ik.s = p; adi->ik.len = ik.len; memcpy(p, ik.s, ik.len); p += ik.len; adi->ip.s = p; adi->ip.len = ip.len; memcpy(p, ip.s, ip.len); p += ip.len; adi->ha1.s = p; adi->ha1.len = ha1.len; memcpy(p, ha1.s, ha1.len); p += ha1.len; adi->line_identifier.s = p; adi->line_identifier.len = line_identifier.len; memcpy(p, line_identifier.s, line_identifier.len); p += line_identifier.len; adi->response_auth.s = p; adi->response_auth.len = response_auth.len; memcpy(p, response_auth.s, response_auth.len); p += response_auth.len; adi->digest_realm.s = p; adi->digest_realm.len = digest_realm.len; memcpy(p, digest_realm.s, digest_realm.len); p += digest_realm.len; if (p != (((char*) adi) + adi_len)) { LM_CRIT("buffer overflow\n"); shm_free(adi); adi = 0; result = CSCF_RETURN_ERROR; goto done; } auth_data->code = -auth_data->code; adi->item_number = item_number; int len = sizeof (struct auth_data_item_list); adi_list = (struct auth_data_item_list*) shm_malloc(len); memset(adi_list, 0, len); if (adi_list->first == 0) { adi_list->first = adi_list->last = adi; } else { adi_list->last->next = adi; adi->previous = adi_list->last; adi_list->last = adi; } } if (!(rc) && !(experimental_rc)) { stateful_request_reply_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP); result = CSCF_RETURN_FALSE; goto done; } switch (rc) { case -1: switch (experimental_rc) { case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_USER_UNKNOWN); result = CSCF_RETURN_FALSE; break; case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_IDENTITIES_DONT_MATCH); result = CSCF_RETURN_FALSE; break; case RC_IMS_DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_AUTH_SCHEME_UNSOPPORTED); result = CSCF_RETURN_FALSE; break; default: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC); result = CSCF_RETURN_FALSE; } break; case AAA_UNABLE_TO_COMPLY: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNABLE_TO_COMPLY); result = CSCF_RETURN_FALSE; break; case AAA_SUCCESS: goto success; break; default: stateful_request_reply_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC); result = CSCF_RETURN_FALSE; } goto done; success: if (!sip_number_auth_items) { stateful_request_reply_async(t, t->uas.request, 403, MSG_403_NO_AUTH_DATA); result = CSCF_RETURN_FALSE; goto done; } avlist = shm_malloc(sizeof (auth_vector *) * sip_number_auth_items); if (!avlist) { stateful_request_reply_async(t, t->uas.request, 403, MSG_480_HSS_ERROR); result = CSCF_RETURN_FALSE; goto done; } sip_number_auth_items = 0; struct auth_data_item *tmp; tmp = adi_list->first; while (tmp) { if (tmp->ip.len) av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s, tmp->ip, empty_s, empty_s); else if (tmp->line_identifier.len) av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s, line_identifier, empty_s, empty_s); else if (tmp->ha1.len) { if (tmp->response_auth.len) //HSS check { memset(ha1_hex, 0, HASHHEXLEN + 1); memcpy(ha1_hex, tmp->ha1.s, tmp->ha1.len > HASHHEXLEN ? 32 : tmp->ha1.len); etsi_nonce.len = tmp->authenticate.len / 2; etsi_nonce.s = pkg_malloc(etsi_nonce.len); if (!etsi_nonce.s) { LM_ERR("error allocating %d bytes\n", etsi_nonce.len); goto done; } etsi_nonce.len = base16_to_bin(tmp->authenticate.s, tmp->authenticate.len, etsi_nonce.s); calc_response(ha1_hex, &etsi_nonce, &empty_s, &empty_s, &empty_s, 0, &(t->uas.request->first_line.u.request.method), &scscf_name_str, 0, result_hex); pkg_free(etsi_nonce.s); if (!tmp->response_auth.len == 32 || strncasecmp(tmp->response_auth.s, result_hex, 32)) { LM_ERR("The HSS' Response-Auth is different from what we compute locally!\n" " BUT! If you sent an MAR with auth scheme unknown (HSS-Selected Authentication), this is normal.\n" "HA1=\t|%s|\nNonce=\t|%.*s|\nMethod=\t|%.*s|\nuri=\t|%.*s|\nxresHSS=\t|%.*s|\nxresSCSCF=\t|%s|\n", ha1_hex, tmp->authenticate.len, tmp->authenticate.s, t->uas.request->first_line.u.request.method.len, t->uas.request->first_line.u.request.method.s, scscf_name_str.len, scscf_name_str.s, tmp->response_auth.len, tmp->response_auth.s, result_hex); //stateful_register_reply(msg,514,MSG_514_HSS_AUTH_FAILURE); //goto done; } } av = new_auth_vector(tmp->item_number, tmp->auth_scheme, tmp->authenticate, tmp->ha1, empty_s, empty_s); } else av = new_auth_vector(tmp->item_number, tmp->auth_scheme, tmp->authenticate, tmp->authorization, tmp->ck, tmp->ik); if (sip_number_auth_items == 0) avlist[sip_number_auth_items++] = av; else { i = sip_number_auth_items; while (i > 0 && avlist[i - 1]->item_number > av->item_number) i--; for (j = sip_number_auth_items; j > i; j--) avlist[j] = avlist[j - 1]; avlist[i] = av; sip_number_auth_items++; } //TODO need to confirm that removing this has done no problems //tmp->auth_data->code = -tmp->auth_data->code; LM_DBG("Added new auth-vector.\n"); tmp = tmp->next; } //MAA returns a whole list of av! Which should we use? //right now we take the first and put the rest in the AV queue //then we use the first one and then add it to the queue as sent! for (i = 1; i < sip_number_auth_items; i++) if (!add_auth_vector(private_identity, public_identity, avlist[i])) free_auth_vector(avlist[i]); if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) { stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV); result = CSCF_RETURN_FALSE; goto done; } if (data->is_proxy_auth) stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE); else stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE); done: if (avlist) { start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors //now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT if (!add_auth_vector(private_identity, public_identity, avlist[0])) free_auth_vector(avlist[0]); } //free memory if (maa) cdpb.AAAFreeMessage(&maa); if (avlist) { shm_free(avlist); avlist = 0; } if (adi_list) { struct auth_data_item *tmp1 = adi_list->first; while (tmp1) { struct auth_data_item *tmp2 = tmp1->next; shm_free(tmp1); tmp1 = tmp2; } shm_free(adi_list); adi_list = 0; } LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n"); 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); //make sure we delete any private lumps we created create_return_code(result); if (t) { del_nonshm_lump_rpl(&t->uas.request->reply_lump); tmb.unref_cell(t); } tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); return; error: //don't need to set result code as by default it is ERROR! if (t) { del_nonshm_lump_rpl(&t->uas.request->reply_lump); tmb.unref_cell(t); } tmb.t_continue(data->tindex, data->tlabel, data->act); free_saved_transaction_data(data); }
struct cell* build_cell( struct sip_msg* p_msg ) { struct cell* new_cell; int sip_msg_len; avp_list_t* old; /* allocs a new cell */ new_cell = (struct cell*)shm_malloc( sizeof( struct cell ) ); if ( !new_cell ) { ser_error=E_OUT_OF_MEM; return NULL; } /* filling with 0 */ memset( new_cell, 0, sizeof( struct cell ) ); /* UAS */ new_cell->uas.response.my_T=new_cell; init_rb_timers(&new_cell->uas.response); /* timers */ init_cell_timers(new_cell); old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &new_cell->uri_avps_from ); new_cell->uri_avps_from = *old; *old = 0; old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &new_cell->uri_avps_to ); new_cell->uri_avps_to = *old; *old = 0; old = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &new_cell->user_avps_from ); new_cell->user_avps_from = *old; *old = 0; old = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &new_cell->user_avps_to ); new_cell->user_avps_to = *old; *old = 0; /* We can just store pointer to domain avps in the transaction context, * because they are read-only */ new_cell->domain_avps_from = get_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN); new_cell->domain_avps_to = get_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN); /* enter callback, which may potentially want to parse some stuff, * before the request is shmem-ized */ if ( p_msg && has_reqin_tmcbs() ) run_reqin_callbacks( new_cell, p_msg, p_msg->REQ_METHOD); if (p_msg) { /* clean possible previous added vias/clen header or else they would * get propagated in the failure routes */ free_via_clen_lump(&p_msg->add_rm); new_cell->uas.request = sip_msg_cloner(p_msg,&sip_msg_len); if (!new_cell->uas.request) goto error; new_cell->uas.end_request=((char*)new_cell->uas.request)+sip_msg_len; } /* UAC */ init_branches(new_cell); new_cell->relayed_reply_branch = -1; /* new_cell->T_canceled = T_UNDEFINED; */ init_synonym_id(new_cell); init_cell_lock( new_cell ); return new_cell; error: destroy_avp_list(&new_cell->user_avps_from); destroy_avp_list(&new_cell->user_avps_to); destroy_avp_list(&new_cell->uri_avps_from); destroy_avp_list(&new_cell->uri_avps_to); shm_free(new_cell); /* unlink transaction AVP list and link back the global AVP list (bogdan)*/ reset_avps(); return NULL; }
static inline int pre_print_uac_request( struct cell *t, int branch, struct sip_msg *request, struct sip_msg_body **body_clone) { int backup_route_type; struct usr_avp **backup_list; char *p; /* ... we calculate branch ... */ if (!t_calc_branch(t, branch, request->add_to_branch_s, &request->add_to_branch_len )) { LM_ERR("branch computation failed\n"); goto error; } /* from now on, flag all new lumps with LUMPFLAG_BRANCH flag in order to * be able to remove them later --bogdan */ set_init_lump_flags(LUMPFLAG_BRANCH); /* copy path vector into branch */ if (request->path_vec.len) { t->uac[branch].path_vec.s = shm_realloc(t->uac[branch].path_vec.s, request->path_vec.len+1); if (t->uac[branch].path_vec.s==NULL) { LM_ERR("shm_realloc failed\n"); goto error; } t->uac[branch].path_vec.len = request->path_vec.len; memcpy( t->uac[branch].path_vec.s, request->path_vec.s, request->path_vec.len+1); } /* do the same for the advertised port & address */ if (request->set_global_address.len) { t->uac[branch].adv_address.s = shm_realloc(t->uac[branch].adv_address.s, request->set_global_address.len+1); if (t->uac[branch].adv_address.s==NULL) { LM_ERR("shm_realloc failed for storing the advertised address " "(len=%d)\n",request->set_global_address.len); goto error; } t->uac[branch].adv_address.len = request->set_global_address.len; memcpy( t->uac[branch].adv_address.s, request->set_global_address.s, request->set_global_address.len+1); } if (request->set_global_port.len) { t->uac[branch].adv_port.s = shm_realloc(t->uac[branch].adv_port.s, request->set_global_port.len+1); if (t->uac[branch].adv_port.s==NULL) { LM_ERR("shm_realloc failed for storing the advertised port " "(len=%d)\n",request->set_global_port.len); goto error; } t->uac[branch].adv_port.len = request->set_global_port.len; memcpy( t->uac[branch].adv_port.s, request->set_global_port.s, request->set_global_port.len+1); } /********** run route & callback ************/ /* run branch route, if any; run it before RURI's DNS lookup * to allow to be changed --bogdan */ if (t->on_branch) { /* need to pkg_malloc the dst_uri */ if ( request->dst_uri.s && request->dst_uri.len>0 ) { if ( (p=pkg_malloc(request->dst_uri.len))==0 ) { LM_ERR("no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->dst_uri.s, request->dst_uri.len); request->dst_uri.s = p; } /* need to pkg_malloc the new_uri */ if ( (p=pkg_malloc(request->new_uri.len))==0 ) { LM_ERR("no more pkg mem\n"); ser_error=E_OUT_OF_MEM; goto error; } memcpy( p, request->new_uri.s, request->new_uri.len); request->new_uri.s = p; request->parsed_uri_ok = 0; /* make a clone of the original body, to restore it later */ if (clone_sip_msg_body( request, NULL, body_clone, 0)!=0) { LM_ERR("faile to clone the body, branch route changes will be" " preserved\n"); } /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* run branch route */ swap_route_type( backup_route_type, BRANCH_ROUTE); _tm_branch_index = branch; if(run_top_route(sroutes->branch[t->on_branch].a,request)&ACT_FL_DROP){ LM_DBG("dropping branch <%.*s>\n", request->new_uri.len, request->new_uri.s); _tm_branch_index = 0; /* restore the route type */ set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); goto error; } _tm_branch_index = 0; /* restore the route type */ set_route_type( backup_route_type ); /* restore original avp list */ set_avp_list( backup_list ); } /* run the specific callbacks for this transaction */ run_trans_callbacks( TMCB_REQUEST_FWDED, t, request, 0, -request->REQ_METHOD); /* copy dst_uri into branch (after branch route possible updated it) */ if (request->dst_uri.len) { t->uac[branch].duri.s = shm_realloc(t->uac[branch].duri.s, request->dst_uri.len); if (t->uac[branch].duri.s==NULL) { LM_ERR("shm_realloc failed\n"); goto error; } t->uac[branch].duri.len = request->dst_uri.len; memcpy( t->uac[branch].duri.s,request->dst_uri.s,request->dst_uri.len); } return 0; error: return -1; }
void handle_ebr_ipc(int sender, void *payload) { ebr_ipc_job *job = (ebr_ipc_job*)payload; struct usr_avp **old_avps; struct sip_msg req; LM_DBG("EBR notification received via IPC for event %.*s\n", job->ev->event_name.len, job->ev->event_name.s); if (job->flags&EBR_SUBS_TYPE_NOTY) { /* this is a job for notifiying on an event */ /* push our list of AVPs */ old_avps = set_avp_list( &job->avps ); /* prepare a fake/dummy request */ memset( &req, 0, sizeof(struct sip_msg)); req.first_line.type = SIP_REQUEST; req.first_line.u.request.method.s= "DUMMY"; req.first_line.u.request.method.len= 5; req.first_line.u.request.uri.s= "sip:[email protected]"; req.first_line.u.request.uri.len= 19; req.rcv.src_ip.af = AF_INET; req.rcv.dst_ip.af = AF_INET; LM_DBG("using transaction reference %X:%X\n", job->tm.hash, job->tm.label); if (ebr_tmb.t_set_remote_t && job->tm.hash!=0 && job->tm.label!=0 ) ebr_tmb.t_set_remote_t( &job->tm ); /* route the notification route */ set_route_type( REQUEST_ROUTE ); run_top_route( rlist[(int)(long)job->data].a, &req); if (ebr_tmb.t_set_remote_t) ebr_tmb.t_set_remote_t( NULL ); /* cleanup over route execution */ set_avp_list( old_avps ); free_sip_msg( &req ); /* destroy everything */ destroy_avp_list( &job->avps ); shm_free(job); } else { /* this is a job for resuming on WAIT */ /* pass the list of AVPs to be pushed into the msg */ ((async_ctx*)job->data)->resume_param = job->avps; /* invoke the global resume ASYNC function */ async_script_resume_f(ASYNC_FD_NONE, job->data /*the async ctx*/ ); shm_free(job); } return; }
/* This function is called whenever a reply for our module is received; * we need to register this function on module initialization; * Returns : 0 - core router stops * 1 - core router relay statelessly */ int reply_received( struct sip_msg *p_msg ) { int msg_status; int last_uac_status; int branch; int reply_status; utime_t timer; /* has the transaction completed now and we need to clean-up? */ branch_bm_t cancel_bitmap; struct ua_client *uac; struct cell *t; struct usr_avp **backup_list; unsigned int has_reply_route; set_t(T_UNDEFINED); /* make sure we know the associated transaction ... */ if (t_check(p_msg, &branch ) == -1) goto not_found; /*... if there is none, tell the core router to fwd statelessly */ t = get_t(); if ((t == 0) || (t == T_UNDEFINED)) goto not_found; cancel_bitmap=0; msg_status=p_msg->REPLY_STATUS; uac=&t->uac[branch]; LM_DBG("org. status uas=%d, uac[%d]=%d local=%d is_invite=%d)\n", t->uas.status, branch, uac->last_received, is_local(t), is_invite(t)); last_uac_status=uac->last_received; if_update_stat( tm_enable_stats, tm_rcv_rpls , 1); /* it's a cancel which is not e2e ? */ if ( get_cseq(p_msg)->method_id==METHOD_CANCEL && is_invite(t) ) { /* ... then just stop timers */ reset_timer( &uac->local_cancel.retr_timer); if ( msg_status >= 200 ) { reset_timer( &uac->local_cancel.fr_timer); } LM_DBG("reply to local CANCEL processed\n"); goto done; } /* *** stop timers *** */ /* stop retransmission */ reset_timer(&uac->request.retr_timer); /* stop final response timer only if I got a final response */ if ( msg_status >= 200 ) { reset_timer( &uac->request.fr_timer); } /* acknowledge negative INVITE replies (do it before detailed * on_reply processing, which may take very long, like if it * is attempted to establish a TCP connection to a fail-over dst */ if (is_invite(t) && ((msg_status >= 300) || (is_local(t) && !no_autoack(t) && msg_status >= 200) )) { if (send_ack(p_msg, t, branch)!=0) LM_ERR("failed to send ACK (local=%s)\n", is_local(t)?"yes":"no"); } _tm_branch_index = branch; /* processing of on_reply block */ has_reply_route = (t->on_reply) || (t->uac[branch].on_reply); if (has_reply_route) { if (onreply_avp_mode) { /* lock the reply*/ LOCK_REPLIES( t ); /* set the as avp_list the one from transaction */ backup_list = set_avp_list(&t->user_avps); } else { backup_list = 0; } /* transfer transaction flag to branch context */ p_msg->flags = t->uas.request->flags; setb0flags(t->uac[branch].br_flags); /* run block - first per branch and then global one */ if ( t->uac[branch].on_reply && (run_top_route(onreply_rlist[t->uac[branch].on_reply].a,p_msg) &ACT_FL_DROP) && (msg_status<200) ) { if (onreply_avp_mode) { UNLOCK_REPLIES( t ); set_avp_list( backup_list ); } LM_DBG("dropping provisional reply %d\n", msg_status); goto done; } if ( t->on_reply && (run_top_route(onreply_rlist[t->on_reply].a,p_msg) &ACT_FL_DROP) && (msg_status<200) ) { if (onreply_avp_mode) { UNLOCK_REPLIES( t ); set_avp_list( backup_list ); } LM_DBG("dropping provisional reply %d\n", msg_status); goto done; } /* transfer current message context back to t */ t->uac[branch].br_flags = getb0flags(); t->uas.request->flags = p_msg->flags; if (onreply_avp_mode) /* restore original avp list */ set_avp_list( backup_list ); } if (!onreply_avp_mode || !has_reply_route) /* lock the reply*/ LOCK_REPLIES( t ); /* mark that the UAC received replies */ uac->flags |= T_UAC_HAS_RECV_REPLY; /* we fire a cancel on spot if (a) branch is marked "to be canceled" or (b) * the whole transaction was canceled (received cancel) and no cancel sent * yet on this branch; and of course, only if a provisional reply :) */ if (t->uac[branch].flags&T_UAC_TO_CANCEL_FLAG || ((t->flags&T_WAS_CANCELLED_FLAG) && !t->uac[branch].local_cancel.buffer.s)) { if ( msg_status < 200 ) /* reply for an UAC with a pending cancel -> do cancel now */ cancel_branch(t, branch); /* reset flag */ t->uac[branch].flags &= ~(T_UAC_TO_CANCEL_FLAG); } if (is_local(t)) { reply_status = local_reply(t,p_msg, branch,msg_status,&cancel_bitmap); if (reply_status == RPS_COMPLETED) { cleanup_uac_timers(t); if (is_invite(t)) cancel_uacs(t, cancel_bitmap); /* There is no need to call set_final_timer because we know * that the transaction is local */ put_on_wait(t); } } else { reply_status = relay_reply(t,p_msg,branch,msg_status,&cancel_bitmap); /* clean-up the transaction when transaction completed */ if (reply_status == RPS_COMPLETED) { /* no more UAC FR/RETR (if I received a 2xx, there may * be still pending branches ... */ cleanup_uac_timers(t); if (is_invite(t)) cancel_uacs(t, cancel_bitmap); /* FR for negative INVITES, WAIT anything else */ /* set_final_timer(t); */ } } if (reply_status!=RPS_PROVISIONAL) goto done; /* update FR/RETR timers on provisional replies */ if (msg_status < 200 && (restart_fr_on_each_reply || ((last_uac_status<msg_status) && ((msg_status >= 180) || (last_uac_status == 0))) ) ) { /* provisional now */ if (is_invite(t)) { /* invite: change FR to longer FR_INV, do not * attempt to restart retransmission any more */ backup_list = set_avp_list(&t->user_avps); if (!fr_inv_avp2timer(&timer)) { LM_DBG("FR_INV_TIMER = %lld\n", timer); set_timer(&uac->request.fr_timer, FR_INV_TIMER_LIST, &timer); } else { set_timer(& uac->request.fr_timer, FR_INV_TIMER_LIST, 0); } set_avp_list(backup_list); } else { /* non-invite: restart retransmissions (slow now) */ uac->request.retr_list = RT_T2; set_timer(&uac->request.retr_timer, RT_T2, 0); } } /* provisional replies */ done: /* we are done with the transaction, so unref it - the reference * was incremented by t_check() function -bogdan*/ t_unref(p_msg); /* don't try to relay statelessly neither on success * (we forwarded statefully) nor on error; on troubles, * simply do nothing; that will make the other party to * retransmit; hopefuly, we'll then be better off */ _tm_branch_index = 0; return 0; not_found: set_t(T_UNDEFINED); return 1; }
static void run_reqin_callbacks_internal(struct tmcb_head_list* hl, struct cell *trans, struct tmcb_params* params) { struct tm_callback *cbp; avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to; #ifdef WITH_XAVP sr_xavp_t **backup_xavps; #endif if (hl==0 || hl->first==0) return; backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from ); backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to ); backup_from = set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, &trans->user_avps_from ); backup_to = set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, &trans->user_avps_to ); backup_dom_from = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, &trans->domain_avps_from); backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, &trans->domain_avps_to); #ifdef WITH_XAVP backup_xavps = xavp_set_list(&trans->xavps_list); #endif for (cbp=(struct tm_callback*)hl->first; cbp; cbp=cbp->next) { DBG("DBG: trans=%p, callback type %d, id %d entered\n", trans, cbp->types, cbp->id ); params->param = &(cbp->param); cbp->callback( trans, cbp->types, params ); } set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, backup_uri_to ); set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, backup_uri_from ); set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, backup_dom_to ); set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, backup_dom_from ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, backup_to ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, backup_from ); #ifdef WITH_XAVP xavp_set_list(backup_xavps); #endif }
void async_http_cb(struct http_m_reply *reply, void *param) { async_query_t *aq; cfg_action_t *act; unsigned int tindex; unsigned int tlabel; struct cell *t = NULL; char *p; sip_msg_t *fmsg; if (reply->result != NULL) { LM_DBG("query result = %.*s [%d]\n", reply->result->len, reply->result->s, reply->result->len); } /* clean process-local result variables */ ah_error.s = NULL; ah_error.len = 0; memset(ah_reply, 0, sizeof(struct sip_msg)); /* set process-local result variables */ if (reply->result == NULL) { /* error */ ah_error.s = reply->error; ah_error.len = strlen(ah_error.s); } else { /* success */ /* check for HTTP Via header * - HTTP Via format is different that SIP Via * - workaround: replace with Hia to be ignored by SIP parser */ if((p=strfindcasestrz(reply->result, "\nVia:"))!=NULL) { p++; *p = 'H'; LM_DBG("replaced HTTP Via with Hia [[\n%.*s]]\n", reply->result->len, reply->result->s); } ah_reply->buf = reply->result->s; ah_reply->len = reply->result->len; if (parse_msg(reply->result->s, reply->result->len, ah_reply) != 0) { LM_DBG("failed to parse the http_reply\n"); } else { LM_DBG("successfully parsed http reply %p\n", ah_reply); } } aq = param; strncpy(q_id, aq->id, strlen(aq->id)); act = (cfg_action_t*)aq->param; if (aq->query_params.suspend_transaction) { tindex = aq->tindex; tlabel = aq->tlabel; if (tmb.t_lookup_ident(&t, tindex, tlabel) < 0) { LM_ERR("transaction not found %d:%d\n", tindex, tlabel); LM_DBG("freeing query %p\n", aq); free_async_query(aq); return; } // we bring the list of AVPs of the transaction to the current context 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 (t) tmb.unref_cell(t); LM_DBG("resuming transaction (%d:%d)\n", tindex, tlabel); if(act!=NULL) tmb.t_continue(tindex, tlabel, act); } else { fmsg = faked_msg_next(); if (run_top_route(act, fmsg, 0)<0) LM_ERR("failure inside run_top_route\n"); } free_sip_msg(ah_reply); free_async_query(aq); return; }
/* run reply route functions */ int run_reply_route(struct sip_msg *_rpl, struct cell *_t, int index) { avp_list_t *backup_uri_from, *backup_uri_to; avp_list_t *backup_user_from, *backup_user_to; avp_list_t *backup_domain_from, *backup_domain_to; struct run_act_ctx ra_ctx; if (!_t || (index < 0)) return -1; /* set the avp_list the one from transaction */ backup_uri_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &_t->uri_avps_from ); backup_uri_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &_t->uri_avps_to ); backup_user_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &_t->user_avps_from ); backup_user_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &_t->user_avps_to ); backup_domain_from = set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &_t->domain_avps_from ); backup_domain_to = set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &_t->domain_avps_to ); init_run_actions_ctx(&ra_ctx); if (run_actions(&ra_ctx, onreply_rt.rlist[index], _rpl)<0) LOG(L_ERR, "ERROR: run_reply_route(): on_reply processing failed\n"); /* restore original avp list */ set_avp_list( AVP_TRACK_FROM | AVP_CLASS_URI, backup_uri_from ); set_avp_list( AVP_TRACK_TO | AVP_CLASS_URI, backup_uri_to ); set_avp_list( AVP_TRACK_FROM | AVP_CLASS_USER, backup_user_from ); set_avp_list( AVP_TRACK_TO | AVP_CLASS_USER, backup_user_to ); set_avp_list( AVP_TRACK_FROM | AVP_CLASS_DOMAIN, backup_domain_from ); set_avp_list( AVP_TRACK_TO | AVP_CLASS_DOMAIN, backup_domain_to ); return 0; }
void run_trans_callbacks_internal(struct tmcb_head_list* cb_lst, int type, struct cell *trans, struct tmcb_params *params) { struct tm_callback *cbp; avp_list_t* backup_from, *backup_to, *backup_dom_from, *backup_dom_to, *backup_uri_from, *backup_uri_to; #ifdef WITH_XAVP sr_xavp_t **backup_xavps; #endif backup_uri_from = set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, &trans->uri_avps_from ); backup_uri_to = set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, &trans->uri_avps_to ); backup_from = set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, &trans->user_avps_from ); backup_to = set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, &trans->user_avps_to ); backup_dom_from = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, &trans->domain_avps_from); backup_dom_to = set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, &trans->domain_avps_to); #ifdef WITH_XAVP backup_xavps = xavp_set_list(&trans->xavps_list); #endif cbp=(struct tm_callback*)cb_lst->first; while(cbp){ membar_depends(); /* make sure the cache has the correct cbp contents */ if ( (cbp->types)&type ) { DBG("DBG: trans=%p, callback type %d, id %d entered\n", trans, type, cbp->id ); params->param = &(cbp->param); cbp->callback( trans, type, params ); } cbp=cbp->next; } set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_TO, backup_dom_to ); set_avp_list(AVP_CLASS_DOMAIN | AVP_TRACK_FROM, backup_dom_from ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_TO, backup_to ); set_avp_list(AVP_CLASS_USER | AVP_TRACK_FROM, backup_from ); set_avp_list(AVP_CLASS_URI | AVP_TRACK_TO, backup_uri_to ); set_avp_list(AVP_CLASS_URI | AVP_TRACK_FROM, backup_uri_from ); #ifdef WITH_XAVP xavp_set_list(backup_xavps); #endif }
/* function triggered from reactor in order to continue the processing */ int t_resume_async(int fd, void *param) { static struct sip_msg faked_req; static struct ua_client uac; async_ctx *ctx = (async_ctx *)param; struct cell *backup_t; struct usr_avp **backup_list; struct socket_info* backup_si; struct cell *t= ctx->t; int route; LM_DBG("resuming on fd %d, transaction %p \n",fd, t); if (current_processing_ctx) { LM_CRIT("BUG - a context already set!\n"); abort(); } /* prepare for resume route */ uac.br_flags = getb0flags( t->uas.request ) ; uac.uri = *GET_RURI( t->uas.request ); if (!fake_req( &faked_req /* the fake msg to be built*/, t->uas.request, /* the template msg saved in transaction */ &t->uas, /*the UAS side of the transaction*/ &uac, /* the fake UAC */ 1 /* copy dst_uri too */) ) { LM_ERR("fake_req failed\n"); return 0; } /* enviroment setting */ current_processing_ctx = ctx->msg_ctx; backup_t = get_t(); /* fake transaction */ set_t( t ); reset_kr(); set_kr(ctx->kr); /* make available the avp list from transaction */ backup_list = set_avp_list( &t->user_avps ); /* set default send address to the saved value */ backup_si = bind_address; bind_address = t->uac[0].request.dst.send_sock; async_status = ASYNC_DONE; /* assume default status as done */ /* call the resume function in order to read and handle data */ return_code = ctx->resume_f( fd, &faked_req, ctx->resume_param ); if (async_status==ASYNC_CONTINUE) { /* do not run the resume route */ goto restore; } /* remove from reactor, we are done */ reactor_del_reader( fd, -1, IO_FD_CLOSING); if (async_status == ASYNC_DONE_CLOSE_FD) close(fd); /* run the resume_route (some type as the original one) */ swap_route_type(route, ctx->route_type); run_resume_route( ctx->resume_route, &faked_req); set_route_type(route); /* no need for the context anymore */ shm_free(ctx); restore: /* restore original environment */ set_t(backup_t); /* restore original avp list */ set_avp_list( backup_list ); bind_address = backup_si; free_faked_req( &faked_req, t); current_processing_ctx = NULL; return 0; }