release_call.c File Reference

#include "release_call.h"

Go to the source code of this file.

Functions

void alter_dialog_route_set (dlg_t *d, enum p_dialog_direction dir)
 Alters the saved dlg_t routes for the dialog by removing the first routes before myself.
int send_request (str, str, dlg_t *, transaction_cb, enum p_dialog_direction)
void confirmed_response (struct cell *t, int type, struct tmcb_params *ps)
 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.
int release_call_confirmed (p_dialog *d, int reason_code, str reason_text)
 This functions sends BYE for a confirmed dialog.
int release_call_previous (p_dialog *d, enum release_call_situation situation, int reason_code, str reason_text)
 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.
int release_call_early (p_dialog *d, int reason_code, str reason_text)
int release_call_early200 (p_dialog *d, int reason_code, str reason_text)
int release_call_p (p_dialog *d, int reason_code, str reason_text)
 Releases a dialog either confirmed or early the dialog is given with a lock on the hash!
int release_call (str callid, int reason_code, str reason_text)
 Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog.
int P_release_call_onreply (struct sip_msg *msg, char *str1, char *str2)
 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 - the sip message being processed - the first parameter "orig" or "term" - [optional] the Reason header that you want to go to the messages.

Variables

tm_binds tmb
 Structure with pointers to tm funcs.
dlg_func_t dialogb
 Structure with pointers to dialog funcs.
str pcscf_record_route_mo_uri
 URI for Record-route originating.
str pcscf_record_route_mt_uri
 URI for Record-route terminating.
static str reason_hdr_s = {"Reason: SIP ;cause=",19}
static str reason_hdr_1 = {" ;text=\"",8}
static str reason_hdr_e = {"\"\r\n",3}
static str _488_text_s = {"Not Acceptable Here",19}
static str method_CANCEL_s = {"CANCEL",6}
static str method_ACK_s = {"ACK",3}
static str method_BYE_s = {"BYE",3}
static str content_length_s = {"Content-Length: 0\r\n",19}


Function Documentation

void alter_dialog_route_set ( dlg_t *  d,
enum p_dialog_direction  dir 
)

Alters the saved dlg_t routes for the dialog by removing the first routes before myself.

This is requiered because half of the RRset is useless.

Parameters:
d - the dialog to modify the Record-Routes
dir - the direction

Definition at line 511 of file release_call.c.

References DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, NULL, pcscf_record_route_mo_uri, and pcscf_record_route_mt_uri.

Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().

00512 {
00513     rr_t *r,*r_new; 
00514     str p; /*this is going to point to the scscf uri*/
00515         
00516     
00517     
00518     switch (dir) {
00519         case DLG_MOBILE_ORIGINATING:
00520             p = pcscf_record_route_mo_uri;
00521             break;
00522         case DLG_MOBILE_TERMINATING:
00523             p = pcscf_record_route_mt_uri;
00524             break;
00525         default:
00526             return;
00527     }
00528     //LOG(L_CRIT,"Looking for <%.*s> in\n",p.len,p.s);
00529     //for(r=d->route_set;r!=NULL;r=r->next) 
00530     //  LOG(L_CRIT,"<%.*s>\n",r->nameaddr.uri.len,r->nameaddr.uri.s);
00531         
00532     for(r=d->route_set;r!=NULL;r=r->next) {
00533         if (r->nameaddr.uri.len>=p.len && 
00534             strncasecmp(r->nameaddr.uri.s,p.s,r->nameaddr.uri.len)==0)
00535             {
00536                 r_new=r->next;
00537                 r->next=NULL;
00538                 shm_free_rr(&d->route_set);
00539                 d->route_set = r_new;
00540                 return; 
00541             }
00542                     
00543     }   
00544 }       

int send_request ( str  ,
str  ,
dlg_t *  ,
transaction_cb  ,
enum  p_dialog_direction 
)

Definition at line 477 of file release_call.c.

References dialogb, M_NAME, and NULL.

Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().

00478 {
00479     if((d!=NULL) && (method.s!=NULL))
00480     {
00481         enum p_dialog_direction *cbp=NULL;
00482         
00483         if (method.len !=3 || memcmp(method.s,"ACK",3)!=0)
00484         {
00485             /*In case of ACK i don't want to even send the direction
00486              * moreover as the memory is freed in the callback function
00487              * and the ACK is never replied it would be a bug if i did*/
00488             cbp = shm_malloc(sizeof(enum p_dialog_direction));
00489             if (!cbp){
00490                 LOG(L_ERR,"ERR:"M_NAME":send_request(): error allocating %d bytes\n",sizeof(enum p_dialog_direction));
00491                 return 0;
00492             }
00493             *cbp=dir;
00494         }   
00495         dialogb.request_inside(&method,&reqbuf,NULL, d,cb,cbp);
00496         return 1;
00497     }
00498     
00499     return 0;
00500 }

