Beispiel #1
0
/**
 * Given an s_dialog, releases the call.
 * This function is already called with a lock in d
 * after returning d should be unlocked.
 * @param d - pointer to the s_dialog structure
 * @param reason - Reason header to include
 * @returns -1 if dialog the dialog is not confirmed, 0 on error or 1 on success
 */
int release_call_s(s_dialog *d,str reason)
{
	enum s_dialog_direction odir;
	s_dialog *o;

	LOG(L_INFO,"DBG:"M_NAME":release_call_s(): Releasing call <%.*s> DIR[%d].\n",
		d->call_id.len,d->call_id.s,d->direction);
					
	/* As for now, i'm only releasing confirmed dialogs */
	if (d->state < DLG_STATE_CONFIRMED){
		LOG(L_INFO,"ERR:"M_NAME":release_call_s(): Unable to release a non-confirmed dialog\n");		
		return -1;
	}
		
	/* get the dialog in the other direction to see if something going on there and mark as in releasing */
	switch (d->direction){
		case DLG_MOBILE_ORIGINATING:
			odir = DLG_MOBILE_TERMINATING;
			break;
		case DLG_MOBILE_TERMINATING:
			odir = DLG_MOBILE_ORIGINATING;
			break;
		default:
			odir = d->direction;
	}	
	
	o = get_s_dialog_dir_nolock(d->call_id,odir);
	if (o && !o->is_releasing) o->is_releasing = 1;
		
	d->is_releasing++;
		
	if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
		LOG(L_ERR,"ERR:"M_NAME":release_call_s(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction);
		del_s_dialog(d);
		return 0;
	}
	if (d->is_releasing==1) {	
		/*Before generating a request, we have to generate
		 * the route_set in the dlg , because the route set
		 * in the dialog is for the UAC everything which was in the 
		 * Record-Routes (including local address)*/
		alter_dialog_route_set(d->dialog_c,d->direction);		
		
		/*first generate the bye for called user*/
		/*then generate the bye for the calling user*/
		send_bye(d->dialog_c,bye_response,d->direction,reason);
		send_bye(d->dialog_s,bye_response,d->direction,reason);
		
		/*the dialog is droped by the callback-function when recieves the two replies */
	}	 
	return 1;
}
Beispiel #2
0
/**
 * Function that releases a call in early or early200 situation
 * early200 is when the callee has already sent out 200 but that hasn't
 * arrived yet to the caller
 * @param d - p_dialog of the call
 * @situation - flag to distinguish between two situations
 * @return 0 on error 1 on success
 * 
 * \note This function shouldn't be called directly!
 * use release_call_early or release_call_early200 instead 
 * 
 * \note This function is full of tricks to fake states and
 * to decieve the transaction module so that it lets us
 * end a call in weird state
 * 
 * \note any move in the order of functions to clarify the structure
 * can lead to a crash in P-CSCF so watch out!
 */
