00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
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
00202 lock_get(s_dialogs[(hash)].lock);
00203
00204 }
00205
00210 inline void d_unlock(unsigned int hash)
00211 {
00212 lock_release(s_dialogs[(hash)].lock);
00213
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
00486
00487 del_s_dialog(d);
00488 }
00489 return 1;
00490 break;
00491 case DLG_METHOD_SUBSCRIBE:
00492 if (!release_subscription(d)){
00493
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;
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
00638
00639
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
00669 if (dir!=dirmsg) return CSCF_RETURN_FALSE;
00670
00671
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))
00786 {
00787
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 + 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)
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
00960 {
00961 d->expires = d_act_time()+d->lr_session_expires;
00962
00963 new_ses_exp.len = 11 + 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))
00972 {
00973
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;
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;
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 + h_req->body.len + 9;
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
01056
01057
01058
01059
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
01071
01072
01073
01074
01075
01076
01077
01078
01079 if (!d){
01080 LOG(L_INFO,"INFO:"M_NAME