void confirmed_response ( struct cell *  ,
int  ,
struct tmcb_params *   
)

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.

Definition at line 175 of file release_call.c.

References d_unlock(), del_p_dialog(), del_s_dialog(), DLG_STATE_TERMINATED_ONE_SIDE, get_p_dialog_dir(), get_s_dialog_dir(), _s_dialog::hash, _p_dialog::hash, M_NAME, _s_dialog::state, and _p_dialog::state.

Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().

00176 {       
00177     p_dialog *d;
00178     unsigned int hash;
00179     str call_id;
00180     
00181     enum p_dialog_direction dir;
00182     
00183     
00184     if (!ps->param) return;
00185     dir = *((enum p_dialog_direction *) *(ps->param));
00186     shm_free(*ps->param);
00187     *ps->param = 0;     
00188         
00189     //call_id = cscf_get_call_id(ps->rpl,0);
00190     call_id = t->callid;
00191     call_id.s+=9;
00192     call_id.len-=11;
00193     
00194     LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a BYE for a call release for <%.*s> DIR[%d].\n",
00195         call_id.len,call_id.s,dir);
00196     
00197     d = get_p_dialog_dir(call_id,dir);
00198     if (!d) {
00199         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",
00200             call_id.len,call_id.s,dir);
00201         return;
00202     }
00203     
00204     if (ps->code>=200){
00205         if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){
00206             hash=d->hash;
00207             del_p_dialog(d);
00208             d_unlock(hash);          
00209         } else {
00210             hash=d->hash;
00211             d->state=DLG_STATE_TERMINATED_ONE_SIDE;
00212             d_unlock(hash);
00213         }       
00214     } 
00215 }

int release_call_confirmed ( p_dialog d,
int  reason_code,
str  reason_text 
)

This functions sends BYE for a confirmed dialog.

Parameters:
d - the p_dialog to end
reason - the Reason: header to include in the messages
Returns:
0 on error 1 on success

Definition at line 95 of file release_call.c.

References alter_dialog_route_set(), _p_dialog::call_id, confirmed_response(), content_length_s, del_p_dialog(), _p_dialog::dialog_c, _p_dialog::dialog_s, _p_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_p_dialog_dir_nolock(), _p_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_BYE_s, reason_hdr_1, reason_hdr_e, reason_hdr_s, send_request(), and STR_APPEND.

Referenced by release_call_p().

00096 {
00097     enum p_dialog_direction odir;
00098     p_dialog *o;
00099     str r;
00100     str hdrs={0,0}; 
00101     char buf[256];
00102     
00103     LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Releasing call <%.*s> DIR[%d].\n",
00104         d->call_id.len,d->call_id.s,d->direction);
00105     
00106     r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s",
00107         reason_hdr_s.len,reason_hdr_s.s,
00108         reason_code,
00109         reason_hdr_1.len,reason_hdr_1.s,
00110         reason_text.len,reason_text.s,
00111         reason_hdr_e.len,reason_hdr_e.s);
00112     r.s = buf;
00113 
00114     hdrs.len = r.len+content_length_s.len;  
00115     hdrs.s = pkg_malloc(hdrs.len);
00116     if (!hdrs.s){
00117         LOG(L_INFO,"DBG:"M_NAME":release_call_confirmed(): Error allocating %d bytes.\n",hdrs.len);
00118         hdrs.len=0;
00119         goto error;
00120     }
00121     hdrs.len=0; 
00122     STR_APPEND(hdrs,r);
00123     STR_APPEND(hdrs,content_length_s);  
00124         
00125     /* get the dialog in the other direction to see if something going on there and mark as in releasing */
00126     switch (d->direction){
00127         case DLG_MOBILE_ORIGINATING:
00128             odir = DLG_MOBILE_TERMINATING;
00129             break;
00130         case DLG_MOBILE_TERMINATING:
00131             odir = DLG_MOBILE_ORIGINATING;
00132             break;
00133         default:
00134             odir = d->direction;
00135     }   
00136     
00137     o = get_p_dialog_dir_nolock(d->call_id,odir);
00138     if (o && !o->is_releasing) o->is_releasing = 1;
00139         
00140     d->is_releasing++;
00141         
00142     if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
00143         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);
00144         del_p_dialog(d);
00145         goto error;
00146     }
00147     if (d->is_releasing==1) {   
00148         /*Before generating a request, we have to generate
00149          * the route_set in the dlg , because the route set
00150          * in the dialog is for the UAC everything which was in the 
00151          * Record-Routes (including local address)*/
00152         alter_dialog_route_set(d->dialog_c,d->direction);       
00153         
00154         /*first generate the bye for called user*/
00155         /*then generate the bye for the calling user*/
00156         send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction);
00157         send_request(method_BYE_s,hdrs,d->dialog_s,confirmed_response,d->direction);
00158         
00159         /*the dialog is droped by the callback-function when receives the two replies */
00160     }    
00161 
00162     if (hdrs.s) pkg_free(hdrs.s);
00163     return 1;
00164 error:
00165     if (hdrs.s) pkg_free(hdrs.s);
00166     return 0;   
00167 }

