release_call.c

Go to the documentation of this file.
00001 /*
00002  * $Id: release_call.c 487 2007-11-07 16:51:17Z vingarzan $
00003  *  
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  * 
00025  * It has to be noted that this Open Source IMS Core System is not 
00026  * intended to become or act as a product in a commercial context! Its 
00027  * sole purpose is to provide an IMS core reference implementation for 
00028  * IMS technology testing and IMS application prototyping for research 
00029  * purposes, typically performed in IMS test-beds.
00030  * 
00031  * Users of the Open Source IMS Core System have to be aware that IMS
00032  * technology may be subject of patents and licence terms, as being 
00033  * specified within the various IMS-related IETF, ITU-T, ETSI, and 3GPP
00034  * standards. Thus all Open IMS Core users have to take notice of this 
00035  * fact and have to agree to check out carefully before installing, 
00036  * using and extending the Open Source IMS Core System, if related 
00037  * patents and licences may become applicable to the intended usage 
00038  * context.  
00039  *
00040  * You should have received a copy of the GNU General Public License
00041  * along with this program; if not, write to the Free Software
00042  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00043  * 
00044  */
00045  
00046 
00058 #include "release_call.h"
00059 #include "sip.h"
00060 
00061 extern struct tm_binds tmb; 
00062 extern dlg_func_t dialogb;  
00063 
00064 extern str scscf_record_route_mo_uri;
00065 extern str scscf_record_route_mt_uri;
00066 
00067 
00068 
00069 
00070 static str method_bye_s={"BYE",3};
00071 static str default_reason_s={"Reason: SIP ;cause=503 ;text=\"Session Terminated\"\r\n",51};
00072 static str content_length_s={"Content-Length: 0\r\n",19};
00073 
00083 int send_request(str method,str reqbuf,dlg_t *d,transaction_cb cb, enum s_dialog_direction dir)
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 }
00108 
00109 
00110 
00111 
00112 
00113 
00114 
00115 
00121 void confirmed_response(struct cell *t,int type,struct tmcb_params *ps)
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 }
00162 
00163 
00164 
00172 void alter_dialog_route_set(dlg_t *d,enum s_dialog_direction dir)
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 }
00199 
00200 
00208 int release_call(str callid,str reason)
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 }
00235 
00236 
00245 int release_call_s(s_dialog *d,str reason)
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 }
00331 
00332 static str hdrs_notify_s={"Subscription-State: terminated\r\n",32};
00333 static str method_NOTIFY_s={"NOTIFY",6};
00334 static str hdr_expires_s={"Expires: 0\r\n",12};
00335 static str hdr_event1_s={"Event: ",7};
00336 static str hdr_event2_s={"\r\n",2};
00337 static str hdr_contact1_s={"Contact: <",10};
00338 static str hdr_contact2_s={">\r\n",3};
00339 static str method_SUBSCRIBE_s={"SUBSCRIBE",9};
00340 
00341 
00342 int release_subscription(s_dialog *d)
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 }
00427 

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