/** * Given a call-id, locate if its terminating,orginating or both * release the dialog involved and drop the dialog * @param callid - the Call-ID to release * @param reason - the Reason header to include in messages * @returns 0 on error, 1 on success */ int release_call(str callid,int reason_code,str reason_text) { p_dialog *d=0; unsigned int hash; int res = 0; d = get_p_dialog_dir(callid,DLG_MOBILE_ORIGINATING); if (d) { hash = d->hash; if (release_call_p(d,reason_code,reason_text)>0) res = 1; goto done; } d = get_p_dialog_dir(callid,DLG_MOBILE_TERMINATING); if (d) { hash = d->hash; if (release_call_p(d,reason_code,reason_text)>0) res = 1; goto done; } /*Neither ORGINATING nor TERMINATING is UNKNOWN!*/ /*or doesn't exist*/ /*drop it silently?*/ /*treat it as ORIGINATING or TERMINATING?*/ done: if (d) d_unlock(hash); return 0; }
/** * Releases a call from the on reply route block * called with any reply to an INVITE * useful in cases of rejecting a call when you are processing the SDP * or handling QoS things * @msg - the sip message being processed * @str1 - the first parameter "orig" or "term" * @str2 - [optional] the Reason header that you want to go to the messages * @returns - TRUE on success or FALSE on misscall and BREAK on error */ int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2) { enum p_dialog_direction dir; p_dialog *d=NULL; str callid; struct hdr_field *h1; str reason={NULL,0}; if (str2) { reason.s=str2; reason.len=strlen(str2); } else reason = _488_text_s; dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING; if (msg->first_line.type== SIP_REQUEST) { LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n"); return CSCF_RETURN_FALSE; } callid=cscf_get_call_id(msg,&h1); if (is_p_dialog_dir(callid,dir)) { d=get_p_dialog_dir(callid,dir); if (msg->first_line.u.reply.statuscode > 199) { release_call_previous(d,RELEASE_CALL_WEIRD,488,reason); d_unlock(d->hash); return CSCF_RETURN_TRUE; } else { release_call_previous(d,RELEASE_CALL_EARLY,488,reason); d_unlock(d->hash); return CSCF_RETURN_TRUE; } } else { LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply : unable to find dialog\n"); return CSCF_RETURN_BREAK; } }
/** * Callback function for BYE requests! * Identify the s_dialog, then see if one BYE has already been recieved * if yes drop it , if no, wait for the second */ void confirmed_response(struct cell *t,int type,struct tmcb_params *ps) { p_dialog *d; unsigned int hash; str call_id; enum p_dialog_direction dir; if (!ps->param) return; dir = *((enum p_dialog_direction *) *(ps->param)); shm_free(*ps->param); *ps->param = 0; //call_id = cscf_get_call_id(ps->rpl,0); call_id = t->callid; call_id.s+=9; call_id.len-=11; LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a BYE for a call release for <%.*s> DIR[%d].\n", call_id.len,call_id.s,dir); d = get_p_dialog_dir(call_id,dir); if (!d) { LOG(L_ERR,"ERR:"M_NAME":confirmed_response(): Received a BYE for a call release but there is no dialog for <%.*s> DIR[%d].\n", call_id.len,call_id.s,dir); return; } if (ps->code>=200){ if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){ hash=d->hash; del_p_dialog(d); d_unlock(hash); } else { hash=d->hash; d->state=DLG_STATE_TERMINATED_ONE_SIDE; d_unlock(hash); } } }
/** * Releases a call from the on reply route block * called with any reply to an INVITE * useful in cases of rejecting a call when you are processing the SDP * or handling QoS things * @msg - the sip message being processed * @str1 - the first parameter "orig" or "term" * @str2 - [optional] the Reason header that you want to go to the messages * @returns - BREAK ... whatever happens this message is not relayed */ int P_release_call_onreply(struct sip_msg *msg,char *str1,char *str2) { enum p_dialog_direction dir; p_dialog *d=NULL; str callid; struct hdr_field *h1; str reason= {NULL,0}; unsigned int hash; struct cell* t; /*needed to distinguish between UPDATE and INVITE*/ LOG(L_INFO,ANSI_WHITE"P_release_call_on_reply\n"); if (str2) { reason.s=str2; reason.len=strlen(str2); } else reason = _488_text_s; dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING; if (msg->first_line.type== SIP_REQUEST) { LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n"); return CSCF_RETURN_FALSE; } callid=cscf_get_call_id(msg,&h1); if (is_p_dialog_dir(callid,dir)) { d=get_p_dialog_dir(callid,dir); hash=d->hash; t=tmb.t_gett(); if (!t) { LOG(L_ERR,"P_release_call_onreply(): unable to get transaction\n"); return CSCF_RETURN_BREAK; } if (t->method.len==6 && memcmp(t->method.s,"INVITE",6)==0) { // If its an INVTE, the state depends on which reply we are processing if (msg->first_line.u.reply.statuscode > 199) { release_call_previous(d,RELEASE_CALL_WEIRD,488,reason); } else { release_call_previous(d,RELEASE_CALL_EARLY,488,reason); } // This means we already finished with the dialog if (d->pcc_session_id.s) shm_free(d->pcc_session_id.s); d->pcc_session_id.s=0; d->pcc_session_id.len=0; d_unlock(hash); return CSCF_RETURN_BREAK; } else { //UPDATE so early release_call_early(d,488,reason); d_unlock(hash); return CSCF_RETURN_BREAK; } } else { LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply : unable to find dialog\n"); return CSCF_RETURN_ERROR; } }