int release_call_previous ( p_dialog d,
enum release_call_situation  situation,
int  reason_code,
str  reason_text 
)

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.

Parameters:
d - p_dialog of the call - flag to distinguish between two situations
Returns:
0 on error 1 on success
Note:
This function shouldn't be called directly! use release_call_early or release_call_early200 instead

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

any move in the order of functions to clarify the structure can lead to a crash in P-CSCF so watch out!

Definition at line 237 of file release_call.c.

References alter_dialog_route_set(), _p_dialog::call_id, confirmed_response(), content_length_s, del_p_dialog(), _p_dialog::dialog_c, _p_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, DLG_STATE_TERMINATED_ONE_SIDE, get_p_dialog_dir_nolock(), _p_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_ACK_s, method_BYE_s, method_CANCEL_s, reason_hdr_1, reason_hdr_e, reason_hdr_s, RELEASE_CALL_WEIRD, send_request(), _p_dialog::state, STR_APPEND, and tmb.

Referenced by P_release_call_onreply(), release_call_early(), and release_call_early200().

00238 {
00239     struct cell* t;
00240     p_dialog *o;
00241     enum p_dialog_direction odir;
00242     int i;
00243     str r;
00244     str hdrs={0,0}; 
00245     char buf[256];
00246     
00247     LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Releasing call <%.*s> DIR[%d].\n",
00248         d->call_id.len,d->call_id.s,d->direction);
00249     
00250     r.len = snprintf(buf,256,"%.*s%d%.*s%.*s%.*s",
00251         reason_hdr_s.len,reason_hdr_s.s,
00252         reason_code,
00253         reason_hdr_1.len,reason_hdr_1.s,
00254         reason_text.len,reason_text.s,
00255         reason_hdr_e.len,reason_hdr_e.s);
00256     r.s = buf;
00257 
00258     hdrs.len = r.len+content_length_s.len;  
00259     hdrs.s = pkg_malloc(hdrs.len);
00260     if (!hdrs.s){
00261         LOG(L_INFO,"DBG:"M_NAME":release_call_previous(): Error allocating %d bytes.\n",hdrs.len);
00262         hdrs.len=0;
00263         goto error;
00264     }
00265     hdrs.len=0;
00266     STR_APPEND(hdrs,r);
00267     STR_APPEND(hdrs,content_length_s);  
00268                                                     
00269     /* get the dialog in the other direction to see if something going on there and mark as in releasing */
00270     switch (d->direction){
00271         case DLG_MOBILE_ORIGINATING:
00272             odir = DLG_MOBILE_TERMINATING;
00273             break;
00274         case DLG_MOBILE_TERMINATING:
00275             odir = DLG_MOBILE_ORIGINATING;
00276             break;
00277         default:
00278             odir = d->direction;
00279     }   
00280     
00281     o = get_p_dialog_dir_nolock(d->call_id,odir);
00282     if (o && !o->is_releasing) o->is_releasing = 1;
00283         
00284     d->is_releasing++;
00285         
00286     if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
00287         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);
00288         del_p_dialog(d);
00289         goto error;
00290     }
00291     
00292     alter_dialog_route_set(d->dialog_c,d->direction);
00293     
00294     d->state=DLG_STATE_TERMINATED_ONE_SIDE;
00295     /*this is just a trick to use the same callback function*/  
00296     
00297     /*trick or treat!*/
00298     d->dialog_c->state=DLG_CONFIRMED;
00299     
00300     if (situation == RELEASE_CALL_WEIRD){
00301         send_request(method_ACK_s,hdrs,d->dialog_c,0,0);
00302         send_request(method_BYE_s,hdrs,d->dialog_c,confirmed_response,d->direction);
00303         //d->dialog_c->state=DLG_EARLY;
00304     } else {/*(situation == RELEASE_CALL_EARLY)*/       
00305         send_request(method_CANCEL_s,hdrs,d->dialog_c,confirmed_response,d->direction);
00306         //d->dialog_c->state=DLG_EARLY;
00307     }
00308 
00309     /*i need the cell of the invite!!*/
00310     /*this is very experimental
00311      * and very tricky too*/
00312     t=tmb.t_gett();
00313     
00314     if (t && t!=(void*) -1  && t->uas.request) {
00315         /*first trick: i really want to get this reply sent even though we are onreply*/
00316         *tmb.route_mode=MODE_ONFAILURE;
00317         
00318         /*second trick .. i haven't recieve any response from the uac
00319          * if i don't do this i get a cancel sent to the S-CSCF .. its not a big deal*/
00320          /*if i cared about sip forking then probably i would not do that and let the 
00321           * CANCEL go to the S-CSCF (reread specifications needed)*/
00322         for (i=0; i< t->nr_of_outgoings; i++)
00323             t->uac[i].last_received=99;
00324         /*t->uas.status=100;*/ /*no one cares about this*/
00325         /*now its safe to do this*/
00326         
00327         tmb.t_reply(t->uas.request,reason_code,reason_text.s);
00328         *tmb.route_mode=MODE_ONREPLY;
00329         tmb.t_release(t->uas.request);
00330 
00331         /*needed because if not i get last message retransmited... 
00332          * probably there is a more logical way to do this.. but since i really
00333          * want this transaction to end .. whats the point?*/
00334     }
00335     
00336     return 1;
00337 error:
00338     if (hdrs.s) pkg_free(hdrs.s);
00339     return 0;   
00340 }