int release_call_previous(p_dialog *d,enum release_call_situation situation,int reason_code,str reason_text)
{
	struct cell* t;
	p_dialog *o;
	enum p_dialog_direction odir;
	int i;
	str r;
	str hdrs={0,0};	
	char buf[256];
	
	LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Releasing call <%.*s> DIR[%d].\n",
		d->call_id.len,d->call_id.s,d->direction);
	
	r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s",
		reason_hdr_s.len,reason_hdr_s.s,
		reason_code,
		reason_hdr_1.len,reason_hdr_1.s,
		reason_text.len,reason_text.s,
		reason_hdr_e.len,reason_hdr_e.s);
	r.s = buf;

	hdrs.len = r.len+content_length_s.len;	
	hdrs.s = pkg_malloc(hdrs.len);
	if (!hdrs.s){
		LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Error allocating %d bytes.\n",hdrs.len);
		hdrs.len=0;
		goto error;
	}
	hdrs.len=0;
	STR_APPEND(hdrs,r);
	STR_APPEND(hdrs,content_length_s);	
													
	/* get the dialog in the other direction to see if something going on there and mark as in releasing */
	switch (d->direction){
		case DLG_MOBILE_ORIGINATING:
			odir = DLG_MOBILE_TERMINATING;
			break;
		case DLG_MOBILE_TERMINATING:
			odir = DLG_MOBILE_ORIGINATING;
			break;
		default:
			odir = d->direction;
	}	
	
	o = get_p_dialog_dir_nolock(d->call_id,odir);
	if (o && !o->is_releasing) o->is_releasing = 1;
		
	d->is_releasing++;
		
	if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
		LOG(L_ERR,"ERR:"M_NAME":release_call_previous(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction);
		del_p_dialog(d);
		goto error;
	}
	
	alter_dialog_route_set(d->dialog_c,d->direction);
	
	d->state=DLG_STATE_TERMINATED_ONE_SIDE;
	/*this is just a trick to use the same callback function*/	
	
	/*trick or treat!*/
	d->dialog_c->state=DLG_CONFIRMED;
	
	if (situation == RELEASE_CALL_WEIRD){
		send_request(method_ACK_s,hdrs,d->dialog_c,0,0);
		send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction);
		//d->dialog_c->state=DLG_EARLY;
	} else {/*(situation == RELEASE_CALL_EARLY)*/		
		send_request(method_CANCEL_s,hdrs,d->dialog_c,confirmed_response,d->direction);
		//d->dialog_c->state=DLG_EARLY;
	}

	/*i need the cell of the invite!!*/
	/*this is very experimental
	 * and very tricky too*/
	t=tmb.t_gett();
	
	if (t && t->uas.request) {
		/*first trick: i really want to get this reply sent even though we are onreply*/
		*tmb.route_mode=MODE_ONFAILURE;
		
		/*second trick .. i haven't recieve any response from the uac
		 * if i don't do this i get a cancel sent to the S-CSCF .. its not a big deal*/
		 /*if i cared about sip forking then probably i would not do that and let the 
		  * CANCEL go to the S-CSCF (reread specifications needed)*/
		for (i=0; i< t->nr_of_outgoings; i++)
			t->uac[i].last_received=99;
		/*t->uas.status=100;*/ /*no one cares about this*/
		/*now its safe to do this*/
		
		tmb.t_reply(t->uas.request,reason_code,reason_text.s);
		*tmb.route_mode=MODE_ONREPLY;
		tmb.t_release(t->uas.request);

		/*needed because if not i get last message retransmited... 
		 * probably there is a more logical way to do this.. but since i really
		 * want this transaction to end .. whats the point?*/
	}
	
	return 1;
error:
	if (hdrs.s) pkg_free(hdrs.s);
	return 0;	
}
Beispiel #3
0
/**
 * This functions sends BYE for a confirmed dialog
 * @param d - the p_dialog to end
 * @param reason - the Reason: header to include in the messages
 * @returns 0 on error 1 on success
 */
int release_call_confirmed(p_dialog *d, int reason_code, str reason_text)
{
	enum p_dialog_direction odir;
	p_dialog *o;
	str r;
	str hdrs={0,0};	
	char buf[256];
	
	LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Releasing call <%.*s> DIR[%d].\n",
		d->call_id.len,d->call_id.s,d->direction);
	
	r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s",
		reason_hdr_s.len,reason_hdr_s.s,
		reason_code,
		reason_hdr_1.len,reason_hdr_1.s,
		reason_text.len,reason_text.s,
		reason_hdr_e.len,reason_hdr_e.s);
	r.s = buf;

	hdrs.len = r.len+content_length_s.len;	
	hdrs.s = pkg_malloc(hdrs.len);
	if (!hdrs.s){
		LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Error allocating %d bytes.\n",hdrs.len);
		hdrs.len=0;
		goto error;
	}
	hdrs.len=0;	
	STR_APPEND(hdrs,r);
	STR_APPEND(hdrs,content_length_s);	
		
	/* get the dialog in the other direction to see if something going on there and mark as in releasing */
	switch (d->direction){
		case DLG_MOBILE_ORIGINATING:
			odir = DLG_MOBILE_TERMINATING;
			break;
		case DLG_MOBILE_TERMINATING:
			odir = DLG_MOBILE_ORIGINATING;
			break;
		default:
			odir = d->direction;
	}	
	
	o = get_p_dialog_dir_nolock(d->call_id,odir);
	if (o && !o->is_releasing) o->is_releasing = 1;
		
	d->is_releasing++;
		
	if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
		LOG(L_ERR,"ERR:"M_NAME":release_call_confirmed(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction);
		del_p_dialog(d);
		goto error;
	}
	if (d->is_releasing==1) {	
		/*Before generating a request, we have to generate
		 * the route_set in the dlg , because the route set
		 * in the dialog is for the UAC everything which was in the 
		 * Record-Routes (including local address)*/
		alter_dialog_route_set(d->dialog_c,d->direction);		
		
		/*first generate the bye for called user*/
		/*then generate the bye for the calling user*/
		send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction);
		send_request(method_BYE_s,hdrs,d->dialog_s,confirmed_response,d->direction);
		
		/*the dialog is droped by the callback-function when receives the two replies */
	}	 

	if (hdrs.s) pkg_free(hdrs.s);
	return 1;
