release_call.c File Reference

#include "release_call.h"
#include "sip.h"

Go to the source code of this file.

Functions

int send_request (str method, str reqbuf, dlg_t *d, transaction_cb cb, enum s_dialog_direction dir)
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.
void alter_dialog_route_set (dlg_t *d, enum s_dialog_direction dir)
 Alters the saved dlg_t routes for the dialog by removing the first routes before myself.
int release_call (str callid, str reason)
 Given a call-id, locate if its terminating,orginating or both release the dialog involved and drop the dialog.
int release_call_s (s_dialog *d, str reason)
 Given an s_dialog, releases the call.
int release_subscription (s_dialog *d)

Variables

tm_binds tmb
 Structure with pointers to tm funcs.
dlg_func_t dialogb
 Structure with pointers to dialog funcs.
str scscf_record_route_mo_uri
 just the record route uri for Mobile Originating
str scscf_record_route_mt_uri
 just the record route uri for Mobile Terminating
static str method_bye_s = {"BYE",3}
static str default_reason_s = {"Reason: SIP ;cause=503 ;text=\"Session Terminated\"\r\n",51}
static str content_length_s = {"Content-Length: 0\r\n",19}
static str hdrs_notify_s = {"Subscription-State: terminated\r\n",32}
static str method_NOTIFY_s = {"NOTIFY",6}
static str hdr_expires_s = {"Expires: 0\r\n",12}
static str hdr_event1_s = {"Event: ",7}
static str hdr_event2_s = {"\r\n",2}
static str hdr_contact1_s = {"Contact: <",10}
static str hdr_contact2_s = {">\r\n",3}
static str method_SUBSCRIBE_s = {"SUBSCRIBE",9}


Function Documentation

int send_request ( str  method,
str  reqbuf,
dlg_t *  d,
transaction_cb  cb,
enum s_dialog_direction  dir 
)

Definition at line 83 of file release_call.c.

References dialogb, M_NAME, and NULL.

00084 {
00085     
00086     if((d!=NULL) && (method.s!=NULL))
00087     {
00088         enum s_dialog_direction *cbp=NULL;
00089         
00090         if (method.len !=3 || memcmp(method.s,"ACK",3)!=0)
00091         {
00092             /*In case of ACK i don't want to even send the direction
00093              * moreover as the memory is freed in the callback function
00094              * and the ACK is never replied it would be a bug if i did*/
00095             cbp = shm_malloc(sizeof(enum s_dialog_direction));
00096             if (!cbp){
00097                 LOG(L_ERR,"ERR:"M_NAME":send_request(): error allocating %d bytes\n",sizeof(enum s_dialog_direction));
00098                 return 0;
00099             }
00100             *cbp=dir;
00101         }   
00102         dialogb.request_inside(&method,&reqbuf,NULL, d,cb,cbp);
00103         return 1;
00104     }
00105     
00106     return 0;
00107 }

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.

Definition at line 121 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(), _p_dialog::hash, _s_dialog::hash, M_NAME, _p_dialog::state, and _s_dialog::state.

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

00122 {       
00123     s_dialog *d;
00124     unsigned int hash;
00125     str call_id;
00126     
00127     enum s_dialog_direction dir;
00128     
00129     
00130     if (!ps->param) return;
00131     dir = *((enum s_dialog_direction *) *(ps->param));
00132     shm_free(*ps->param);
00133     *ps->param = 0;     
00134         
00135     call_id = t->callid;
00136     call_id.s+=9;
00137     call_id.len-=11;
00138 
00139     LOG(L_INFO,"DBG:"M_NAME":confirmed_response(): Received a %d response to BYE for a call release for <%.*s> DIR[%d].\n",
00140         ps->code, call_id.len,call_id.s,dir);
00141             
00142     d = get_s_dialog_dir(call_id,dir);
00143     if (!d) {
00144         LOG(L_ERR,"ERR:"M_NAME":confirmed_response(): Received a BYE response for a call release but there is no dialog for <%.*s> DIR[%d].\n",
00145             call_id.len,call_id.s,dir);
00146         return;
00147     }
00148     
00149     if (ps->code>=200){
00150         if (d->state==DLG_STATE_TERMINATED_ONE_SIDE){
00151             hash=d->hash;
00152             LOG(L_INFO,"INFO:"M_NAME":confirmed_response(): Received a response to second BYE. Dialog is dropped.\n");
00153             del_s_dialog(d);
00154             d_unlock(hash);          
00155         } else {
00156             hash=d->hash;
00157             d->state=DLG_STATE_TERMINATED_ONE_SIDE;
00158             d_unlock(hash);
00159         }       
00160     }   
00161 }