int release_call_early ( p_dialog d,
int  reason_code,
str  reason_text 
)

Definition at line 343 of file release_call.c.

References RELEASE_CALL_EARLY, and release_call_previous().

Referenced by release_call_p().

00344 {
00345     /*CANCEL will be badly routed because the response hasn't being processed
00346      * it will be sent to I-CSCF who will relay to S-CSCF and from there to term@P-CSCF*/
00347     return release_call_previous(d,RELEASE_CALL_EARLY,reason_code,reason_text);
00348 }

int release_call_early200 ( p_dialog d,
int  reason_code,
str  reason_text 
)

Definition at line 350 of file release_call.c.

References release_call_previous(), and RELEASE_CALL_WEIRD.

00351 {
00352     return release_call_previous(d,RELEASE_CALL_WEIRD,reason_code,reason_text);
00353 }

int release_call_p ( p_dialog d,
int  reason_code,
str  reason_text 
)

Releases a dialog either confirmed or early the dialog is given with a lock on the hash!

Parameters:
d - p_dialog to release
reason - Reason header to include in messages
Returns:
0 on error , 1 on success, -1 if dialog should be deleted from outside

Definition at line 370 of file release_call.c.

References DLG_STATE_CONFIRMED, release_call_confirmed(), release_call_early(), and _p_dialog::state.

Referenced by release_call(), and terminate_p_dialog().

00371 {       
00372     if (d->state>=DLG_STATE_CONFIRMED)
00373             return(release_call_confirmed(d,reason_code,reason_text));
00374      else  
00375             return(release_call_early(d,reason_code,reason_text)); 
00376 }

int release_call ( str  callid,
int  reason_code,
str  reason_text 
)

Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog.

Parameters:
callid - the Call-ID to release
reason - the Reason header to include in messages
Returns:
0 on error, 1 on success

Definition at line 386 of file release_call.c.

00387 {
00388     p_dialog *d=0;
00389     unsigned int hash;
00390     int res = 0;
00391     
00392     d = get_p_dialog_dir(callid,DLG_MOBILE_ORIGINATING);
00393     if (d) {                
00394         hash = d->hash;
00395         if (release_call_p(d,reason_code,reason_text)>0) res = 1;       
00396         goto done;      
00397     }
00398     d = get_p_dialog_dir(callid,DLG_MOBILE_TERMINATING);
00399     if (d) {                
00400         hash = d->hash;
00401         if (release_call_p(d,reason_code,reason_text)>0) res = 1;       
00402         goto done;
00403     } 
00404     
00405     /*Neither ORGINATING nor TERMINATING is UNKNOWN!*/
00406     /*or doesn't exist*/
00407     /*drop it silently?*/
00408     /*treat it as ORIGINATING or TERMINATING?*/             
00409 done:       
00410     if (d) d_unlock(hash);
00411     return 0;   
00412 }

