00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00052 #include <stdio.h>
00053 #include <string.h>
00054 #include <stdlib.h>
00055
00056 #include "../../pvar.h"
00057 #include "../../lib/kcore/parse_sst.h"
00058 #include "../../lib/kcore/parse_supported.h"
00059 #include "../../mem/mem.h"
00060 #include "../../mem/shm_mem.h"
00061 #include "../../data_lump.h"
00062 #include "../../data_lump_rpl.h"
00063 #include "../../ut.h"
00064 #include "../../lvalue.h"
00065 #include "../../dprint.h"
00066 #include "../../sr_module.h"
00067 #include "../../modules/sl/sl.h"
00068
00069 #include "sst_handlers.h"
00070 #include "sst_mi.h"
00071
00072
00073
00074
00075
00076
00077 #ifdef USE_CONFIRM_CALLBACK
00078 #define DLOGMSG(msg) { \
00079 if (msg->first_line.type == SIP_REQUEST) { \
00080 LM_INFO("REQUEST: %.*s\n", \
00081 msg->first_line.u.request.method.len, \
00082 msg->first_line.u.request.method.s); \
00083 } \
00084 else { \
00085 LM_INFO("RESPONSE: %d %.*s\n", \
00086 msg->first_line.u.reply.statuscode, \
00087 msg->first_line.u.reply.reason.len, \
00088 msg->first_line.u.reply.reason.s); \
00089 } \
00090 }
00091 #endif
00092
00093
00098 extern struct dlg_binds *dlg_binds;
00099
00104 typedef struct sst_msg_info_st {
00105 int supported;
00106 unsigned int min_se;
00107 unsigned int se;
00108 enum sst_refresher refresher;
00109 } sst_msg_info_t;
00110
00115 #ifdef USE_CONFIRM_CALLBACK
00116 static void sst_dialog_confirmed_CB(struct dlg_cell* did, int type,
00117 struct dlg_cb_params * params);
00118 #endif
00119 static void sst_dialog_terminate_CB(struct dlg_cell* did, int type,
00120 struct dlg_cb_params * params);
00121 static void sst_dialog_request_within_CB(struct dlg_cell* did, int type,
00122 struct dlg_cb_params * params);
00123 static void sst_dialog_response_fwded_CB(struct dlg_cell* did, int type,
00124 struct dlg_cb_params * params);
00125 static int send_response(struct sip_msg *request, int code, str *reason,
00126 char *header, int header_len);
00127 static int append_header(struct sip_msg *msg, const char *header);
00128 static int remove_header(struct sip_msg *msg, const char *header);
00129 static int set_timeout_avp(struct sip_msg *msg, unsigned int value);
00130 static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo);
00131 static int send_reject(struct sip_msg *msg, unsigned int min_se);
00132 static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info);
00133
00138 extern sl_api_t slb;
00139
00143 static pv_spec_t *timeout_avp = 0;
00144
00148 static unsigned int sst_min_se = 0;
00149
00153 static unsigned int sst_reject = 1;
00154
00159 static int sst_flag = 0;
00160
00161
00162 static str sst_422_rpl = str_init("Session Timer Too Small");
00163
00164
00165
00166 #define SST_SE_BUF_SIZE 80
00167 static char sst_se_buf[SST_SE_BUF_SIZE];
00168 static inline int sst_build_minse_hdr(int seval, str *sehdr)
00169 {
00170 if(sehdr==NULL)
00171 return -1;
00172
00173 sehdr->len = snprintf(sst_se_buf, SST_SE_BUF_SIZE,
00174 "Min-SE: %d\r\n", seval);
00175 sehdr->s = sst_se_buf;
00176 return 0;
00177 }
00178 static inline int sst_build_se_hdr(int seval, str *sehdr)
00179 {
00180 if(sehdr==NULL)
00181 return -1;
00182
00183 sehdr->len = snprintf(sst_se_buf, SST_SE_BUF_SIZE,
00184 "Session-Expires: %d\r\n", seval);
00185 sehdr->s = sst_se_buf;
00186 return 0;
00187 }
00188
00199 void sst_handler_init(pv_spec_t *timeout_avp_p, unsigned int min_se,
00200 int flag, unsigned int reject)
00201 {
00202 timeout_avp = timeout_avp_p;
00203 sst_min_se = min_se;
00204 sst_flag = 1 << flag;
00205 sst_reject = reject;
00206 }
00207
00249 void sst_dialog_created_CB(struct dlg_cell *did, int type,
00250 struct dlg_cb_params * params)
00251 {
00252 sst_info_t *info = NULL;
00253 sst_msg_info_t minfo;
00254 struct sip_msg* msg = params->req;
00255
00256 memset(&minfo, 0, sizeof(sst_msg_info_t));
00257
00258
00259
00260 if ((msg->flags & sst_flag) != sst_flag) {
00261 LM_DBG("SST flag was not set for this request\n");
00262 return;
00263 }
00264
00265
00266
00267
00268 if (msg->first_line.type != SIP_REQUEST ||
00269 msg->first_line.u.request.method_value != METHOD_INVITE) {
00270 LM_WARN("dialog create callback called with a non-INVITE request.\n");
00271 return;
00272 }
00273
00274
00275
00276
00277 if (parse_msg_for_sst_info(msg, &minfo)) {
00278 LM_ERR("failed to parse sst information\n");
00279 return;
00280 }
00281
00282 info = (sst_info_t *)shm_malloc(sizeof(sst_info_t));
00283 memset(info, 0, sizeof(sst_info_t));
00284 info->requester = (minfo.se?SST_UAC:SST_UNDF);
00285 info->supported = (minfo.supported?SST_UAC:SST_UNDF);
00286 info->interval = MAX(sst_min_se, 90);
00287
00288
00289 if (minfo.se != 0) {
00290
00291
00292
00293
00294 if (minfo.se < sst_min_se) {
00295
00296
00297
00298
00299
00300 if (!minfo.supported) {
00301
00302
00303
00304
00305 str msehdr;
00306 if (minfo.min_se) {
00307
00308
00309 remove_header(msg, "Min-SE");
00310 }
00311 info->interval = MAX(sst_min_se, minfo.min_se);
00312 sst_build_minse_hdr(info->interval, &msehdr);
00313 if (append_header(msg, msehdr.s)) {
00314 LM_ERR("Could not append modified Min-SE: header\n");
00315 }
00316 }
00317 else if (sst_reject) {
00318
00319 send_reject(msg, MAX(MAX(sst_min_se, minfo.min_se), 90));
00320 shm_free(info);
00321 return;
00322 }
00323 }
00324 else {
00325
00326 info->interval = minfo.se;
00327 }
00328 }
00329 else {
00330
00331
00332
00333 str msehdr;
00334
00335 info->interval = MAX(minfo.min_se, sst_min_se);
00336
00337 if (minfo.min_se && minfo.min_se < sst_min_se) {
00338 remove_header(msg, "Min-SE");
00339 sst_build_minse_hdr(info->interval, &msehdr);
00340 if (append_header(msg, msehdr.s)) {
00341 LM_ERR("failed to append modified Min-SE: header\n");
00342
00343 }
00344 }
00345
00346 info->requester = SST_PXY;
00347 sst_build_se_hdr(info->interval, &msehdr);
00348 if (append_header(msg, msehdr.s)) {
00349 LM_ERR("failed to append Session-Expires header to proxy "
00350 "requested SST.\n");
00351 shm_free(info);
00352 return;
00353 }
00354 }
00355 setup_dialog_callbacks(did, info);
00356 set_timeout_avp(msg, info->interval);
00357 return;
00358 }
00359
00360 #ifdef USE_CONFIRM_CALLBACK
00361
00364 static void sst_dialog_confirmed_CB(struct dlg_cell *did, int type,
00365 struct dlg_cb_params * params)
00366 {
00367 struct sip_msg* msg = params->rpl;
00368
00369 LM_DBG("confirmed dialog CB %p\n", did);
00370 DLOGMSG(msg);
00371 }
00372 #endif
00373
00383 static void sst_dialog_terminate_CB(struct dlg_cell* did, int type,
00384 struct dlg_cb_params * params)
00385 {
00386 switch (type) {
00387 case DLGCB_FAILED:
00388 LM_DBG("DID %p failed (canceled). "
00389 "Terminating session.\n", did);
00390 break;
00391 case DLGCB_EXPIRED:
00392
00393
00394
00395 LM_DBG("Terminating session.\n");
00396 break;
00397 default:
00398 LM_DBG("Terminating DID %p session\n", did);
00399 break;
00400 }
00401
00402
00403
00404 if (*(params->param)) {
00405 LM_DBG("freeing the sst_info_t from dialog %p\n", did);
00406 shm_free(*(params->param));
00407 *(params->param) = NULL;
00408 }
00409 return;
00410 }
00411
00428 static void sst_dialog_request_within_CB(struct dlg_cell* did, int type,
00429 struct dlg_cb_params * params)
00430 {
00431 sst_info_t *info = (sst_info_t *)*(params->param);
00432 sst_msg_info_t minfo = {0,0,0,0};
00433 struct sip_msg* msg = params->req;
00434
00435 if (msg->first_line.type == SIP_REQUEST) {
00436 if ((msg->first_line.u.request.method_value == METHOD_INVITE ||
00437 msg->first_line.u.request.method_value == METHOD_UPDATE)) {
00438
00439 LM_DBG("Update by a REQUEST. %.*s\n",
00440 msg->first_line.u.request.method.len,
00441 msg->first_line.u.request.method.s);
00442 if (parse_msg_for_sst_info(msg, &minfo)) {
00443 LM_ERR("failed to parse sst information\n");
00444 return;
00445 }
00446
00447 set_timeout_avp(msg, minfo.se);
00448 info->interval = minfo.se;
00449 }
00450 else if (msg->first_line.u.request.method_value == METHOD_PRACK) {
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462 LM_DBG("PRACK workaround applied!\n");
00463 set_timeout_avp(msg, info->interval);
00464 }
00465 }
00466 else if (msg->first_line.type == SIP_REPLY) {
00467 if ((msg->first_line.u.reply.statuscode > 199 &&
00468 msg->first_line.u.reply.statuscode < 300)) {
00469
00470
00471
00472
00473 LM_DBG("Update by a REPLY %d %.*s\n",
00474 msg->first_line.u.reply.statuscode,
00475 msg->first_line.u.reply.reason.len,
00476 msg->first_line.u.reply.reason.s);
00477 if (parse_msg_for_sst_info(msg, &minfo)) {
00478 LM_ERR("failed to parse sst information\n");
00479 return;
00480 }
00481 set_timeout_avp(msg, minfo.se);
00482 info->interval = minfo.se;
00483 }
00484 }
00485 }
00486
00496 static void sst_dialog_response_fwded_CB(struct dlg_cell* did, int type,
00497 struct dlg_cb_params * params)
00498 {
00499 struct sip_msg* msg = params->rpl;
00500
00501
00502
00503
00504
00505
00506 if (msg->first_line.type == SIP_REPLY) {
00507 sst_msg_info_t minfo = {0,0,0,0};
00508 sst_info_t *info = (sst_info_t *)*(params->param);
00509
00510 LM_DBG("Dialog seen REPLY %d %.*s\n",
00511 msg->first_line.u.reply.statuscode,
00512 msg->first_line.u.reply.reason.len,
00513 msg->first_line.u.reply.reason.s);
00514
00515
00516
00517
00518
00519
00520 if (msg->first_line.u.reply.statuscode == 422) {
00521 if (parse_msg_for_sst_info(msg, &minfo)) {
00522 LM_ERR("failed to parse sst information for the 422 reply\n");
00523 return;
00524 }
00525
00526 info->interval = MAX(info->interval, minfo.min_se);
00527 return;
00528 }
00529
00530
00531
00532
00533
00534 if (!msg->cseq && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || !msg->cseq)) {
00535 LM_ERR("failed to parse CSeq\n");
00536 return;
00537 }
00538
00539
00540 if (msg->first_line.u.reply.statuscode > 199 &&
00541 msg->first_line.u.reply.statuscode < 300 &&
00542 (get_cseq(msg)->method_id == METHOD_INVITE ||
00543 get_cseq(msg)->method_id == METHOD_UPDATE)) {
00544 if (parse_msg_for_sst_info(msg, &minfo)) {
00545 LM_ERR("failed to parse sst information for the 2XX reply\n");
00546 return;
00547 }
00548
00549 if (minfo.se != 0) {
00550 if (set_timeout_avp(msg, info->interval)) {
00551 LM_ERR("failed to set the timeout AVP\n");
00552 return;
00553 }
00554 }
00555 else {
00556
00557 if (info->requester == SST_PXY || info->supported == SST_UAC) {
00558 str sehdr;
00559
00560 LM_DBG("appending the Session-Expires: header to the 2XX reply."
00561 " UAC will deal with it.\n");
00562
00563
00564
00565
00566
00567 sst_build_se_hdr(info->interval, &sehdr);
00568 if (append_header(msg, sehdr.s)) {
00569 LM_ERR("failed to append Session-Expires header\n");
00570 return;
00571 }
00572
00573 if (set_timeout_avp(msg, info->interval)) {
00574 return;
00575 }
00576 }
00577 else {
00578
00579
00580 LM_DBG("UAC and UAS do not support timers!"
00581 " No session timers for this session.\n");
00582 }
00583 }
00584 }
00585 }
00586 }
00587
00611 int sst_check_min(struct sip_msg *msg, char *flag, char *str2)
00612 {
00613 enum parse_sst_result result;
00614 struct session_expires se = {0,0};
00615 unsigned minse = 0;
00616
00617
00618
00619
00620
00621 if (msg->first_line.type == SIP_REQUEST &&
00622 msg->first_line.u.request.method_value == METHOD_INVITE) {
00623
00624
00625
00626
00627
00628
00629 if ((result = parse_session_expires(msg, &se)) != parse_sst_success) {
00630 if (result != parse_sst_header_not_found) {
00631 LM_ERR("failed to parse Session-Expires headers.\n");
00632 return 0;
00633 }
00634
00635 LM_DBG("No Session-Expires header found. retuning false (-1)\n");
00636
00637
00638
00639 return -1;
00640 }
00641
00642
00643
00644
00645 if ((result = parse_min_se(msg, &minse)) != parse_sst_success) {
00646 if (result != parse_sst_header_not_found) {
00647
00648
00649
00650
00651 LM_ERR("failed to parse MIN-SE header.\n");
00652 return -1;
00653 }
00654
00655
00656
00657
00658 LM_DBG("No MIN-SE header found.\n");
00659 minse = 90;
00660 }
00661
00662 LM_DBG("Session-Expires: %d; MIN-SE: %d\n", se.interval, minse);
00663
00664
00665
00666
00667
00668
00669 if (sst_min_se < MIN(minse, se.interval)) {
00670
00671
00672
00673
00674 if (flag) {
00675 str msehdr;
00676 sst_build_minse_hdr(sst_min_se, &msehdr);
00677 LM_DBG("Sending 422: %.*s\n", msehdr.len, msehdr.s);
00678 if (send_response(msg, 422, &sst_422_rpl, msehdr.s, msehdr.len)){
00679 LM_ERR("Error sending 422 reply.\n");
00680 }
00681 }
00682 LM_DBG("Done returning true (1)\n");
00683 return 1;
00684 }
00685 }
00686 LM_DBG("Done returning false (-1)\n");
00687
00688
00689
00690 return -1;
00691 }
00692
00706 static int send_response(struct sip_msg *request, int code, str *reason,
00707 char *header, int header_len)
00708 {
00709
00710 if (slb.freply != 0) {
00711
00712 if ((header) && (header_len)) {
00713 if (add_lump_rpl(request, header, header_len, LUMP_RPL_HDR) == 0) {
00714
00715 LM_ERR("unable to append header.\n");
00716 return -1;
00717 }
00718 }
00719
00720 if (slb.freply(request, code, reason) < 0) {
00721 LM_ERR("Unable to sent reply.\n");
00722 return -1;
00723 }
00724 }
00725 else {
00726 return -1;
00727 }
00728 return(0);
00729 }
00730
00739 static int append_header(struct sip_msg *msg, const char *header)
00740 {
00741 struct lump* anchor = NULL;
00742 char *s = NULL;
00743 int len = 0;
00744
00745 LM_DBG("Appending header: %s", header);
00746
00747 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00748 LM_ERR("failed to parse headers in message.\n");
00749 return(1);
00750 }
00751
00752 if ((anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0)) == 0) {
00753 LM_ERR("failed to get anchor to append header\n");
00754 return(1);
00755 }
00756 len = strlen(header);
00757 if ((s = (char *)pkg_malloc(len)) == 0) {
00758 LM_ERR("No more pkg memory. (size requested = %d)\n", len);
00759 return(1);
00760 }
00761 memcpy(s, header, len);
00762 if (insert_new_lump_before(anchor, s, len, 0) == 0) {
00763 LM_ERR("failed to insert lump\n");
00764 pkg_free(s);
00765 return(1);
00766 }
00767 LM_DBG("Done appending header successfully.\n");
00768 return(0);
00769 }
00770
00780 static int remove_header(struct sip_msg *msg, const char *header)
00781 {
00782 struct lump* anchor = NULL;
00783 struct hdr_field *hf = NULL;
00784 int cnt = 0;
00785 int len = strlen(header);
00786
00787 if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00788 LM_ERR("failed to parse headers in message.\n");
00789 return(-1);
00790 }
00791
00792 for (hf = msg->headers; hf; hf = hf->next) {
00793 if (hf->name.len != len) {
00794 continue;
00795 }
00796 if (strncasecmp(hf->name.s, header, hf->name.len) != 0) {
00797 continue;
00798 }
00799
00800 anchor = del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
00801 if (anchor == 0) {
00802 LM_ERR("no more pkg memory\n");
00803 return -1;
00804 }
00805 cnt++;
00806 }
00807 return cnt;
00808 }
00809
00819 static int set_timeout_avp(struct sip_msg *msg, unsigned int value)
00820 {
00821 int rtn = -1;
00822 pv_value_t pv_val;
00823 int result = 0;
00824
00825
00826 if (timeout_avp) {
00827 if ((result = pv_get_spec_value(msg, timeout_avp, &pv_val)) == 0) {
00828
00829 if (pv_val.flags & PV_VAL_INT && pv_val.ri == value) {
00830
00831 LM_DBG("Current timeout value already set to %d\n",
00832 value);
00833 rtn = 0;
00834 } else {
00835
00836 pv_val.flags = PV_VAL_INT|PV_TYPE_INT;
00837 pv_val.ri = value;
00838 if (timeout_avp->setf(msg,&timeout_avp->pvp,EQ_T,&pv_val)!=0) {
00839 LM_ERR("failed to set new dialog timeout value\n");
00840 } else {
00841 rtn = 0;
00842 }
00843 }
00844 }
00845 else {
00846 LM_ERR("SST not reset. get avp result is %d\n", result);
00847 }
00848 }
00849 else {
00850 LM_ERR("SST needs to know the name of the dialog timeout AVP!\n");
00851 }
00852 return(rtn);
00853 }
00854
00864 static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo)
00865 {
00866 int rtn = 0;
00867 struct session_expires se = {0,0};
00868
00869 if (!msg || !minfo) {
00870 return (-1);
00871 }
00872
00873
00874
00875
00876 minfo->supported = 0;
00877 minfo->se = 0;
00878 minfo->refresher = sst_refresher_unspecified;
00879 minfo->min_se = 0;
00880
00881
00882
00883
00884
00885
00886 if ((rtn = parse_supported(msg)) == 0) {
00887 if ((((struct supported_body*)msg->supported->parsed)->supported_all
00888 & F_SUPPORTED_TIMER)) {
00889 minfo->supported = 1;
00890 }
00891 }
00892
00893
00894
00895 minfo->min_se = 0;
00896 if ((rtn = parse_min_se(msg, &minfo->min_se)) != parse_sst_success) {
00897 minfo->min_se = 0;
00898 }
00899 minfo->se = 0;
00900 if ((rtn = parse_session_expires(msg, &se)) == parse_sst_success) {
00901 minfo->se = se.interval;
00902 minfo->refresher = se.refresher;
00903 }
00904 return(0);
00905 }
00906
00915 static int send_reject(struct sip_msg *msg, unsigned int min_se)
00916 {
00917 str msehdr;
00918
00919 sst_build_minse_hdr(min_se, &msehdr);
00920
00921 if (send_response(msg, 422, &sst_422_rpl, msehdr.s, msehdr.len)) {
00922 LM_ERR("Error sending 422 reply.\n");
00923 return(-1);
00924 }
00925 LM_DBG("Send reject reply 422 with Min-SE: %d\n", min_se);
00926 return(0);
00927 }
00928
00937 static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info)
00938 {
00939
00940
00941
00942
00943 #ifdef USE_CONFIRM_CALLBACK
00944 LM_DBG("Adding callback DLGCB_CONFIRMED\n");
00945 dlg_binds->register_dlgcb(did,
00946 DLGCB_CONFIRMED_NA, sst_dialog_confirmed_CB, info, NULL);
00947 #endif
00948
00949 LM_DBG("Adding callback "
00950 "DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED\n");
00951 dlg_binds->register_dlgcb(did,
00952 DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED,
00953 sst_dialog_terminate_CB, (void *)info, NULL);
00954 LM_DBG("Adding callback DLGCB_REQ_WITHIN\n");
00955
00956 dlg_binds->register_dlgcb(did, DLGCB_REQ_WITHIN,
00957 sst_dialog_request_within_CB, info, NULL);
00958
00959
00960
00961
00962
00963
00964 LM_DBG("Adding callback DLGCB_RESPONSE_FWDED\n");
00965 dlg_binds->register_dlgcb(did, DLGCB_RESPONSE_FWDED,
00966 sst_dialog_response_fwded_CB, info, NULL);
00967
00968 LM_DBG("Adding mi handler\n");
00969 dlg_binds->register_dlgcb(did, DLGCB_MI_CONTEXT,
00970 sst_dialog_mi_context_CB, info, NULL);
00971 }