/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; int expires=0; str totag; time_t t_time; str ses_exp = {0,0}; str refresher = {0,0}; enum s_dialog_direction dir = get_dialog_direction(str1); // if (!find_dialog_aor(msg,str1,&aor)){ // req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_s_dialog_dir(call_id,dir); // if (!d && msg->first_line.type==SIP_REPLY){ // /* Try to get the dialog from the request */ // if (!req) req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // d = get_s_dialog_dir(call_id,aor); // } if (!d){ LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE) { d->uac_supp_timer = supports_extension(msg, &str_ext_timer); ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time) { d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; } else { d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; if (refresher.len) STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER"); } } else if (d->method == DLG_METHOD_SUBSCRIBE && msg->first_line.u.request.method.len == 6 && strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0) { // Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2 expires = cscf_get_subscription_state(msg); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; } else { expires = cscf_get_expires_hdr(msg,0); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; } }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200){ d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; }else if (response>=200 && response<300){ d->state = DLG_STATE_CONFIRMED; update_dialog_on_reply(msg, d); /*I save the dialogs only here because * i only want to release confirmed dialogs*/ cscf_get_to_tag(msg,&totag); if (d->dialog_s){ tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else{ LOG(L_ERR,"ERR:S_update_dialog(): dialog_s for dialog was NULL!\n"); } }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); struct cell * t = tmb.t_gett(); if(t->nr_of_outgoings < 2) return S_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: d->expires = d_act_time()+scscf_dialogs_expiration_time; d->lr_session_expires = 0; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } update_dialog_on_reply(msg, d); break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_dros_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = d_act_time() + expires; } } else if (req && req->first_line.u.request.method.len==9 && strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0){ expires = cscf_get_expires_hdr(msg,0); if (expires >= 0) d->expires = d_act_time()+expires; else d->expires = d_act_time()+scscf_dialogs_expiration_time; } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; out_of_memory: if (d) d_unlock(d->hash); return CSCF_RETURN_ERROR; }
/* Wrapper to send AAR from config file - this only allows for AAR for calls - not register, which uses r_rx_aar_register * return: 1 - success, <=0 failure. 2 - message not a AAR generating message (ie proceed without PCC if you wish) */ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) { int ret = CSCF_RETURN_ERROR; struct cell *t; AAASession* auth_session; rx_authsessiondata_t* rx_authdata_p = 0; str *rx_session_id; str callid = {0, 0}; str ftag = {0, 0}; str ttag = {0, 0}; str route_name; cfg_action_t* cfg_action = 0; saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call char* direction = str1; 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; } LM_DBG("Rx AAR called\n"); //create the default return code AVP create_return_code(ret); //We don't ever do AAR on request for calling scenario... if (msg->first_line.type != SIP_REPLY) { LM_DBG("Can't do AAR for call session in request\n"); return CSCF_RETURN_ERROR; } //is it appropriate to send AAR at this stage? t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_WARN("Cannot get transaction for AAR based on SIP Request\n"); //goto aarna; return CSCF_RETURN_ERROR; } //we dont apply QoS if its not a reply to an INVITE! or UPDATE or PRACK! if ((t->method.len == 5 && memcmp(t->method.s, "PRACK", 5) == 0) || (t->method.len == 6 && (memcmp(t->method.s, "INVITE", 6) == 0 || memcmp(t->method.s, "UPDATE", 6) == 0))) { if (cscf_get_content_length(msg) == 0 || cscf_get_content_length(t->uas.request) == 0) { LM_DBG("No SDP offer answer -> therefore we can not do Rx AAR"); //goto aarna; //AAR na if we dont have offer/answer pair return CSCF_RETURN_ERROR; } } else { LM_DBG("Message is not response to INVITE, PRACK or UPDATE -> therefore we do not Rx AAR"); return CSCF_RETURN_ERROR; } /* get callid, from and to tags to be able to identify dialog */ callid = cscf_get_call_id(msg, 0); if (callid.len <= 0 || !callid.s) { LM_ERR("unable to get callid\n"); return CSCF_RETURN_ERROR; } if (!cscf_get_from_tag(msg, &ftag)) { LM_ERR("Unable to get ftag\n"); return CSCF_RETURN_ERROR; } if (!cscf_get_to_tag(msg, &ttag)) { LM_ERR("Unable to get ttag\n"); return CSCF_RETURN_ERROR; } //check to see that this is not a result of a retransmission in reply route only if (msg->cseq == NULL && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || (msg->cseq == NULL))) { LM_ERR("No Cseq header found - aborting\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; //OTHER parms need after async response set here //store call id saved_t_data->callid.s = (char*) shm_malloc(callid.len + 1); if (!saved_t_data->callid.s) { LM_ERR("no more memory trying to save transaction state : callid\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->callid.s, 0, callid.len + 1); memcpy(saved_t_data->callid.s, callid.s, callid.len); saved_t_data->callid.len = callid.len; //store ttag saved_t_data->ttag.s = (char*) shm_malloc(ttag.len + 1); if (!saved_t_data->ttag.s) { LM_ERR("no more memory trying to save transaction state : ttag\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->ttag.s, 0, ttag.len + 1); memcpy(saved_t_data->ttag.s, ttag.s, ttag.len); saved_t_data->ttag.len = ttag.len; //store ftag saved_t_data->ftag.s = (char*) shm_malloc(ftag.len + 1); if (!saved_t_data->ftag.s) { LM_ERR("no more memory trying to save transaction state : ftag\n"); shm_free(saved_t_data); return CSCF_RETURN_ERROR; } memset(saved_t_data->ftag.s, 0, ftag.len + 1); memcpy(saved_t_data->ftag.s, ftag.s, ftag.len); saved_t_data->ftag.len = ftag.len; //store branch int branch; if (tmb.t_check( msg , &branch )==-1){ LOG(L_ERR, "ERROR: t_suspend: failed find UAC branch\n"); return CSCF_RETURN_ERROR; } //Check that we dont already have an auth session for this specific dialog //if not we create a new one and attach it to the dialog (via session ID). enum dialog_direction dlg_direction = get_dialog_direction(direction); if (dlg_direction == DLG_MOBILE_ORIGINATING) { rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag, &orig_session_key); } else { rx_session_id = dlgb.get_dlg_var(&callid, &ftag, &ttag, &term_session_key); } if (!rx_session_id || rx_session_id->len <= 0 || !rx_session_id->s) { LM_DBG("New AAR session for this dialog in mode %s\n", direction); //create new diameter auth session int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &rx_authdata_p); if (!ret) { LM_DBG("Unable to create new media session data parcel\n"); goto error; } auth_session = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_authdata_p); //returns with a lock if (!auth_session) { LM_ERR("Rx: unable to create new Rx Media Session\n"); if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash); if (rx_authdata_p) { shm_free(rx_authdata_p); rx_authdata_p = 0; } goto error; } //attach new cdp auth session to dlg for this direction if (dlg_direction == DLG_MOBILE_ORIGINATING) { dlgb.set_dlg_var(&callid, &ftag, &ttag, &orig_session_key, &auth_session->id); } else { dlgb.set_dlg_var(&callid, &ftag, &ttag, &term_session_key, &auth_session->id); } LM_DBG("Attached CDP auth session [%.*s] for Rx to dialog in %s mode\n", auth_session->id.len, auth_session->id.s, direction); } else { LM_DBG("Update AAR session for this dialog in mode %s\n", direction); 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 create_return_code(CSCF_RETURN_TRUE); return CSCF_RETURN_TRUE; } 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("Sending Rx AAR"); ret = rx_send_aar(t->uas.request, msg, auth_session, direction, saved_t_data); if (!ret) { LM_ERR("Failed to send AAR\n"); tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); goto error; } else { 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 } error: LM_ERR("Error trying to send AAR (calling)\n"); 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; }
/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int S_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; s_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; int expires=0; str totag; enum s_dialog_direction dir = get_dialog_direction(str1); // if (!find_dialog_aor(msg,str1,&aor)){ // req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_INFO,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_s_dialog_dir(call_id,dir); // if (!d && msg->first_line.type==SIP_REPLY){ // /* Try to get the dialog from the request */ // if (!req) req = cscf_get_request_from_reply(msg); // if (!find_dialog_aor(req,str1,&aor)){ // LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1); // return CSCF_RETURN_BREAK; // } // d = get_s_dialog_dir(call_id,aor); // } if (!d){ LOG(L_INFO,"INFO:"M_NAME":S_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; d->expires = d_act_time()+scscf_dialogs_expiration_time; }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200){ d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; }else if (response>=200 && response<300){ d->state = DLG_STATE_CONFIRMED; d->expires = d_act_time()+scscf_dialogs_expiration_time; /*I save the dialogs only here because * i only want to release confirmed dialogs*/ cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: d->expires = d_act_time()+scscf_dialogs_expiration_time; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); } d->expires = d_act_time()+scscf_dialogs_expiration_time; break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_dros_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return S_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = expires; } } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); // print_s_dialogs(L_INFO); return CSCF_RETURN_TRUE; }
/** * Updates a dialog. * If the initial request was: * - INVITE - refreshes the expiration or looks for the BYE and destroys the dialog * if found * - SUBSCRIBE - looks for the Subscription-state in NOTIFY, refreshes the expiration * and if terminated destroys the dialog * - When adding more dialogs, add the refreshal methods here or they will expire and will * be destroyed. Also add the termination to reduce the memory consumption and improve the * performance. * @param msg - the request/response * @param str1 - direction - "orig" or "term" * @param str2 - not used * @returns #CSCF_RETURN_TRUE if ok, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_BREAK on error */ int P_update_dialog(struct sip_msg* msg, char* str1, char* str2) { str call_id; p_dialog *d; int response; int cseq; struct hdr_field *h=0; struct sip_msg *req=0; str host; int port,transport; int expires; str totag; time_t t_time=0; str ses_exp = {0,0}; str refresher = {0,0}; enum p_dialog_direction dir; dir = get_dialog_direction(str1); if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg); else req = msg; if (!find_dialog_contact(req,dir,&host,&port,&transport)){ LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1); return CSCF_RETURN_BREAK; } call_id = cscf_get_call_id(msg,0); if (!call_id.len) return CSCF_RETURN_FALSE; LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s); d = get_p_dialog(call_id,host,port,transport,&dir); if (!d) d = get_p_dialog(call_id,host,port,transport,0); if (!d){ if (msg->first_line.type==SIP_REQUEST && msg->first_line.u.request.method.len == 3 && strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){ /* to skip the ACK after a 4xx when the dialog was dropped already*/ return CSCF_RETURN_TRUE; }else{ LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n"); return CSCF_RETURN_FALSE; } } if (msg->first_line.type==SIP_REQUEST){ /* Request */ LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1, msg->first_line.u.request.method.len,msg->first_line.u.request.method.s); cseq = cscf_get_cseq(msg,&h); if (cseq>d->last_cseq) d->last_cseq = cseq; if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE) { d->uac_supp_timer = supports_extension(msg, &str_ext_timer); ses_exp = cscf_get_session_expires_body(msg, &h); t_time = cscf_get_session_expires(ses_exp, &refresher); if (!t_time){ d->expires = d_act_time()+pcscf_dialogs_expiration_time; d->lr_session_expires = 0; } else { d->expires = d_act_time() + t_time; d->lr_session_expires = t_time; if (refresher.len) STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER"); } } else if (d->method == DLG_METHOD_SUBSCRIBE && msg->first_line.u.request.method.len == 6 && strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0) { // Subscription-State header is mandatory for NOTIFY. See RFC 3265, Section 7.2 expires = cscf_get_subscription_state(msg); if (expires >= 0) { d->expires = d_act_time()+expires; } else { d->expires = d_act_time()+pcscf_dialogs_expiration_time; } } else { expires = cscf_get_expires_hdr(msg); if (expires >= 0) { LOG(L_INFO,"DBG:"M_NAME":P_update_dialog(%.*s): Update expiration time to %d via Expire header 2\n",call_id.len,call_id.s,expires); d->expires = d_act_time()+expires; } else { LOG(L_INFO,"INF:"M_NAME": update_dialog(%.*s): d->expires+=pcscf_dialogs_expiration_time 4\n",call_id.len,call_id.s); d->expires = d_act_time()+pcscf_dialogs_expiration_time; } d->lr_session_expires = 0; } }else{ /* Reply */ response = msg->first_line.u.reply.statuscode; LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): <%d> \n",str1,response); cseq = cscf_get_cseq(msg,&h); if (cseq==0 || h==0) return CSCF_RETURN_FALSE; if (d->first_cseq==cseq && d->method_str.len == ((struct cseq_body *)h->parsed)->method.len && strncasecmp(d->method_str.s,((struct cseq_body *)h->parsed)->method.s,d->method_str.len)==0 && d->state < DLG_STATE_CONFIRMED){ /* reply to initial request */ if (response<200 && response>100){ save_dialog_routes(msg,str1,d); d->state = DLG_STATE_EARLY; d->expires = d_act_time()+300; cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>=200 && response<300){ save_dialog_routes(msg,str1,d); d->state = DLG_STATE_CONFIRMED; update_dialog_on_reply(msg, d); cscf_get_to_tag(msg,&totag); tmb.update_dlg_uas(d->dialog_s,response,&totag); tmb.dlg_response_uac(d->dialog_c,msg,IS_NOT_TARGET_REFRESH); }else if (response>300){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); } }else{ /* reply to subsequent request */ if (!req) req = cscf_get_request_from_reply(msg); /* destroy dialogs on specific methods */ switch (d->method){ case DLG_METHOD_OTHER: expires = cscf_get_expires_hdr(msg); if (expires >= 0) { d->expires = d_act_time()+expires; } else { d->expires = d_act_time()+pcscf_dialogs_expiration_time; } d->lr_session_expires = 0; break; case DLG_METHOD_INVITE: if (req && req->first_line.u.request.method.len==3 && strncasecmp(req->first_line.u.request.method.s,"BYE",3)==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); } update_dialog_on_reply(msg, d); break; case DLG_METHOD_SUBSCRIBE: // if (req && req->first_line.u.request.method.len==9 && // strncasecmp(req->first_line.u.request.method.s,"SUBSCRIBE",9)==0 && // cscf_get_expires_hdr(msg)==0){ // d->state = DLG_STATE_TERMINATED; // d_unlock(d->hash); // return P_drop_dialog(msg,str1,str2); // } if (req && req->first_line.u.request.method.len==6 && strncasecmp(req->first_line.u.request.method.s,"NOTIFY",6)==0){ expires = cscf_get_subscription_state(req); if (expires==0){ d->state = DLG_STATE_TERMINATED; d_unlock(d->hash); return P_drop_dialog(msg,str1,str2); }else if (expires>0){ d->expires = d_act_time() + expires; } } break; } if (cseq>d->last_cseq) d->last_cseq = cseq; } } d_unlock(d->hash); print_p_dialogs(L_INFO); return CSCF_RETURN_TRUE; out_of_memory: d_unlock(d->hash); return CSCF_RETURN_ERROR; }