void alter_dialog_route_set ( dlg_t *  d,
enum s_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 172 of file release_call.c.

References DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, NULL, scscf_record_route_mo_uri, and scscf_record_route_mt_uri.

00173 {
00174     rr_t *r,*r_new; 
00175     str p; /*this is going to point to the scscf uri*/
00176             
00177     switch (dir) {
00178         case DLG_MOBILE_ORIGINATING:
00179             p = scscf_record_route_mo_uri;
00180             break;
00181         case DLG_MOBILE_TERMINATING:
00182             p = scscf_record_route_mt_uri;
00183             break;
00184         default:
00185             return;
00186     }
00187         
00188     for(r=d->route_set;r!=NULL;r=r->next) {
00189         if (r->nameaddr.uri.len>=p.len && 
00190             strncasecmp(r->nameaddr.uri.s,p.s,r->nameaddr.uri.len)==0) {
00191             r_new = r->next;
00192             r->next = NULL;
00193             shm_free_rr(&d->route_set);
00194             d->route_set = r_new;               
00195             return;
00196         }           
00197     }   
00198 }

int release_call ( str  callid,
str  reason 
)

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 208 of file release_call.c.

References d_unlock(), DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, get_s_dialog_dir(), _s_dialog::hash, and release_call_s().

00209 {
00210     s_dialog *d=0;
00211     unsigned int hash;
00212     int res = 0;
00213     
00214     d = get_s_dialog_dir(callid,DLG_MOBILE_ORIGINATING);
00215     if (d) {                
00216         hash = d->hash;
00217         if (release_call_s(d,reason)>0) res = 1;        
00218         goto done;      
00219     }
00220     d = get_s_dialog_dir(callid,DLG_MOBILE_TERMINATING);
00221     if (d) {                
00222         hash = d->hash;
00223         if (release_call_s(d,reason)>0) res = 1;        
00224         goto done;
00225     } 
00226     
00227     /*Neither ORGINATING nor TERMINATING is UNKNOWN!*/
00228     /*or doesn't exist*/
00229     /*drop it silently?*/
00230     /*treat it as ORIGINATING or TERMINATING?*/             
00231 done:       
00232     if (d) d_unlock(hash);
00233     return res; 
00234 }

int release_call_s ( s_dialog d,
str  reason 
)

Given an s_dialog, releases the call.

This function is already called with a lock in d after returning d should be unlocked.

Parameters:
d - pointer to the s_dialog structure
reason - Reason header to include
Returns:
-1 if dialog the dialog is not confirmed, 0 on error or 1 on success

Definition at line 245 of file release_call.c.

References alter_dialog_route_set(), _s_dialog::call_id, confirmed_response(), content_length_s, default_reason_s, _s_dialog::dialog_c, _s_dialog::dialog_s, _s_dialog::direction, DLG_MOBILE_ORIGINATING, DLG_MOBILE_TERMINATING, DLG_STATE_CONFIRMED, get_s_dialog_dir_nolock(), _s_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_bye_s, send_request(), _s_dialog::state, and STR_APPEND.

Referenced by release_call(), and terminate_s_dialog().

00246 {
00247     enum s_dialog_direction odir;
00248     s_dialog *o;
00249     str reqbuf={0,0};
00250 
00251     LOG(L_INFO,"DBG:"M_NAME":release_call_s(): Releasing call <%.*s> DIR[%d].\n",
00252         d->call_id.len,d->call_id.s,d->direction);
00253                     
00254     /* As for now, i'm only releasing confirmed dialogs */
00255     if (d->state < DLG_STATE_CONFIRMED){
00256         LOG(L_INFO,"ERR:"M_NAME":release_call_s(): Unable to release a non-confirmed dialog\n");        
00257         return -1;
00258     }
00259         
00260     /* get the dialog in the other direction to see if something going on there and mark as in releasing */
00261     switch (d->direction){
00262         case DLG_MOBILE_ORIGINATING:
00263             odir = DLG_MOBILE_TERMINATING;
00264             break;
00265         case DLG_MOBILE_TERMINATING:
00266             odir = DLG_MOBILE_ORIGINATING;
00267             break;
00268         default:
00269             odir = d->direction;
00270     }   
00271     
00272     o = get_s_dialog_dir_nolock(d->call_id,odir);
00273     if (o && !o->is_releasing) o->is_releasing = 1;
00274         
00275     d->is_releasing++;
00276         
00277     if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE){
00278         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);
00279         
00280         return 0;
00281     }
00282     if (d->is_releasing==1) {   
00283         /*Before generating a request, we have to generate
00284          * the route_set in the dlg , because the route set
00285          * in the dialog is for the UAC everything which was in the 
00286          * Record-Routes (including local address)*/
00287         alter_dialog_route_set(d->dialog_c,d->direction);       
00288         
00289         /*first generate the bye for called user*/
00290         /*then generate the bye for the calling user*/
00291         /*send_bye(d->dialog_c,bye_response,d->direction,reason);
00292         send_bye(d->dialog_s,bye_response,d->direction,reason);*/
00293         
00294         /*now prepare the headers*/
00295         if (reason.len)
00296         {
00297             reqbuf.len = reason.len+content_length_s.len;
00298             reqbuf.s = pkg_malloc(reqbuf.len);
00299             if (!reqbuf.s){
00300                 LOG(L_ERR,"ERR:"M_NAME":release_call_s(): Error allocating %d bytes.\n",
00301                     reqbuf.len);
00302                 return 0;
00303             }       
00304             reqbuf.len=0;
00305             STR_APPEND(reqbuf,reason);
00306             STR_APPEND(reqbuf,content_length_s);
00307             
00308         } else {
00309             reqbuf.len = default_reason_s.len+content_length_s.len;
00310             reqbuf.s = pkg_malloc(reqbuf.len);
00311             if (!reqbuf.s){
00312                 LOG(L_ERR,"ERR:"M_NAME":release_call_s(): Error allocating %d bytes.\n",
00313                     reqbuf.len);
00314                 return 0;
00315             }       
00316             reqbuf.len=0;
00317             STR_APPEND(reqbuf,default_reason_s);
00318             STR_APPEND(reqbuf,content_length_s);
00319         }
00320         
00321         
00322         send_request(method_bye_s,reqbuf,d->dialog_c,confirmed_response,d->direction);
00323         send_request(method_bye_s,reqbuf,d->dialog_s,confirmed_response,d->direction);
00324         
00325         /*the dialog is droped by the callback-function when recieves the two replies */
00326     }
00327     if (reqbuf.s)
00328         pkg_free(reqbuf.s);  
00329     return 1;
00330 }

