dlg_state.c

Go to the documentation of this file.
00001 /*
00002  * $Id: dlg_state.c 554 2008-04-17 17:54:56Z 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  
00056 #include <time.h>
00057 
00058 #include "dlg_state.h"
00059 #include "../tm/tm_load.h"
00060 #include "../sl/sl_funcs.h"
00061 #include "../../mem/shm_mem.h"
00062 #include "../../parser/parse_rr.h"
00063 
00064 #include "sip.h"
00065 #include "release_call.h"
00066 #include "ims_pm.h"
00067 
00068 extern struct tm_binds tmb;
00069 
00070 int s_dialogs_hash_size;                        
00071 s_dialog_hash_slot *s_dialogs=0;                
00072 extern int scscf_dialogs_expiration_time;       
00073 extern int scscf_dialogs_enable_release;    
00075 extern str scscf_name_str;
00076 extern str scscf_record_route_mo;               
00077 extern str scscf_record_route_mt;               
00078 extern str scscf_record_route_mo_uri;           
00079 extern str scscf_record_route_mt_uri;           
00081 time_t d_time_now;                              
00083 extern int scscf_min_se;
00084 
00085 int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2); 
00086 int supports_extension(struct sip_msg *m, str *extension);
00087 int requires_extension(struct sip_msg *m, str *extension);
00088 
00089 
00090 #define strtotime(src,dest) \
00091 {\
00092     int i;\
00093     (dest)=0;\
00094     for(i=0;i<(src).len;i++)\
00095         if ((src).s[i]>='0' && (src).s[i]<='9')\
00096             (dest) = (dest)*10 + (src).s[i] -'0';\
00097 }
00098 
00099 #define FParam_INT(val) { \
00100      .v = { \
00101         .i = val \
00102      },\
00103     .type = FPARAM_INT, \
00104     .orig = "int_value", \
00105 };
00106 
00107 #define FParam_STRING(val) { \
00108     .v = { \
00109         .str = STR_STATIC_INIT(val) \
00110     },\
00111     .type = FPARAM_STR, \
00112     .orig = val, \
00113 };
00114 
00115 
00121 inline unsigned int get_s_dialog_hash(str call_id)
00122 {
00123     if (call_id.len==0) return 0;
00124 #define h_inc h+=v^(v>>3)
00125     char* p;
00126     register unsigned v;
00127     register unsigned h;
00128     
00129     h=0;
00130     for (p=call_id.s; p<=(call_id.s+call_id.len-4); p+=4){
00131         v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00132         h_inc;
00133     }
00134     v=0;
00135     for (;p<(call_id.s+call_id.len); p++) {
00136         v<<=8;
00137         v+=*p;
00138     }
00139     h_inc;
00140     
00141     h=((h)+(h>>11))+((h>>13)+(h>>23));
00142     return (h)%s_dialogs_hash_size;
00143 #undef h_inc 
00144 }
00145 
00151 int s_dialogs_init(int hash_size)
00152 {
00153     int i;
00154     
00155     s_dialogs_hash_size = hash_size;
00156     s_dialogs = shm_malloc(sizeof(s_dialog_hash_slot)*s_dialogs_hash_size);
00157 
00158     if (!s_dialogs) return 0;
00159 
00160     memset(s_dialogs,0,sizeof(s_dialog_hash_slot)*s_dialogs_hash_size);
00161     
00162     for(i=0;i<s_dialogs_hash_size;i++){
00163         s_dialogs[i].lock = lock_alloc();
00164         if (!s_dialogs[i].lock){
00165             LOG(L_ERR,"ERR:"M_NAME":d_hash_table_init(): Error creating lock\n");
00166             return 0;
00167         }
00168         s_dialogs[i].lock = lock_init(s_dialogs[i].lock);
00169     }
00170             
00171     return 1;
00172 }
00173 
00177 void s_dialogs_destroy()
00178 {
00179     int i;
00180     s_dialog *d,*nd;
00181     for(i=0;i<s_dialogs_hash_size;i++){
00182         d_lock(i);
00183             d = s_dialogs[i].head;
00184             while(d){
00185                 nd = d->next;
00186                 free_s_dialog(d);
00187                 d = nd;
00188             }
00189         d_unlock(i);
00190         lock_dealloc(s_dialogs[i].lock);
00191     }
00192     shm_free(s_dialogs);
00193 }
00194 
00199 inline void d_lock(unsigned int hash)
00200 {
00201 //  LOG(L_CRIT,"GET %d\n",hash);
00202     lock_get(s_dialogs[(hash)].lock);
00203 //  LOG(L_CRIT,"GOT %d\n",hash);    
00204 }
00205 
00210 inline void d_unlock(unsigned int hash)
00211 {
00212     lock_release(s_dialogs[(hash)].lock);
00213 //  LOG(L_CRIT,"RELEASED %d\n",hash);   
00214 }
00215 
00220 inline int d_act_time()
00221 {
00222     d_time_now=time(0);
00223     return d_time_now;
00224 }
00225 
00226 extern int* scscf_dialog_count;
00227 extern int scscf_max_dialog_count;
00228 extern gen_lock_t* scscf_dialog_count_lock;
00229 
00233 inline void s_dialog_count_lock()
00234 {
00235     lock_get(scscf_dialog_count_lock);
00236 }
00237 
00241 inline void s_dialog_count_unlock()
00242 {
00243         lock_release(scscf_dialog_count_lock);
00244 }
00245 
00246 
00251 inline int s_dialog_count_increment ()
00252 {
00253     if (scscf_max_dialog_count<0) return 1;
00254     s_dialog_count_lock();  
00255     if (*scscf_dialog_count<scscf_max_dialog_count){
00256         (*scscf_dialog_count)++;
00257         s_dialog_count_unlock();
00258         return 1;
00259     } else {
00260         s_dialog_count_unlock();
00261         return 0;
00262     }
00263     LOG(L_DBG,"DBG:"M_NAME":s_dialog_count_increment(): P-CSCF Dialog counter value is %d\n", *scscf_dialog_count);
00264 }
00265 
00269 inline void s_dialog_count_decrement()
00270 {
00271     if (scscf_max_dialog_count<0) return ;
00272     s_dialog_count_lock();
00273     (*scscf_dialog_count)--;
00274     s_dialog_count_unlock();
00275     LOG(L_DBG,"DBG:"M_NAME":s_dialog_count_decrement(): P-CSCF Dialog counter value is %d\n", *scscf_dialog_count);    
00276 }
00277 
00278 
00287 s_dialog* new_s_dialog(str call_id,str aor, enum s_dialog_direction dir)
00288 {
00289     s_dialog *d;
00290     
00291     if (!s_dialog_count_increment()) return 0;
00292     d = shm_malloc(sizeof(s_dialog));
00293     if (!d) {
00294         LOG(L_ERR,"ERR:"M_NAME":new_s_dialog(): Unable to alloc %d bytes\n",
00295             sizeof(s_dialog));
00296         goto error;
00297     }
00298     memset(d,0,sizeof(s_dialog));
00299     
00300     d->hash = get_s_dialog_hash(call_id);       
00301     STR_SHM_DUP(d->call_id,call_id,"shm");
00302     STR_SHM_DUP(d->aor,aor,"shm");  
00303     d->direction = dir;
00304     d->is_releasing = 0;
00305     return d;
00306 error:
00307 out_of_memory:
00308     if (d){
00309         shm_free(d);        
00310     }
00311     s_dialog_count_decrement();
00312     return 0;
00313 }
00314 
00324 s_dialog* add_s_dialog(str call_id,str aor,enum s_dialog_direction dir)
00325 {
00326     s_dialog *d;
00327     
00328     d = new_s_dialog(call_id,aor,dir);
00329     if (!d) return 0;       
00330     
00331     d_lock(d->hash);
00332         d->next = 0;
00333         d->prev = s_dialogs[d->hash].tail;
00334         if (d->prev) d->prev->next = d;
00335         s_dialogs[d->hash].tail = d;
00336         if (!s_dialogs[d->hash].head) s_dialogs[d->hash].head = d;
00337 
00338         return d;
00339 }
00340 
00347 int is_s_dialog(str call_id,str aor,enum s_dialog_direction dir)
00348 {
00349     s_dialog *d=0;
00350     unsigned int hash = get_s_dialog_hash(call_id);
00351 
00352     d_lock(hash);
00353         d = s_dialogs[hash].head;
00354         while(d){
00355                 if (d->direction == dir &&
00356                     d->aor.len == aor.len &&
00357                     d->call_id.len == call_id.len &&
00358                     strncasecmp(d->aor.s,aor.s,aor.len)==0 &&
00359                     strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00360                     d_unlock(hash);
00361                     return 1;
00362                 }
00363             d = d->next;
00364         }
00365     d_unlock(hash);
00366     return 0;
00367 }
00368 
00375 int is_s_dialog_dir(str call_id,enum s_dialog_direction dir)
00376 {
00377     s_dialog *d=0;
00378     unsigned int hash = get_s_dialog_hash(call_id);
00379 
00380     d_lock(hash);
00381         d = s_dialogs[hash].head;
00382         while(d){
00383                 if (d->direction == dir &&
00384                 d->call_id.len == call_id.len &&
00385                 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00386                     d_unlock(hash);
00387                     return 1;
00388                 }
00389             d = d->next;
00390         }
00391     d_unlock(hash);
00392     return 0;
00393 }
00394 
00402 s_dialog* get_s_dialog(str call_id,str aor)
00403 {
00404     s_dialog *d=0;
00405     unsigned int hash = get_s_dialog_hash(call_id);
00406 
00407     d_lock(hash);
00408         d = s_dialogs[hash].head;
00409         while(d){
00410             if (d->aor.len == aor.len &&
00411                 d->call_id.len == call_id.len &&
00412                 strncasecmp(d->aor.s,aor.s,aor.len)==0 &&
00413                 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00414                     return d;
00415                 }
00416             d = d->next;
00417         }
00418     d_unlock(hash);
00419     return 0;
00420 }
00421 
00429 s_dialog* get_s_dialog_dir(str call_id,enum s_dialog_direction dir)
00430 {
00431     s_dialog *d=0;
00432     unsigned int hash = get_s_dialog_hash(call_id);
00433 
00434     d_lock(hash);
00435         d = s_dialogs[hash].head;
00436         while(d){
00437             if (d->direction == dir &&
00438                 d->call_id.len == call_id.len &&
00439                 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00440                     return d;
00441                 }
00442             d = d->next;
00443         }
00444     d_unlock(hash);
00445     return 0;
00446 }
00447 
00455 s_dialog* get_s_dialog_dir_nolock(str call_id,enum s_dialog_direction dir)
00456 {
00457     s_dialog *d=0;
00458     unsigned int hash = get_s_dialog_hash(call_id);
00459 
00460     d = s_dialogs[hash].head;
00461     while(d){
00462         if (d->direction == dir &&
00463             d->call_id.len == call_id.len &&
00464             strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00465                 return d;
00466             }
00467         d = d->next;
00468     }
00469     return 0;
00470 }
00471 
00472 static str Reason={"Reason: SIP ;cause=503 ;text=\"Session Time-out on S-CSCF\"\r\n",59};
00479 int terminate_s_dialog(s_dialog *d)
00480 {
00481     if (!scscf_dialogs_enable_release) return 0;    
00482     switch (d->method){
00483         case DLG_METHOD_INVITE:
00484             if (release_call_s(d,Reason)<=0){
00485                 //dialog has expired and not confirmed
00486                 // or error releasing dialog
00487                 del_s_dialog(d);
00488             }
00489             return 1;
00490             break;
00491         case DLG_METHOD_SUBSCRIBE:
00492             if (!release_subscription(d)){
00493                 //error releasing the subscription - just drop silently
00494                 del_s_dialog(d);
00495             }
00496             return 1;
00497             break;
00498         default:
00499             LOG(L_ERR,"ERR:"M_NAME":terminate_s_dialog(): Not implemented yet for method[%d]!\n",d->method);
00500             return 0;
00501     }
00502 }
00503 
00509 void del_s_dialog(s_dialog *d)
00510 {
00511     LOG(L_INFO,"DBG:"M_NAME":del_s_dialog(): Deleting dialog <%.*s> DIR[%d]\n",d->call_id.len,d->call_id.s,d->direction);
00512     if (d->prev) d->prev->next = d->next;
00513     else s_dialogs[d->hash].head = d->next;
00514     if (d->next) d->next->prev = d->prev;
00515     else s_dialogs[d->hash].tail = d->prev;
00516     free_s_dialog(d);
00517 }
00518 
00519 
00524 void free_s_dialog(s_dialog *d)
00525 {
00526     if (!d) return;
00527     if (d->call_id.s) shm_free(d->call_id.s);
00528     if (d->aor.s) shm_free(d->aor.s);   
00529     if (d->method_str.s) shm_free(d->method_str.s);
00530     if (d->dialog_s) tmb.free_dlg(d->dialog_s);
00531     if (d->dialog_c) tmb.free_dlg(d->dialog_c);
00532     if (d->refresher.s) shm_free(d->refresher.s);       
00533     if (d->event.s) shm_free(d->event.s);       
00534     shm_free(d);
00535     s_dialog_count_decrement();     
00536 }
00537 
00542 void print_s_dialogs(int log_level)
00543 {
00544     s_dialog *d;
00545     int i;
00546     if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */
00547     d_act_time();
00548     LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List begin --------------\n");
00549     for(i=0;i<s_dialogs_hash_size;i++){
00550         d_lock(i);
00551             d = s_dialogs[i].head;
00552             while(d){
00553                 LOG(log_level,"INF:"M_NAME":[%4d] Dir["ANSI_MAGENTA"%d"ANSI_GREEN
00554                     "] Call-ID:<"ANSI_BLUE"%.*s"ANSI_GREEN
00555                     "> AOR:<"ANSI_RED"%.*s"ANSI_GREEN
00556                     ">\n",i,                
00557                     d->direction,
00558                     d->call_id.len,d->call_id.s,
00559                     d->aor.len,d->aor.s);
00560                 LOG(log_level,"INF:"M_NAME":\t\tMethod:["ANSI_MAGENTA"%d"ANSI_GREEN
00561                     "] State:["ANSI_MAGENTA"%d"ANSI_GREEN
00562                     "] Exp:["ANSI_MAGENTA"%4d"ANSI_GREEN"] Ref:["ANSI_MAGENTA"%.*s"ANSI_GREEN"] Event:["ANSI_MAGENTA"%.*s"ANSI_GREEN"]\n",              
00563                     d->method,
00564                     d->state,
00565                     (int)(d->expires - d_time_now),
00566                     d->refresher.len,d->refresher.s,
00567                     d->event.len,d->event.s);
00568                     
00569                 d = d->next;
00570             }       
00571         d_unlock(i);
00572     }
00573     LOG(log_level,"INF:"M_NAME":----------  S-CSCF Dialog List end   --------------\n");    
00574 }
00575 
00576 
00577 
00583 enum s_dialog_direction get_dialog_direction(char *direction)
00584 {
00585     switch(direction[0]){
00586         case 'o':
00587         case 'O':
00588         case '0':
00589             return DLG_MOBILE_ORIGINATING;
00590         case 't':
00591         case 'T':
00592         case '1':
00593             return DLG_MOBILE_TERMINATING;
00594         default:
00595             LOG(L_CRIT,"ERR:"M_NAME":get_dialog_direction(): Unknown direction %s",direction);
00596             return DLG_MOBILE_UNKNOWN;
00597     }
00598 }
00606 static inline int find_dialog_aor(struct sip_msg *msg,enum s_dialog_direction d,str *aor)
00607 {
00608     if (msg->first_line.type!=SIP_REQUEST)
00609         return 0;
00610     switch(d){
00611         case DLG_MOBILE_ORIGINATING:
00612             *aor = cscf_get_asserted_identity(msg); 
00613             if (!aor->len) return 0;
00614             return 1;
00615             break;
00616         case DLG_MOBILE_TERMINATING:
00617             *aor = cscf_get_called_party_id(msg,0); 
00618             if (!aor->len) *aor = cscf_get_identity_from_ruri(msg);
00619             if (!aor->len) return 0;
00620             return 1;
00621             break;
00622         default:
00623             LOG(L_CRIT,"ERR:"M_NAME":find_dialog_aor(): Unknown direction %d",d);
00624             return 0;
00625     }
00626     return 1;
00627 }
00632 static inline enum s_dialog_direction find_dialog_route_dir(struct sip_msg *msg)
00633 {
00634     str r;  
00635     r = cscf_get_first_route(msg,0);
00636     
00637 //  LOG(L_ERR,"DBG:"M_NAME":find_dialog_route_dir(): Route <%.*s>\n",r.len,r.s);
00638 //      scscf_record_route_mo_uri.len,scscf_record_route_mo_uri.s,
00639 //      scscf_record_route_mt_uri.len,scscf_record_route_mt_uri.s);
00640     
00641     if (!r.len) return DLG_MOBILE_UNKNOWN;
00642     
00643     if (r.len >= scscf_record_route_mo_uri.len &&
00644         strncasecmp(r.s,scscf_record_route_mo_uri.s,scscf_record_route_mo_uri.len)==0){
00645         return DLG_MOBILE_ORIGINATING;
00646     }
00647     if (r.len >= scscf_record_route_mt_uri.len &&
00648         strncasecmp(r.s,scscf_record_route_mt_uri.s,scscf_record_route_mt_uri.len)==0){
00649         return DLG_MOBILE_TERMINATING;
00650     }
00651     return DLG_MOBILE_UNKNOWN;
00652 }
00653 
00661 int S_is_in_dialog(struct sip_msg* msg, char* str1, char* str2)
00662 {
00663     str call_id;
00664     enum s_dialog_direction dir = get_dialog_direction(str1);
00665     enum s_dialog_direction dirmsg = find_dialog_route_dir(msg);
00666     
00667 
00668 //  LOG(L_CRIT,"%d - %d\n",dir,dirmsg);
00669     if (dir!=dirmsg) return CSCF_RETURN_FALSE;              
00670             
00671 //  print_s_dialogs(L_ERR);
00672     call_id = cscf_get_call_id(msg,0);
00673     if (!call_id.len){
00674         
00675         return CSCF_RETURN_FALSE;
00676     }
00677     
00678     if (is_s_dialog_dir(call_id,dir))
00679         return CSCF_RETURN_TRUE;
00680     else 
00681         return CSCF_RETURN_FALSE;
00682 }
00683 
00684 
00685 str s_OTHER={"<OTHER>",7};
00686 str s_INVITE={"INVITE",6};
00687 str s_SUBSCRIBE={"SUBSCRIBE",9};
00693 static enum s_dialog_method get_dialog_method(str method)
00694 {
00695     if (method.len == s_INVITE.len &&
00696         strncasecmp(method.s,s_INVITE.s,s_INVITE.len)==0) return DLG_METHOD_INVITE;
00697     if (method.len == s_SUBSCRIBE.len &&
00698         strncasecmp(method.s,s_SUBSCRIBE.s,s_SUBSCRIBE.len)==0) return DLG_METHOD_SUBSCRIBE;
00699     return DLG_METHOD_OTHER;
00700 }
00701 
00702 #ifdef WITH_IMS_PM
00703 
00708 static str get_dialog_method_str(enum s_dialog_method method)
00709 {
00710     switch(method){
00711         case DLG_METHOD_INVITE:
00712             return s_INVITE;
00713         case DLG_METHOD_SUBSCRIBE:
00714             return s_SUBSCRIBE;
00715         default:
00716             return s_OTHER;
00717     }   
00718 }   
00719 #endif
00720 
00721 static fparam_t fp_422 = FParam_INT(422);
00722 static fparam_t fp_se_small = FParam_STRING("Session Interval Too Small");
00723 
00731 int S_422_session_expires(struct sip_msg* msg, char* str1, char* str2)
00732 {
00733     str hdr = {pkg_malloc(32), 0};
00734 
00735     if (!hdr.s) {
00736         LOG(L_ERR, "ERR:"M_NAME":S_422_session_expires(): no memory for hdr\n");
00737         goto error;
00738     }
00739 
00740     hdr.len = snprintf(hdr.s, 31, "Min-SE: %d\r\n", scscf_min_se);
00741 
00742     if (!cscf_add_header_rpl(msg, &hdr)) {
00743         LOG(L_ERR, "ERR:"M_NAME":S_422_session_expires(): Can't add header\n");
00744         goto error;
00745     }
00746     
00747     return sl_reply(msg, (char *)&fp_422, (char *)&fp_se_small);
00748 
00749 error:
00750     if (hdr.s) pkg_free(hdr.s);
00751     return CSCF_RETURN_FALSE;
00752 }
00753 
00754 
00755 static str s_refresher = {"refresher=", 10};
00756 static str str_ext_timer = {"timer", 5};
00757 static str str_min_se = {"Min-SE:",7};
00758 static str str_se = {"Session-Expires:",16}; 
00759 static str str_require = {"Require:",8}; 
00760 
00761 
00769 int S_check_session_expires(struct sip_msg* msg, char* str1, char* str2)
00770 {
00771     time_t t_time;
00772     time_t min_se_time = 0;
00773     str ses_exp = {0,0};
00774     str min_se = {0,0};
00775     str new_min_se = {0,0};
00776     str new_ses_exp = {0,0};
00777     struct hdr_field *h_se, *h_min_se;
00778     str refresher;
00779 
00780     ses_exp = cscf_get_session_expires_body(msg, &h_se);
00781     t_time = cscf_get_session_expires(ses_exp, &refresher);
00782     
00783     if (!t_time || t_time >= scscf_min_se)
00784         return CSCF_RETURN_TRUE;
00785     if (!supports_extension(msg, &str_ext_timer)) //does not suports timer extension
00786     {
00787         //add Min-SE header with its minimum interval
00788         min_se = cscf_get_min_se(msg, &h_min_se);
00789         if (min_se.len) {
00790             strtotime(min_se, min_se_time);
00791             if (min_se_time < scscf_min_se)
00792                 cscf_del_header(msg, h_min_se);
00793             else
00794                 return CSCF_RETURN_TRUE;
00795         }
00796         new_min_se.len = 11/*int value*/ + str_min_se.len+3;
00797         new_min_se.s = pkg_malloc(new_min_se.len+1);
00798         if (!new_min_se.s) {
00799             LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_min_se.len);
00800             goto error;
00801         }
00802         new_min_se.len = snprintf(new_min_se.s, new_min_se.len, "%.*s %d\r\n",str_min_se.len, str_min_se.s, scscf_min_se);
00803         min_se_time = scscf_min_se;
00804         cscf_add_header(msg, &new_min_se, HDR_OTHER_T);
00805         if (t_time < scscf_min_se) {
00806             cscf_del_header(msg, h_se);
00807             new_ses_exp.len = 11 + str_se.len+3;
00808             new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
00809             if (!new_ses_exp.s) {
00810                 LOG(L_ERR,"ERR:"M_NAME":S_check_session_expires: Error allocating %d bytes\n",new_ses_exp.len);
00811                 goto error;
00812             }
00813             new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d\r\n",str_se.len, str_se.s, scscf_min_se);
00814             t_time = scscf_min_se;
00815             cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
00816         }
00817         return CSCF_RETURN_TRUE;
00818     }
00819 error:
00820     if (new_min_se.s) pkg_free(new_min_se.s);
00821     if (new_ses_exp.s) pkg_free(new_ses_exp.s);
00822     return CSCF_RETURN_FALSE;
00823 }       
00824 
00825 
00833 int S_save_dialog(struct sip_msg* msg, char* str1, char* str2)
00834 {
00835     str call_id;
00836     s_dialog *d;
00837     str aor;
00838     char buf1[256],buf2[256];
00839     str uri,tag,ruri,x; 
00840     time_t t_time;
00841     str ses_exp = {0,0};
00842     str refresher = {0,0};
00843     str event = {0,0};
00844     struct hdr_field *h;
00845     unsigned int hash;
00846     
00847     enum s_dialog_direction dir = get_dialog_direction(str1);
00848     
00849     if (!find_dialog_aor(msg,dir,&aor)){
00850         LOG(L_ERR,"ERR:"M_NAME":S_save_dialog(): Error retrieving %s contact\n",str1);
00851         return CSCF_RETURN_BREAK;
00852     }       
00853         
00854     call_id = cscf_get_call_id(msg,0);
00855     if (!call_id.len)
00856         return CSCF_RETURN_FALSE;
00857 
00858     LOG(L_INFO,"DBG:"M_NAME":S_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);
00859 
00860     if (is_s_dialog(call_id,aor,dir)){
00861         LOG(L_ERR,"ERR:"M_NAME":S_save_dialog: dialog already exists!\n");  
00862         return CSCF_RETURN_TRUE;
00863     }
00864     
00865     d = add_s_dialog(call_id,aor,dir);
00866     if (!d) return CSCF_RETURN_FALSE;
00867 
00868     d->method = get_dialog_method(msg->first_line.u.request.method);
00869     STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
00870     d->first_cseq = cscf_get_cseq(msg,0);
00871     d->last_cseq = d->first_cseq;
00872     d->state = DLG_STATE_INITIAL;
00873 
00874     d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
00875 
00876     ses_exp = cscf_get_session_expires_body(msg, &h);
00877     t_time = cscf_get_session_expires(ses_exp, &refresher);
00878     if (!t_time) {
00879         d->expires = d_act_time() + 60;
00880         d->lr_session_expires = 0;
00881     } else {
00882         d->expires = d_act_time() + t_time;
00883         d->lr_session_expires = t_time;
00884         if (refresher.len)
00885             STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
00886     }
00887     
00888     cscf_get_from_tag(msg,&tag);
00889     cscf_get_from_uri(msg,&x);
00890     uri.len = snprintf(buf1,256,"<%.*s>",x.len,x.s);
00891     uri.s = buf1;   
00892     cscf_get_to_uri(msg,&x);
00893     ruri.len = snprintf(buf2,256,"<%.*s>",x.len,x.s);
00894     ruri.s = buf2;
00895      
00896     tmb.new_dlg_uac(&call_id,
00897                         &tag,
00898                         d->first_cseq,&uri,
00899                         &ruri,
00900                         &d->dialog_c);
00901     
00902     tmb.new_dlg_uas(msg,99,&d->dialog_s);
00903     
00904     event = cscf_get_event(msg);
00905     if (event.len){
00906         STR_SHM_DUP(d->event,event,"shm");
00907     }
00908     else
00909         d->event = event;
00910 
00911     d_unlock(d->hash);
00912     
00913     print_s_dialogs(L_INFO);
00914     
00915     return CSCF_RETURN_TRUE;    
00916 out_of_memory:
00917     if (d){
00918         hash = d->hash;
00919         del_s_dialog(d);
00920         d_unlock(hash);
00921     }
00922     return CSCF_RETURN_ERROR;   
00923 }
00924 
00931 int update_dialog_on_reply(struct sip_msg *msg, s_dialog *d)
00932 {
00933     struct hdr_field *h_req;
00934     struct hdr_field *h=0;
00935     int res=0;
00936     time_t t_time=0;
00937     str ses_exp = {0,0};
00938     str refresher = {0,0};
00939     str new_ses_exp = {0,0};
00940     str new_ext = {0,0};
00941     int expires = 0;
00942 
00943     ses_exp = cscf_get_session_expires_body(msg, &h);
00944     t_time = cscf_get_session_expires(ses_exp, &refresher);
00945     if (!t_time) //i.e not session-expires header in response
00946     {
00947         if (!d->uac_supp_timer || !d->lr_session_expires)
00948         {
00949             expires = cscf_get_expires_hdr(msg);
00950             if (expires >= 0)
00951             {
00952                  d->expires = d_act_time()+expires;
00953             }
00954             else
00955             {
00956                  d->expires = d_act_time()+scscf_dialogs_expiration_time;
00957             }
00958         }
00959         else// uac supports timer, but no session-expires header found in response
00960         {
00961             d->expires = d_act_time()+d->lr_session_expires;
00962             
00963             new_ses_exp.len = 11/*int value*/ + str_se.len+s_refresher.len+8;
00964             new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
00965             if (!new_ses_exp.s) {
00966                 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ses_exp.len);
00967                 goto error;
00968             }
00969             new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d; %.*suac\r\n",str_se.len, str_se.s, (int)d->lr_session_expires ,s_refresher.len, s_refresher.s);
00970             cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
00971             if (!requires_extension(msg, &str_ext_timer)) //must have require timer extenstion
00972             {
00973                 /* walk through all Require headers to find first require header*/
00974                 res = parse_headers(msg, HDR_EOH_F, 0);
00975                 if (res == -1) {
00976                     ERR("Error while parsing headers (%d)\n", res);
00977                     return 0; /* what to return here ? */
00978                 }
00979                 
00980                 h_req = msg->require;
00981                 while (h_req) {
00982                     if (h_req->type == HDR_REQUIRE_T) {
00983                         if (h_req->body.s[new_ext.len-1]=='\n')
00984                         {
00985                             new_ext.len = str_require.len + 1/* */+h_req->body.len + 7;/*, timer*/
00986                             new_ext.s = pkg_malloc(new_ext.len);
00987                             if (!new_ext.s) {
00988                                 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
00989                                 goto error;
00990                             }           
00991                             new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len-2, h_req->body.s);
00992                         }
00993                         else
00994                         {
00995                             new_ext.len = str_require.len + 1/*space*/ + h_req->body.len + 9;/*, timer\r\n*/
00996                             new_ext.s = pkg_malloc(new_ext.len);
00997                             if (!new_ext.s) {
00998                                 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
00999                                 goto error;
01000                             }           
01001                             new_ext.len = snprintf(new_ext.s, str_require.len, "%.*s %.*s, timer\r\n", str_require.len, str_require.s, h_req->body.len, h_req->body.s);
01002                         }
01003                         cscf_del_header(msg, h_req);
01004                         cscf_add_header(msg, &new_ext, HDR_REQUIRE_T);
01005                         break;
01006                     }
01007                     h_req = h_req->next;
01008                 }
01009             }
01010         }
01011     }
01012     else{
01013         d->expires = d_act_time() + t_time;
01014         d->lr_session_expires = t_time;
01015     }
01016     return 1;
01017 error:
01018     if (new_ses_exp.s) pkg_free(new_ses_exp.s);
01019     if (new_ext.s) pkg_free(new_ext.s);
01020     return 0;   
01021 }
01022 
01038 int S_update_dialog(struct sip_msg* msg, char* str1, char* str2)
01039 {
01040     str call_id;
01041     s_dialog *d;
01042     int response;
01043     int cseq;
01044 
01045     struct hdr_field *h=0;
01046     struct sip_msg *req=0;
01047     int expires=0;
01048     str totag;
01049     time_t t_time;
01050     str ses_exp = {0,0};
01051     str refresher = {0,0};
01052 
01053     enum s_dialog_direction dir = get_dialog_direction(str1);
01054         
01055 //  if (!find_dialog_aor(msg,str1,&aor)){
01056 //      req = cscf_get_request_from_reply(msg);     
01057 //      if (!find_dialog_aor(req,str1,&aor)){
01058 //          LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
01059 //          return CSCF_RETURN_BREAK;
01060 //      }
01061 //  }       
01062         
01063     call_id = cscf_get_call_id(msg,0);
01064     if (!call_id.len)
01065         return CSCF_RETURN_FALSE;
01066 
01067     LOG(L_DBG,"DBG:"M_NAME":S_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);
01068 
01069     d = get_s_dialog_dir(call_id,dir);
01070 //  if (!d && msg->first_line.type==SIP_REPLY){
01071 //      /* Try to get the dialog from the request */
01072 //      if (!req) req = cscf_get_request_from_reply(msg);       
01073 //      if (!find_dialog_aor(req,str1,&aor)){
01074 //          LOG(L_ERR,"ERR:"M_NAME":S_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
01075 //          return CSCF_RETURN_BREAK;
01076 //      }       
01077 //      d = get_s_dialog_dir(call_id,aor);      
01078 //  }
01079     if (!d){
01080         LOG(L_INFO,"INFO:"M_NAME