error:
	if (hdrs.s) pkg_free(hdrs.s);
	return 0;	
}
Beispiel #4
0
/**
 * Function that releases a call in early or early200 situation
 * early200 is when the callee has already sent out 200 but that hasn't
 * arrived yet to the caller
 * @param d - p_dialog of the call
 * @situation - flag to distinguish between two situations
 * @return 0 on error 1 on success
 *
 * \note This function shouldn't be called directly!
 * use release_call_early or release_call_early200 instead
 *
 * \note This function is full of tricks to fake states and
 * to decieve the transaction module so that it lets us
 * end a call in weird state
 *
 * \note any move in the order of functions to clarify the structure
 * can lead to a crash in P-CSCF so watch out!
 */
int release_call_previous(p_dialog *d,enum release_call_situation situation,int reason_code,str reason_text)
{
    struct cell* t;
    p_dialog *o;
    enum p_dialog_direction odir;
    int i;
    str r;
    str hdrs= {0,0};
    str firstcseq;
    char buf[256];

    if(!d)
        return 0;

    LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Releasing call <%.*s> DIR[%d].\n",
        d->call_id.len,d->call_id.s,d->direction);

    r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s",
                     reason_hdr_s.len,reason_hdr_s.s,
                     reason_code,
                     reason_hdr_1.len,reason_hdr_1.s,
                     reason_text.len,reason_text.s,
                     reason_hdr_e.len,reason_hdr_e.s);
    r.s = buf;

    hdrs.len = r.len+content_length_s.len;
    hdrs.s = pkg_malloc(hdrs.len);
    if (!hdrs.s) {
        LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Error allocating %d bytes.\n",hdrs.len);
        hdrs.len=0;
        goto error;
    }
    hdrs.len=0;
    STR_APPEND(hdrs,r);
    STR_APPEND(hdrs,content_length_s);

    /* get the dialog in the other direction to see if something going on there and mark as in releasing */
    switch (d->direction) {
    case DLG_MOBILE_ORIGINATING:
        odir = DLG_MOBILE_TERMINATING;
        break;
    case DLG_MOBILE_TERMINATING:
        odir = DLG_MOBILE_ORIGINATING;
        break;
    default:
        odir = d->direction;
    }

    time_t time_now=time(0);

    o = get_p_dialog_dir_nolock(d->call_id,odir);


    if (o && o->is_releasing==0)  {

        o->is_releasing = 1;
        // Addition from Alberto Diez the 2nd November 2007
        // the idea is to put the other one to expire in TIME_TO_EXPIRE
        // just in case no reply is received
        if (o->expires>time_now+TIME_TO_EXPIRE) {
            o->expires=time_now+TIME_TO_EXPIRE;
        }

    }
    d->is_releasing++;

    /*The first time i decrease the expire time for the dialog expire , so that i guarantee that
    	 * its going to be deleted from the table sometime*/


    if (d->expires>time_now+TIME_TO_EXPIRE)
    {
        d->expires=time_now+TIME_TO_EXPIRE;
    }

    if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE) {
        LOG(L_ERR,"ERR:"M_NAME":release_call_previous(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction);
        del_p_dialog(d);
        goto error;
    }

    if(alter_dialog_route_set(d->dialog_c,d->direction,situation)<0) {
        LOG(L_ERR,"ERR:"M_NAME":release_call_previous(): had to delete silently dialog %.*s in direction %i\n",d->call_id.len,d->call_id.s,d->direction);
        del_p_dialog(d);
        goto error;
    }

    d->state=DLG_STATE_TERMINATED_ONE_SIDE;
    /*this is just a trick to use the same callback function*/




    /*i need the cell of the invite!!*/
    /*this is very experimental
     * and very tricky too*/
    //t=tmb.t_gett();
    i=0;
    i=snprintf(buf,256,"%i",d->first_cseq); // i just use buf because its there..

    if (i==256) {
        LOG(L_ERR,"release_call_previous: some client used first CSeq way too big\n");
        goto error;
    }

    firstcseq.s=pkg_malloc(i+1); // the \0
    firstcseq.len=i;
    sprintf(firstcseq.s,"%i",d->first_cseq);
    LOG(L_INFO,"CALLED t_lookup_callid with %.*s, %.*s\n",d->call_id.len,d->call_id.s,firstcseq.len,firstcseq.s);
    if (tmb.t_lookup_callid(&t,d->call_id,firstcseq) < 0) {
        pkg_free(firstcseq.s);
        LOG(L_ERR,"release_call_previous: t_lookup_callid failed\n");
        goto error;
    }

    pkg_free(firstcseq.s);

    if (t && t!=(void*) -1  && t->uas.request) {


        if (t->method.len!=6 || t->method.s[0]!='I' || t->method.s[1]!='N' || t->method.s[2]!='V')
        {
            //well this is the transaction of a subsequent request within the dialog
            //and the dialog is not confirmed yet, so its a PRACK or an UPDATE
            //could also be an options, but the important thing is how am i going to get
            //the transaction of the invite, that is the one i have to cancel
            LOG(L_ERR,"this is not my transaction so where am i?\n");
        }


        /*first trick: i really want to get this reply sent even though we are onreply*/

#ifdef SER_MOD_INTERFACE
        route_type = FAILURE_ROUTE;
#else
        *tmb.route_mode=MODE_ONFAILURE;
#endif


        if (situation == RELEASE_CALL_WEIRD) {
            /*second trick .. i haven't recieve any response from the uac
            * if i don't do this i get a cancel sent to the S-CSCF .. its not a big deal*/
            /*if i cared about sip forking then probably i would not do that and let the
            * CANCEL go to the S-CSCF (reread specifications needed)*/
            //for (i=0; i< t->nr_of_outgoings; i++)
            //	t->uac[i].last_received=99;
            /*t->uas.status=100;*/ /*no one cares about this*/
            /*now its safe to do this*/

            /*trick or treat!*/
            for (i=0; i< t->nr_of_outgoings; i++)
                t->uac[i].last_received=99;
            t->uas.status=100;
            d->dialog_c->state=DLG_CONFIRMED;
            send_request(method_ACK_s,hdrs,d->dialog_c,0,0);
            send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction);
            d->dialog_c->state=DLG_EARLY;

            tmb.t_reply(t->uas.request,reason_code,reason_text.s);
            *tmb.route_mode=MODE_ONREPLY;
            t->uas.status=488;
            tmb.t_release(t->uas.request);
            /*needed because if not i get last message retransmited...
             * probably there is a more logical way to do this.. but since i really
             * want this transaction to end .. whats the point?*/
        } else {/*(situation == RELEASE_CALL_EARLY)*/
            d->dialog_c->loc_seq.value++;

            //d->dialog_c->state=DLG_CONFIRMED;
            //send_request(method_CANCEL_s,hdrs,d->dialog_c,confirmed_response,d->direction);
            //d->dialog_c->state=DLG_EARLY;

            tmb.t_reply(t->uas.request,reason_code,reason_text.s);

            /*
            for (i=0; i< t->nr_of_outgoings; i++)
            	t->uac[i].last_received=180;
            */

            // t_reply has decided to send a CANCEL already so no big deal!

            //tmb.cancel_uacs(t,0xFFFF,F_CANCEL_B_FAKE_REPLY);

            //t->uas.status=488;

            //tmb.t_release(t->uas.request);


            // I thought of deleting the dialog here.. but
            // a good SIP client will respond to the CANCEL with a 487
            //del_p_dialog(d);
        }
    }

    if (hdrs.s) pkg_free(hdrs.s);
    return 1;
error:
    if (hdrs.s) pkg_free(hdrs.s);
    return 0;
}