int P_release_call_onreply ( struct sip_msg *  msg,
char *  str1,
char *  str2 
)

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 - the sip message being processed - the first parameter "orig" or "term" - [optional] the Reason header that you want to go to the messages.

Returns:
- TRUE on success or FALSE on misscall and BREAK on error

Definition at line 426 of file release_call.c.

References _488_text_s, cscf_get_call_id(), CSCF_RETURN_BREAK, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, d_unlock(), DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_p_dialog_dir(), _p_dialog::hash, is_p_dialog_dir(), M_NAME, NULL, RELEASE_CALL_EARLY, release_call_previous(), and RELEASE_CALL_WEIRD.

00427 {
00428     enum p_dialog_direction dir;
00429     p_dialog *d=NULL;
00430     str callid;
00431     struct hdr_field *h1;
00432     str reason={NULL,0};
00433     
00434     if (str2) {
00435         reason.s=str2;
00436         reason.len=strlen(str2);
00437     } else
00438         reason = _488_text_s;
00439         
00440     
00441     dir= (str1[0]=='o' || str1[0]=='O' || str1[0]=='0')? DLG_MOBILE_ORIGINATING : DLG_MOBILE_TERMINATING;
00442     
00443     if (msg->first_line.type== SIP_REQUEST)
00444     {
00445         LOG(L_ERR,"ERR: P_release_call_on_reply called with a request\n");
00446         return CSCF_RETURN_FALSE;
00447     }
00448     
00449     callid=cscf_get_call_id(msg,&h1);
00450     if (is_p_dialog_dir(callid,dir)) {
00451         d=get_p_dialog_dir(callid,dir);
00452         if (msg->first_line.u.reply.statuscode > 199)
00453         {
00454             release_call_previous(d,RELEASE_CALL_WEIRD,488,reason);
00455             d_unlock(d->hash);
00456             return CSCF_RETURN_TRUE;
00457         } else {
00458             release_call_previous(d,RELEASE_CALL_EARLY,488,reason);
00459             d_unlock(d->hash);
00460             return CSCF_RETURN_TRUE;
00461         }
00462     } else {
00463         LOG(L_ERR,"ERR:"M_NAME "P_release_call_onreply :  unable to find dialog\n");
00464         return CSCF_RETURN_BREAK;
00465     }
00466     
00467 }


Variable Documentation

struct tm_binds tmb

Structure with pointers to tm funcs.

Definition at line 257 of file mod.c.

dlg_func_t dialogb

Structure with pointers to dialog funcs.

Definition at line 466 of file mod.c.

str pcscf_record_route_mo_uri

URI for Record-route originating.

Definition at line 171 of file mod.c.

str pcscf_record_route_mt_uri

URI for Record-route terminating.

Definition at line 173 of file mod.c.

str reason_hdr_s = {"Reason: SIP ;cause=",19} [static]

Definition at line 70 of file release_call.c.

Referenced by release_call_confirmed(), and release_call_previous().

str reason_hdr_1 = {" ;text=\"",8} [static]

Definition at line 71 of file release_call.c.

Referenced by release_call_confirmed(), and release_call_previous().

str reason_hdr_e = {"\"\r\n",3} [static]

Definition at line 72 of file release_call.c.

Referenced by release_call_confirmed(), and release_call_previous().

str _488_text_s = {"Not Acceptable Here",19} [static]

Definition at line 76 of file release_call.c.

Referenced by P_release_call_onreply().

str method_CANCEL_s = {"CANCEL",6} [static]

Definition at line 78 of file release_call.c.

Referenced by release_call_previous().

str method_ACK_s = {"ACK",3} [static]

Definition at line 79 of file release_call.c.

Referenced by release_call_previous().

str method_BYE_s = {"BYE",3} [static]

Definition at line 80 of file release_call.c.

Referenced by release_call_confirmed(), and release_call_previous().

str content_length_s = {"Content-Length: 0\r\n",19} [static]

Definition at line 88 of file release_call.c.

Referenced by release_call_confirmed(), release_call_previous(), release_call_s(), and release_subscription().


Generated on Thu Oct 23 04:14:45 2008 for Open IMS Core CSCFs by  doxygen 1.5.2