int release_subscription ( s_dialog d  ) 

Definition at line 342 of file release_call.c.

References alter_dialog_route_set(), _s_dialog::call_id, confirmed_response(), content_length_s, del_s_dialog(), _s_dialog::dialog_c, _s_dialog::dialog_s, _s_dialog::direction, _s_dialog::event, hdr_contact1_s, hdr_contact2_s, hdr_event1_s, hdr_event2_s, hdr_expires_s, hdrs_notify_s, _s_dialog::is_releasing, M_NAME, MAX_TIMES_TO_TRY_TO_RELEASE, method_NOTIFY_s, method_SUBSCRIBE_s, send_request(), and STR_APPEND.

Referenced by terminate_s_dialog().

00343 {
00344     /*i dont think in this case all the checking with the directions is needed
00345      * because the SUBSCRIBE initiated dialog doesnt go twice through the S-CSCF or does it?*/
00346     str reqbuf={0,0};
00347     str c_uri={0,0}; 
00348     d->is_releasing++;
00349     
00350     if (d->is_releasing>MAX_TIMES_TO_TRY_TO_RELEASE)
00351     {
00352         LOG(L_ERR,"ERR:"M_NAME":release_subscription(): had to delete silently a SUBSCRIBE initiated dialog %.*s\n",d->call_id.len,d->call_id.s);
00353         del_s_dialog(d);
00354         return 1;
00355     }
00356     if (d->is_releasing==1)
00357     {
00358         d->dialog_c->state=DLG_CONFIRMED;
00359         alter_dialog_route_set(d->dialog_c,d->direction);
00360         
00361         //SUBSCRIBE
00362         /*Add Contents-Length thing makes everything more complicated*/
00363         c_uri = d->dialog_s->rem_target;
00364         reqbuf.len = hdr_expires_s.len+content_length_s.len;
00365         if (d->event.len) 
00366             reqbuf.len+=hdr_event1_s.len+d->event.len+hdr_event2_s.len;         
00367         if (c_uri.len) 
00368             reqbuf.len+=hdr_contact1_s.len+c_uri.len+hdr_contact2_s.len;            
00369         reqbuf.s=pkg_malloc(reqbuf.len);
00370         if (!reqbuf.s){
00371             LOG(L_ERR,"ERR:"M_NAME":release_subscription(): Error allocating %d bytes.\n",
00372                 reqbuf.len);
00373             return 0;
00374         }
00375         reqbuf.len=0;
00376         STR_APPEND(reqbuf,hdr_expires_s);
00377         if (d->event.len){
00378             STR_APPEND(reqbuf,hdr_event1_s);
00379             STR_APPEND(reqbuf,d->event);            
00380             STR_APPEND(reqbuf,hdr_event2_s);
00381         }
00382         if (c_uri.len){
00383             STR_APPEND(reqbuf,hdr_contact1_s);
00384             STR_APPEND(reqbuf,c_uri);           
00385             STR_APPEND(reqbuf,hdr_contact2_s);
00386         }
00387         STR_APPEND(reqbuf,content_length_s);
00388         
00389         send_request(method_SUBSCRIBE_s,reqbuf,d->dialog_c,confirmed_response,d->direction);
00390         if (reqbuf.s)
00391             pkg_free(reqbuf.s);
00392         
00393         //NOTIFY    
00394         /*Now add the Contents-Length thing for the NOTIFY*/
00395         c_uri = d->dialog_c->rem_target;
00396         reqbuf.len = hdrs_notify_s.len+content_length_s.len;
00397         if (d->event.len) 
00398             reqbuf.len+=hdr_event1_s.len+d->event.len+hdr_event2_s.len;
00399         if (c_uri.len) 
00400             reqbuf.len+=hdr_contact1_s.len+c_uri.len+hdr_contact2_s.len;            
00401         reqbuf.s = pkg_malloc(reqbuf.len);
00402         if (!reqbuf.s){
00403             LOG(L_ERR,"ERR:"M_NAME":release_subscription(): Error allocating %d bytes.\n",
00404                 reqbuf.len);
00405             return 0;
00406         }       
00407         reqbuf.len=0;
00408         STR_APPEND(reqbuf,hdrs_notify_s);
00409         if (d->event.len){
00410             STR_APPEND(reqbuf,hdr_event1_s);
00411             STR_APPEND(reqbuf,d->event);            
00412             STR_APPEND(reqbuf,hdr_event2_s);
00413         }
00414         if (c_uri.len){
00415             STR_APPEND(reqbuf,hdr_contact1_s);
00416             STR_APPEND(reqbuf,c_uri);           
00417             STR_APPEND(reqbuf,hdr_contact2_s);
00418         }   
00419         STR_APPEND(reqbuf,content_length_s);
00420         
00421         send_request(method_NOTIFY_s,reqbuf,d->dialog_s,confirmed_response,d->direction);
00422         if (reqbuf.s)
00423             pkg_free(reqbuf.s);
00424     }
00425     return 1;
00426 }


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 scscf_record_route_mo_uri

