00001
00055 #include <time.h>
00056
00057 #include "dlg_state.h"
00058
00059 #include "../../mem/shm_mem.h"
00060 #include "../sl/sl_funcs.h"
00061
00062 #include "sip.h"
00063 #include "release_call.h"
00064 #include "ims_pm.h"
00065
00066 int p_dialogs_hash_size;
00067 p_dialog_hash_slot *p_dialogs=0;
00069 extern int pcscf_dialogs_expiration_time;
00070 extern int pcscf_dialogs_enable_release;
00071 time_t d_time_now;
00073 extern str pcscf_record_route_mo;
00074 extern str pcscf_record_route_mo_uri;
00075 extern str pcscf_record_route_mt;
00076 extern str pcscf_record_route_mt_uri;
00078 extern str pcscf_name_str;
00080 extern struct tm_binds tmb;
00081 extern int pcscf_min_se;
00082
00083
00084 int (*sl_reply)(struct sip_msg* _msg, char* _str1, char* _str2);
00085 int supports_extension(struct sip_msg *m, str *extension);
00086 int requires_extension(struct sip_msg *m, str *extension);
00087
00088 #define strtotime(src,dest) \
00089 {\
00090 int i;\
00091 (dest)=0;\
00092 for(i=0;i<(src).len;i++)\
00093 if ((src).s[i]>='0' && (src).s[i]<='9')\
00094 (dest) = (dest)*10 + (src).s[i] -'0';\
00095 }
00096
00097
00098 #define FParam_INT(val) { \
00099 .v = { \
00100 .i = val \
00101 },\
00102 .type = FPARAM_INT, \
00103 .orig = "int_value", \
00104 };
00105
00106 #define FParam_STRING(val) { \
00107 .v = { \
00108 .str = STR_STATIC_INIT(val) \
00109 },\
00110 .type = FPARAM_STR, \
00111 .orig = val, \
00112 };
00113
00114
00120 inline unsigned int get_p_dialog_hash(str call_id)
00121 {
00122 if (call_id.len==0) return 0;
00123 #define h_inc h+=v^(v>>3)
00124 char* p;
00125 register unsigned v;
00126 register unsigned h;
00127
00128 h=0;
00129 for (p=call_id.s; p<=(call_id.s+call_id.len-4); p+=4){
00130 v=(*p<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
00131 h_inc;
00132 }
00133 v=0;
00134 for (;p<(call_id.s+call_id.len); p++) {
00135 v<<=8;
00136 v+=*p;
00137 }
00138 h_inc;
00139
00140 h=((h)+(h>>11))+((h>>13)+(h>>23));
00141 return (h)%p_dialogs_hash_size;
00142 #undef h_inc
00143 }
00144
00150 int p_dialogs_init(int hash_size)
00151 {
00152 int i;
00153
00154 p_dialogs_hash_size = hash_size;
00155 p_dialogs = shm_malloc(sizeof(p_dialog_hash_slot)*p_dialogs_hash_size);
00156
00157 if (!p_dialogs) return 0;
00158
00159 memset(p_dialogs,0,sizeof(p_dialog_hash_slot)*p_dialogs_hash_size);
00160
00161 for(i=0;i<p_dialogs_hash_size;i++){
00162 p_dialogs[i].lock = lock_alloc();
00163 if (!p_dialogs[i].lock){
00164 LOG(L_ERR,"ERR:"M_NAME":d_hash_table_init(): Error creating lock\n");
00165 return 0;
00166 }
00167 p_dialogs[i].lock = lock_init(p_dialogs[i].lock);
00168 }
00169
00170 return 1;
00171 }
00172
00176 void p_dialogs_destroy()
00177 {
00178 int i;
00179 p_dialog *d,*nd;
00180 for(i=0;i<p_dialogs_hash_size;i++){
00181 d_lock(i);
00182 d = p_dialogs[i].head;
00183 while(d){
00184 nd = d->next;
00185 free_p_dialog(d);
00186 d = nd;
00187 }
00188 d_unlock(i);
00189 lock_dealloc(p_dialogs[i].lock);
00190 }
00191 shm_free(p_dialogs);
00192 }
00193
00198 inline void d_lock(unsigned int hash)
00199 {
00200
00201 lock_get(p_dialogs[(hash)].lock);
00202
00203 }
00204
00209 inline void d_unlock(unsigned int hash)
00210 {
00211 lock_release(p_dialogs[(hash)].lock);
00212
00213 }
00214
00219 inline int d_act_time()
00220 {
00221 d_time_now=time(0);
00222 return d_time_now;
00223 }
00224
00225 extern int* pcscf_dialog_count;
00226 extern int pcscf_max_dialog_count;
00227 extern gen_lock_t* pcscf_dialog_count_lock;
00228
00232 inline void p_dialog_count_lock()
00233 {
00234 lock_get(pcscf_dialog_count_lock);
00235 }
00236
00240 inline void p_dialog_count_unlock()
00241 {
00242 lock_release(pcscf_dialog_count_lock);
00243 }
00244
00245
00250 inline int p_dialog_count_increment ()
00251 {
00252 if (pcscf_max_dialog_count<0) return 1;
00253 p_dialog_count_lock();
00254 if (*pcscf_dialog_count<pcscf_max_dialog_count){
00255 (*pcscf_dialog_count)++;
00256 p_dialog_count_unlock();
00257 return 1;
00258 } else {
00259 p_dialog_count_unlock();
00260 return 0;
00261 }
00262 LOG(L_DBG,"DBG:"M_NAME":p_dialog_count_increment(): P-CSCF Dialog counter value is %d\n", *pcscf_dialog_count);
00263 }
00264
00268 inline void p_dialog_count_decrement()
00269 {
00270 if (pcscf_max_dialog_count<0) return ;
00271 p_dialog_count_lock();
00272 (*pcscf_dialog_count)--;
00273 p_dialog_count_unlock();
00274 LOG(L_DBG,"DBG:"M_NAME":p_dialog_count_decrement(): P-CSCF Dialog counter value is %d\n", *pcscf_dialog_count);
00275 }
00276
00277
00287 p_dialog* new_p_dialog(str call_id,str host,int port, int transport)
00288 {
00289 p_dialog *d;
00290
00291 if (!p_dialog_count_increment()) return 0;
00292 d = shm_malloc(sizeof(p_dialog));
00293 if (!d) {
00294 LOG(L_ERR,"ERR:"M_NAME":new_p_dialog(): Unable to alloc %d bytes\n",
00295 sizeof(p_dialog));
00296 goto error;
00297 }
00298 memset(d,0,sizeof(p_dialog));
00299
00300 d->hash = get_p_dialog_hash(call_id);
00301 STR_SHM_DUP(d->call_id,call_id,"shm");
00302 STR_SHM_DUP(d->host,host,"shm");
00303 d->port = port;
00304 d->transport = transport;
00305
00306 return d;
00307 error:
00308 out_of_memory:
00309 if (d){
00310 if (d->call_id.s) shm_free(d->call_id.s);
00311 if (d->host.s) shm_free(d->host.s);
00312 shm_free(d);
00313 }
00314 p_dialog_count_decrement();
00315 return 0;
00316 }
00317
00328 p_dialog* add_p_dialog(str call_id,str host,int port, int transport)
00329 {
00330 p_dialog *d;
00331
00332 d = new_p_dialog(call_id,host,port,transport);
00333 if (!d) return 0;
00334
00335 d_lock(d->hash);
00336 d->next = 0;
00337 d->prev = p_dialogs[d->hash].tail;
00338 if (d->prev) d->prev->next = d;
00339 p_dialogs[d->hash].tail = d;
00340 if (!p_dialogs[d->hash].head) p_dialogs[d->hash].head = d;
00341
00342 return d;
00343 }
00344
00355 int is_p_dialog(str call_id,str host,int port, int transport,enum p_dialog_direction *dir)
00356 {
00357 p_dialog *d=0;
00358 unsigned int hash = get_p_dialog_hash(call_id);
00359
00360 d_lock(hash);
00361 d = p_dialogs[hash].head;
00362 while(d){
00363 if ((!dir || d->direction == *dir) &&
00364 d->port == port &&
00365
00366
00367 d->host.len == host.len &&
00368 d->call_id.len == call_id.len &&
00369 strncasecmp(d->host.s,host.s,host.len)==0 &&
00370 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00371 d_unlock(hash);
00372 return 1;
00373 }
00374 d = d->next;
00375 }
00376 d_unlock(hash);
00377 return 0;
00378 }
00379
00387 int is_p_dialog_dir(str call_id,enum p_dialog_direction dir)
00388 {
00389 p_dialog *d=0;
00390 unsigned int hash = get_p_dialog_hash(call_id);
00391 d_lock(hash);
00392 d = p_dialogs[hash].head;
00393 while(d){
00394 if (d->direction==dir && d->call_id.len == call_id.len &&
00395 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00396 d_unlock(hash);
00397 return 1;
00398 }
00399 d=d->next;
00400 }
00401 d_unlock(hash);
00402 return 0;
00403 }
00404
00415 p_dialog* get_p_dialog(str call_id,str host,int port, int transport,enum p_dialog_direction *dir)
00416 {
00417 p_dialog *d=0;
00418 unsigned int hash = get_p_dialog_hash(call_id);
00419
00420 d_lock(hash);
00421 d = p_dialogs[hash].head;
00422 while(d){
00423 if ((!dir || d->direction == *dir) &&
00424 d->port == port &&
00425
00426
00427 d->host.len == host.len &&
00428 d->call_id.len == call_id.len &&
00429 strncasecmp(d->host.s,host.s,host.len)==0 &&
00430 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00431 return d;
00432 }
00433 d = d->next;
00434 }
00435 d_unlock(hash);
00436 return 0;
00437 }
00438
00445 p_dialog* get_p_dialog_dir(str call_id,enum p_dialog_direction dir)
00446 {
00447 p_dialog *d=0;
00448 unsigned int hash = get_p_dialog_hash(call_id);
00449
00450 d_lock(hash);
00451 d = p_dialogs[hash].head;
00452 while(d){
00453 if (d->direction == dir &&
00454 d->call_id.len == call_id.len &&
00455 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00456 return d;
00457 }
00458 d = d->next;
00459 }
00460 d_unlock(hash);
00461 return 0;
00462 }
00463
00464
00472 p_dialog* get_p_dialog_dir_nolock(str call_id,enum p_dialog_direction dir)
00473 {
00474 p_dialog *d=0;
00475 unsigned int hash = get_p_dialog_hash(call_id);
00476
00477 d = p_dialogs[hash].head;
00478 while(d){
00479 if (d->direction == dir &&
00480 d->call_id.len == call_id.len &&
00481 strncasecmp(d->call_id.s,call_id.s,call_id.len)==0) {
00482 return d;
00483 }
00484 d = d->next;
00485 }
00486 return 0;
00487 }
00488
00489 str reason_terminate_p_dialog_s={"Session terminated in the P-CSCF",32};
00496 int terminate_p_dialog(p_dialog *d)
00497 {
00498 if (!pcscf_dialogs_enable_release) return 0;
00499 switch (d->method){
00500 case DLG_METHOD_INVITE:
00501 if (release_call_p(d,503,reason_terminate_p_dialog_s)==-1){
00502 del_p_dialog(d);
00503 }
00504 return 1;
00505 break;
00506 case DLG_METHOD_SUBSCRIBE:
00507 LOG(L_ERR,"ERR:"M_NAME":terminate_p_dialog(): Not needed for SUBSCRIBE dialogs - silent drop on expiration.\n");
00508 return 0;
00509 break;
00510 default:
00511 LOG(L_ERR,"ERR:"M_NAME":terminate_p_dialog(): Not implemented yet for method[%d]!\n",d->method);
00512 return 0;
00513 }
00514 }
00515
00521 void del_p_dialog(p_dialog *d)
00522 {
00523 if (d->prev) d->prev->next = d->next;
00524 else p_dialogs[d->hash].head = d->next;
00525 if (d->next) d->next->prev = d->prev;
00526 else p_dialogs[d->hash].tail = d->prev;
00527 free_p_dialog(d);
00528 }
00529
00534 void free_p_dialog(p_dialog *d)
00535 {
00536 int i;
00537 if (!d) return;
00538 if (d->call_id.s) shm_free(d->call_id.s);
00539 if (d->host.s) shm_free(d->host.s);
00540 if (d->method_str.s) shm_free(d->method_str.s);
00541 if (d->routes){
00542 for(i=0;i<d->routes_cnt;i++)
00543 shm_free(d->routes[i].s);
00544 shm_free(d->routes);
00545 }
00546 if (d->dialog_s) tmb.free_dlg(d->dialog_s);
00547 if (d->dialog_c) tmb.free_dlg(d->dialog_c);
00548 if (d->refresher.s) shm_free(d->refresher.s);
00549 shm_free(d);
00550 p_dialog_count_decrement();
00551 }
00552
00557 void print_p_dialogs(int log_level)
00558 {
00559 p_dialog *d;
00560 int i,j;
00561 if (debug<log_level) return;
00562 d_act_time();
00563 LOG(log_level,"INF:"M_NAME":---------- P-CSCF Dialog List begin --------------\n");
00564 for(i=0;i<p_dialogs_hash_size;i++){
00565 d_lock(i);
00566 d = p_dialogs[i].head;
00567 while(d){
00568 LOG(log_level,"INF:"M_NAME":[%4d] Dir:["ANSI_MAGENTA"%d"ANSI_GREEN
00569 "]\tCall-ID:<"ANSI_BLUE"%.*s"ANSI_GREEN
00570 ">\tAOR:"ANSI_RED"%d://%.*s:%d"ANSI_GREEN"\n"
00571 ,i,
00572 d->direction,
00573 d->call_id.len,d->call_id.s,
00574 d->transport,d->host.len,d->host.s,d->port);
00575 LOG(log_level,"INF:"M_NAME":\t\tMethod:["ANSI_MAGENTA"%d"ANSI_GREEN
00576 "] State:["ANSI_MAGENTA"%d"ANSI_GREEN
00577 "] Exp:["ANSI_MAGENTA"%4d"ANSI_GREEN"]\n",
00578 d->method,d->state,
00579 (int)(d->expires - d_time_now));
00580 for(j=0;j<d->routes_cnt;j++)
00581 LOG(log_level,"INF:"M_NAME":\t\t RR: <"ANSI_YELLOW"%.*s"ANSI_GREEN">\n",
00582 d->routes[j].len,d->routes[j].s);
00583 d = d->next;
00584 }
00585 d_unlock(i);
00586 }
00587 LOG(log_level,"INF:"M_NAME":---------- P-CSCF Dialog List end --------------\n");
00588 }
00589
00595 static inline enum p_dialog_direction get_dialog_direction(char *direction)
00596 {
00597 if (!direction) {
00598 LOG(L_CRIT,"ERR:"M_NAME":get_dialog_direction(): Unknown direction NULL");
00599 return DLG_MOBILE_UNKNOWN;
00600 }
00601 switch(direction[0]){
00602 case 'o':
00603 case 'O':
00604 case '0':
00605 return DLG_MOBILE_ORIGINATING;
00606 case 't':
00607 case 'T':
00608 case '1':
00609 return DLG_MOBILE_TERMINATING;
00610 default:
00611 LOG(L_CRIT,"ERR:"M_NAME":get_dialog_direction(): Unknown direction %s",direction);
00612 return DLG_MOBILE_UNKNOWN;
00613 }
00614 }
00615
00625 static inline int find_dialog_contact(struct sip_msg *msg,enum p_dialog_direction dir,str *host,int *port,int *transport)
00626 {
00627 switch(dir){
00628 case DLG_MOBILE_ORIGINATING:
00629 if (!cscf_get_originating_contact(msg,host,port,transport))
00630 return 0;
00631 if (*port==0) *port = 5060;
00632 return 1;
00633 case DLG_MOBILE_TERMINATING:
00634 if (!cscf_get_terminating_contact(msg,host,port,transport))
00635 return 0;
00636 if (*port==0) *port = 5060;
00637 return 1;
00638 default:
00639 LOG(L_CRIT,"ERR:"M_NAME":find_dialog_contact(): Unknown direction %d",dir);
00640 return 0;
00641 }
00642 return 1;
00643 }
00644
00652 int P_is_in_dialog(struct sip_msg* msg, char* str1, char* str2)
00653 {
00654 str call_id;
00655 str host;
00656 int port,transport;
00657 enum p_dialog_direction dir;
00658
00659 dir = get_dialog_direction(str1);
00660
00661 if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
00662 LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(%s): Error retrieving %s contact\n",str1,str1);
00663 return CSCF_RETURN_BREAK;
00664 }
00665
00666
00667 call_id = cscf_get_call_id(msg,0);
00668 if (!call_id.len)
00669 return CSCF_RETURN_FALSE;
00670
00671 if (is_p_dialog(call_id,host,port,transport,0)) {
00672 return CSCF_RETURN_TRUE;
00673 }
00674 else
00675 return CSCF_RETURN_FALSE;
00676 }
00677
00678 str s_OTHER={"<OTHER>",7};
00679 str s_INVITE={"INVITE",6};
00680 str s_SUBSCRIBE={"SUBSCRIBE",9};
00686 static enum p_dialog_method get_dialog_method(str method)
00687 {
00688 if (method.len == s_INVITE.len &&
00689 strncasecmp(method.s,s_INVITE.s,s_INVITE.len)==0) return DLG_METHOD_INVITE;
00690 if (method.len == s_SUBSCRIBE.len &&
00691 strncasecmp(method.s,s_SUBSCRIBE.s,s_SUBSCRIBE.len)==0) return DLG_METHOD_SUBSCRIBE;
00692 return DLG_METHOD_OTHER;
00693 }
00694
00695 #ifdef WITH_IMS_PM
00696
00701 static str get_dialog_method_str(enum p_dialog_method method)
00702 {
00703 switch(method){
00704 case DLG_METHOD_INVITE:
00705 return s_INVITE;
00706 case DLG_METHOD_SUBSCRIBE:
00707 return s_SUBSCRIBE;
00708 default:
00709 return s_OTHER;
00710 }
00711 }
00712 #endif
00713
00714 static fparam_t fp_422 = FParam_INT(422);
00715 static fparam_t fp_se_small = FParam_STRING("Session Interval Too Small");
00716
00724 int P_422_session_expires(struct sip_msg* msg, char* str1, char* str2)
00725 {
00726 str hdr = {pkg_malloc(32), 0};
00727
00728 if (!hdr.s) {
00729 LOG(L_ERR, "ERR:"M_NAME":P_422_session_expires(): no memory for hdr\n");
00730 goto error;
00731 }
00732
00733 hdr.len = snprintf(hdr.s, 31, "Min-SE: %d\r\n", pcscf_min_se);
00734
00735 if (!cscf_add_header_rpl(msg, &hdr)) {
00736 LOG(L_ERR, "ERR:"M_NAME":P_422_session_expires(): Can't add header\n");
00737 goto error;
00738 }
00739
00740 return sl_reply(msg, (char *)&fp_422, (char *)&fp_se_small);
00741
00742 error:
00743 if (hdr.s) pkg_free(hdr.s);
00744 return CSCF_RETURN_FALSE;
00745 }
00746
00747
00748 static str s_refresher = {"refresher=", 10};
00749 static str str_ext_timer = {"timer", 5};
00750 static str str_min_se = {"Min-SE:",7};
00751 static str str_se = {"Session-Expires:",16};
00752 static str str_require = {"Require:",8};
00753
00761 int P_check_session_expires(struct sip_msg* msg, char* str1, char* str2)
00762 {
00763 time_t t_time;
00764 time_t min_se_time = 0;
00765 str ses_exp = {0,0};
00766 str min_se = {0,0};
00767 str new_min_se = {0,0};
00768 str new_ses_exp = {0,0};
00769 struct hdr_field *h_se, *h_min_se;
00770 str refresher;
00771
00772 ses_exp = cscf_get_session_expires_body(msg, &h_se);
00773 t_time = cscf_get_session_expires(ses_exp, &refresher);
00774
00775 if (!t_time || t_time >= pcscf_min_se)
00776 return CSCF_RETURN_TRUE;
00777 if (!supports_extension(msg, &str_ext_timer))
00778 {
00779
00780 min_se = cscf_get_min_se(msg, &h_min_se);
00781 if (min_se.len) {
00782 strtotime(min_se, min_se_time);
00783 if (min_se_time < pcscf_min_se)
00784 cscf_del_header(msg, h_min_se);
00785 else
00786 return CSCF_RETURN_TRUE;
00787 }
00788 new_min_se.len = 11 + str_min_se.len+3;
00789 new_min_se.s = pkg_malloc(new_min_se.len+1);
00790 if (!new_min_se.s) {
00791 LOG(L_ERR,"ERR:"M_NAME":P_check_session_expires: Error allocating %d bytes\n",new_min_se.len);
00792 goto error;
00793 }
00794 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, pcscf_min_se);
00795 min_se_time = pcscf_min_se;
00796 cscf_add_header(msg, &new_min_se, HDR_OTHER_T);
00797 if (t_time < pcscf_min_se) {
00798 cscf_del_header(msg, h_se);
00799 new_ses_exp.len = 11 + str_se.len+3;
00800 new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
00801 if (!new_ses_exp.s) {
00802 LOG(L_ERR,"ERR:"M_NAME":P_check_session_expires: Error allocating %d bytes\n",new_ses_exp.len);
00803 goto error;
00804 }
00805 new_ses_exp.len = snprintf(new_ses_exp.s, new_ses_exp.len, "%.*s %d\r\n",str_se.len, str_se.s, pcscf_min_se);
00806 t_time = pcscf_min_se;
00807 cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
00808 }
00809 return CSCF_RETURN_TRUE;
00810 }
00811 error:
00812 if (new_min_se.s) pkg_free(new_min_se.s);
00813 if (new_ses_exp.s) pkg_free(new_ses_exp.s);
00814 return CSCF_RETURN_FALSE;
00815 }
00816
00817
00825 int P_save_dialog(struct sip_msg* msg, char* str1, char* str2)
00826 {
00827 str call_id;
00828 p_dialog *d;
00829 str host;
00830 time_t t_time;
00831 str ses_exp = {0,0};
00832 str refresher = {0,0};
00833 int port,transport;
00834 char buf1[256],buf2[256];
00835 str tag,ruri,uri,x;
00836 struct hdr_field *h;
00837 unsigned int hash;
00838 enum p_dialog_direction dir;
00839
00840 dir = get_dialog_direction(str1);
00841
00842 if (!find_dialog_contact(msg,dir,&host,&port,&transport)){
00843 LOG(L_ERR,"ERR:"M_NAME":P_is_in_dialog(): Error retrieving %s contact\n",str1);
00844 return CSCF_RETURN_BREAK;
00845 }
00846
00847 call_id = cscf_get_call_id(msg,0);
00848 if (!call_id.len)
00849 return CSCF_RETURN_FALSE;
00850
00851 LOG(L_DBG,"DBG:"M_NAME":P_save_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);
00852
00853 if (is_p_dialog(call_id,host,port,transport,&dir)){
00854 LOG(L_ERR,"ERR:"M_NAME":P_save_dialog: dialog already exists!\n");
00855 return CSCF_RETURN_TRUE;
00856 }
00857
00858 d = add_p_dialog(call_id,host,port,transport);
00859 if (!d) return CSCF_RETURN_FALSE;
00860
00861 d->method = get_dialog_method(msg->first_line.u.request.method);
00862 STR_SHM_DUP(d->method_str,msg->first_line.u.request.method,"shm");
00863 d->first_cseq = cscf_get_cseq(msg,0);
00864 d->last_cseq = d->first_cseq;
00865 d->state = DLG_STATE_INITIAL;
00866
00867 d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
00868
00869 ses_exp = cscf_get_session_expires_body(msg, &h);
00870 t_time = cscf_get_session_expires(ses_exp, &refresher);
00871 if (!t_time){
00872 d->expires = d_act_time() + 60;
00873 d->lr_session_expires = 0;
00874 }else {
00875 d->expires = d_act_time() + t_time;
00876 d->lr_session_expires = t_time;
00877 if (refresher.len)
00878 STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
00879 }
00880
00881 d->direction=dir;
00882
00883 cscf_get_from_tag(msg,&tag);
00884 cscf_get_from_uri(msg,&x);
00885 uri.len = snprintf(buf1,256,"<%.*s>",x.len,x.s);
00886 uri.s = buf1;
00887 cscf_get_to_uri(msg,&x);
00888 ruri.len = snprintf(buf2,256,"<%.*s>",x.len,x.s);
00889 ruri.s = buf2;
00890
00891 tmb.new_dlg_uac(&call_id,
00892 &tag,
00893 d->first_cseq,
00894 &uri,
00895 &ruri,
00896 &d->dialog_c);
00897
00898 tmb.new_dlg_uas(msg,99,&d->dialog_s);
00899
00900 d_unlock(d->hash);
00901 print_p_dialogs(L_INFO);
00902
00903 return CSCF_RETURN_TRUE;
00904 out_of_memory:
00905 if (d){
00906 hash = d->hash;
00907 del_p_dialog(d);
00908 d_unlock(hash);
00909 }
00910 return CSCF_RETURN_FALSE;
00911 }
00912
00919 void save_dialog_routes(struct sip_msg* msg, char* str1,p_dialog *d)
00920 {
00921 int i;
00922 rr_t *rr,*ri;
00923 struct hdr_field *hdr;
00924 if (d->routes){
00925 for(i=0;i<d->routes_cnt;i++)
00926 shm_free(d->routes[i].s);
00927 shm_free(d->routes);
00928 d->routes = 0;
00929 }
00930 d->routes_cnt = 0;
00931 for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){
00932 rr = (rr_t*)hdr->parsed;
00933 for(ri=rr;ri;ri=ri->next)
00934 d->routes_cnt++;
00935 }
00936 d->routes = shm_malloc(sizeof(str)*d->routes_cnt);
00937 if (!d->routes){
00938 LOG(L_ERR,"ERR:"M_NAME":save_dialog_routes(): Unable to alloc %d bytes\n",
00939 sizeof(str)*d->routes_cnt);
00940 d->routes_cnt = 0;
00941 return;
00942 }
00943 if (!str1) return;
00944 if (str1[0]=='o'||str1[0]=='0'||str1[0]=='O'){
00945
00946 i = d->routes_cnt-1;
00947 for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){
00948 rr = (rr_t*)hdr->parsed;
00949 for(ri=rr;ri;ri=ri->next){
00950 STR_SHM_DUP(d->routes[i],ri->nameaddr.uri,"shm");
00951 i--;
00952 }
00953 }
00954 }else{
00955
00956 i = 0;
00957 for(hdr=cscf_get_next_record_route(msg,0);hdr;hdr=cscf_get_next_record_route(msg,hdr)){
00958 rr = (rr_t*)hdr->parsed;
00959 for(ri=rr;ri;ri=ri->next){
00960 STR_SHM_DUP(d->routes[i],ri->nameaddr.uri,"shm");
00961 i++;
00962 }
00963 }
00964 }
00965 out_of_memory:
00966 return;
00967 }
00973 int update_dialog_on_reply(struct sip_msg *msg, p_dialog *d)
00974 {
00975 struct hdr_field *h_req;
00976 struct hdr_field *h=0;
00977 int res=0;
00978 time_t t_time=0;
00979 str ses_exp = {0,0};
00980 str refresher = {0,0};
00981 str new_ses_exp = {0,0};
00982 str new_ext = {0,0};
00983 int expires = 0;
00984
00985 ses_exp = cscf_get_session_expires_body(msg, &h);
00986 t_time = cscf_get_session_expires(ses_exp, &refresher);
00987 if (!t_time)
00988 {
00989 if (!d->uac_supp_timer || !d->lr_session_expires)
00990 {
00991 expires = cscf_get_expires_hdr(msg);
00992 if (expires >= 0)
00993 {
00994 d->expires = d_act_time()+expires;
00995 }
00996 else
00997 {
00998 d->expires = d_act_time()+pcscf_dialogs_expiration_time;
00999 }
01000 }
01001 else
01002 {
01003 d->expires = d_act_time()+d->lr_session_expires;
01004
01005 new_ses_exp.len = 11 + str_se.len+s_refresher.len+8;
01006 new_ses_exp.s = pkg_malloc(new_ses_exp.len+1);
01007 if (!new_ses_exp.s) {
01008 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ses_exp.len);
01009 goto error;
01010 }
01011 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);
01012 cscf_add_header(msg, &new_ses_exp, HDR_OTHER_T);
01013 if (!requires_extension(msg, &str_ext_timer))
01014 {
01015
01016 res = parse_headers(msg, HDR_EOH_F, 0);
01017 if (res == -1) {
01018 ERR("Error while parsing headers (%d)\n", res);
01019 return 0;
01020 }
01021
01022 h_req = msg->require;
01023 while (h_req) {
01024 if (h_req->type == HDR_REQUIRE_T) {
01025 if (h_req->body.s[new_ext.len-1]=='\n')
01026 {
01027 new_ext.len = str_require.len + 1+h_req->body.len + 7;
01028 new_ext.s = pkg_malloc(new_ext.len);
01029 if (!new_ext.s) {
01030 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
01031 goto error;
01032 }
01033 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);
01034 }
01035 else
01036 {
01037 new_ext.len = str_require.len + 1 + h_req->body.len + 9;
01038 new_ext.s = pkg_malloc(new_ext.len);
01039 if (!new_ext.s) {
01040 LOG(L_ERR,"ERR:"M_NAME":update_dialog_on_reply: Error allocating %d bytes\n",new_ext.len);
01041 goto error;
01042 }
01043 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);
01044 }
01045 cscf_del_header(msg, h_req);
01046 cscf_add_header(msg, &new_ext, HDR_REQUIRE_T);
01047 break;
01048 }
01049 h_req = h_req->next;
01050 }
01051 }
01052 }
01053 }
01054 else{
01055 d->expires = d_act_time() + t_time;
01056 d->lr_session_expires = t_time;
01057 }
01058 return 1;
01059 error:
01060 if (new_ses_exp.s) pkg_free(new_ses_exp.s);
01061 if (new_ext.s) pkg_free(new_ext.s);
01062 return 0;
01063 }
01064
01080 int P_update_dialog(struct sip_msg* msg, char* str1, char* str2)
01081 {
01082 str call_id;
01083 p_dialog *d;
01084 int response;
01085 int cseq;
01086 struct hdr_field *h=0;
01087 struct sip_msg *req=0;
01088 str host;
01089 int port,transport;
01090 int expires;
01091 str totag;
01092 time_t t_time=0;
01093 str ses_exp = {0,0};
01094 str refresher = {0,0};
01095 enum p_dialog_direction dir;
01096
01097 dir = get_dialog_direction(str1);
01098
01099 if (msg->first_line.type==SIP_REPLY) req = cscf_get_request_from_reply(msg);
01100 else req = msg;
01101 if (!find_dialog_contact(req,dir,&host,&port,&transport)){
01102 LOG(L_ERR,"ERR:"M_NAME":P_update_dialog(%s): Error retrieving %s contact\n",str1,str1);
01103 return CSCF_RETURN_BREAK;
01104 }
01105
01106 call_id = cscf_get_call_id(msg,0);
01107 if (!call_id.len)
01108 return CSCF_RETURN_FALSE;
01109
01110 LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Call-ID <%.*s>\n",str1,call_id.len,call_id.s);
01111
01112 d = get_p_dialog(call_id,host,port,transport,&dir);
01113 if (!d)
01114 d = get_p_dialog(call_id,host,port,transport,0);
01115 if (!d){
01116 if (msg->first_line.type==SIP_REQUEST &&
01117 msg->first_line.u.request.method.len == 3 &&
01118 strncasecmp(msg->first_line.u.request.method.s,"ACK",3)){
01119
01120 return CSCF_RETURN_TRUE;
01121 }else{
01122 LOG(L_CRIT,"ERR:"M_NAME":P_update_dialog: dialog does not exists!\n");
01123 return CSCF_RETURN_FALSE;
01124 }
01125 }
01126
01127
01128 if (msg->first_line.type==SIP_REQUEST){
01129
01130 LOG(L_DBG,"DBG:"M_NAME":P_update_dialog(%s): Method <%.*s> \n",str1,
01131 msg->first_line.u.request.method.len,msg->first_line.u.request.method.s);
01132 cseq = cscf_get_cseq(msg,&h);
01133 if (cseq>d->last_cseq) d->last_cseq = cseq;
01134 if (get_dialog_method(msg->first_line.u.request.method) == DLG_METHOD_INVITE)
01135 {
01136 d->uac_supp_timer = supports_extension(msg, &str_ext_timer);
01137
01138 ses_exp = cscf_get_session_expires_body(msg, &h);
01139 t_time = cscf_get_session_expires(ses_exp, &refresher);
01140 if (!t_time){
01141 d->expires = d_act_time()+pcscf_dialogs_expiration_time;
01142 d->lr_session_expires = 0;
01143 } else {
01144 d->expires = d_act_time() + t_time;
01145 d->lr_session_expires = t_time;
01146 if (refresher.len)
01147 STR_SHM_DUP(d->refresher, refresher, "DIALOG_REFRESHER");
01148 }
01149 }
01150 else if (d->method == DLG_METHOD_SUBSCRIBE &&
01151 msg->first_line.u.request.method.len == 6 &&
01152 strncasecmp(msg->first_line.u.request.method.s,"NOTIFY",6)==0)
01153 {
01154
01155 expires =