just the record route uri for Mobile Originating

Definition at line 160 of file mod.c.

str scscf_record_route_mt_uri

just the record route uri for Mobile Terminating

Definition at line 161 of file mod.c.

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

Definition at line 70 of file release_call.c.

Referenced by release_call_s().

str default_reason_s = {"Reason: SIP ;cause=503 ;text=\"Session Terminated\"\r\n",51} [static]

Definition at line 71 of file release_call.c.

Referenced by release_call_s().

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

Definition at line 72 of file release_call.c.

str hdrs_notify_s = {"Subscription-State: terminated\r\n",32} [static]

Definition at line 332 of file release_call.c.

Referenced by release_subscription().

str method_NOTIFY_s = {"NOTIFY",6} [static]

Definition at line 333 of file release_call.c.

Referenced by release_subscription().

str hdr_expires_s = {"Expires: 0\r\n",12} [static]

Definition at line 334 of file release_call.c.

Referenced by release_subscription().

str hdr_event1_s = {"Event: ",7} [static]

Definition at line 335 of file release_call.c.

Referenced by release_subscription().

str hdr_event2_s = {"\r\n",2} [static]

Definition at line 336 of file release_call.c.

Referenced by release_subscription().

str hdr_contact1_s = {"Contact: <",10} [static]

Definition at line 337 of file release_call.c.

Referenced by release_subscription().

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

Definition at line 338 of file release_call.c.

Referenced by release_subscription().

str method_SUBSCRIBE_s = {"SUBSCRIBE",9} [static]

Definition at line 339 of file release_call.c.

Referenced by release_subscription().


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