sst_handlers.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 SOMA Networks, Inc.
00005  * Written by Ron Winacott (karwin)
00006  *
00007  * This file is part of SIP-router, a free SIP server.
00008  *
00009  * SIP-router is free software; you can redistribute it and/or modify it
00010  * 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  * SIP-router is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022  * USA
00023  */
00024 
00052 #include <stdio.h>  /* for snprintf() */
00053 #include <string.h> /* for memset() */
00054 #include <stdlib.h> /* For atoi() */
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" /* Needed for find_export() */
00067 #include "../../modules/sl/sl.h"
00068 
00069 #include "sst_handlers.h"
00070 #include "sst_mi.h"
00071 
00072 /*
00073  * My own LM_*() macros to add the correct message prefix and
00074  * file/function/line number information to all LOG messages.
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;                  /* supported = timer in message */
00106         unsigned int min_se;    /* The Min-SE: value or zero    */
00107         unsigned int se;                /* The Sesion-Expires: header   */
00108         enum sst_refresher refresher;/* The refresher (parse_sst.h)  */
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 /* USE_CONFIRM_CALLBACK */
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 /* fixme: copied from functions, but size is too much */
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          * Only deal with messages flaged as SST interested.
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          * look only at INVITE
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          * Gather all he information about SST for this message
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); /* For now, will set for real
00287                                                                                   * later */
00288 
00289         if (minfo.se != 0) {
00290                 /* 
00291                  * There is a SE already there, this is good, we just need to
00292                  * check the values out a little before passing it along.
00293                  */
00294                 if (minfo.se < sst_min_se) {
00295                         /* 
00296                          * Problem, the requested Session-Expires is too small for
00297                          * our local policy. We need to fix it, or reject it or
00298                          * ignore it.
00299                          */
00300                         if (!minfo.supported) {
00301                                 /* 
00302                                  * Increase the Min-SE: value in the request and
00303                                  * forward it.
00304                                  */
00305                                 str msehdr;
00306                                 if (minfo.min_se) {
00307                                         /* We need to update, which means, remove +
00308                                          * insert */
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                                 /* Make sure that that all are at least 90 */
00319                                 send_reject(msg, MAX(MAX(sst_min_se, minfo.min_se), 90));
00320                                 shm_free(info);
00321                                 return;
00322                         }
00323                 }  /* end of se < sst_min_se */
00324                 else {
00325                         /* Use the INVITE SE: value */
00326                         info->interval = minfo.se;
00327                 }
00328         }
00329         else {
00330                 /* 
00331                  * No Session-Expire: stated in request.
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                                 /* What to do? Let is slide, we can still work */
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; /* Nothing we can do! */
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 /* USE_CONFIRM_CALLBACK */
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                         /* In the case of expired, the msg is pointing at a
00393                          * FAKED_REPLY (-1)
00394                          */
00395                         LM_DBG("Terminating session.\n");
00396                         break;
00397                 default: /* Normal termination. */
00398                         LM_DBG("Terminating DID %p session\n", did);
00399                         break;
00400         }
00401         /*
00402          * Free the param sst_info_t memory
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                         /* Early resetting of the value here */
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                         /* Special case here. The PRACK will cause the dialog
00452                          * module to reset the timeout value to the ldg->lifetime
00453                          * value and look for the new AVP value bound to the
00454                          * 1XX/PRACK/200OK/ACK transaction and not to the
00455                          * INVITE/200OK avp value. So we need to set the AVP
00456                          * again! I think this is a bug in the dialog module,
00457                          * either it should ignore PRACK like it ignored ACK, or
00458                          * the setting of the timeout value when returning to the
00459                          * confiremed callback code should look for the new AVP
00460                          * value, which is does not.
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                          * To spec (RFC) the internal time out value so not be reset
00471                          * until here.
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          * This test to see if the message is a response sould ALWAYS be
00503          * true. This callback should not get called for requests. But
00504          * lets be safe.
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                  * Need to check to see if it is a 422 response. If it is,
00516                  * make sure our Min-SE: for this dialog is set at least as
00517                  * large as in the Min-SE: in the reply 422 message. If not,
00518                  * we will create an INVITE, 422 loop.
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                         /* Make sure we do not try to use anything smaller */
00526                         info->interval = MAX(info->interval, minfo.min_se);
00527                         return; /* There is nothing else to do with this */
00528                 }
00529                 /*
00530                  * We need to get the method this reply is for from the CSEQ
00531                  * body. The RFC states we can only play with 2XX from the
00532                  * INVITE or reINVTE/UPDATE.
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                 /* 2XX replies to INVITES only !*/
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                                 /* no se header found, we want to resquest it. */
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                                          * GOOD! we can just insert the Session-Expires:
00564                                          * header and forward back to the UAC and it will
00565                                          * deal with refreshing the session.
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                                         /* Set the dialog timeout HERE */
00573                                         if (set_timeout_avp(msg, info->interval)) {
00574                                                 return;
00575                                         }
00576                                 }
00577                                 else {
00578                                         /* We are sunk, uac did not request it, and it
00579                                          * does not support it */
00580                                         LM_DBG("UAC and UAS do not support timers!"
00581                                                         " No session timers for this session.\n");
00582                                 }
00583                         }
00584                 } /* End of 2XX for an INVITE */
00585         } /* If the msg is a repsonse and not a request */
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          * Only look in INVITES. We can't reply with a 422 to a 2xx reply
00619          * now can we. This check can ONLY be done on the INVITE/UPDATE.
00620          */
00621         if (msg->first_line.type == SIP_REQUEST &&
00622                         msg->first_line.u.request.method_value == METHOD_INVITE) {
00623                 /*
00624                  * First see if there is an Session-Expires: header.  If there
00625                  * is, also look for a MIN-SE: header. If there is, use the
00626                  * minimum value of the two to compare with srt1. All MUST not
00627                  * be less then 90 and 1800 is recomended. See RCF section 4.
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; /* Error drop the message */
00633                         }
00634                         /* Session-Expires not supported/stated */
00635                         LM_DBG("No Session-Expires header found. retuning false (-1)\n");
00636                         /*
00637                          * NOTE: 0 == drop message, 1 == true, -1 == false
00638                          */
00639                         return -1;
00640                 }
00641 
00642                 /*
00643                  * We have a Session_expire header. Now look for the MIN-SE.
00644                  */
00645                 if ((result = parse_min_se(msg, &minse)) != parse_sst_success) {
00646                         if (result != parse_sst_header_not_found) {
00647                                 /*
00648                                  * This is an error. The header was found but could
00649                                  * not parse it.
00650                                  */
00651                                 LM_ERR("failed to parse MIN-SE header.\n");
00652                                 return -1; 
00653                         }
00654                         /*
00655                          * If not stated, use the value from the session-expires
00656                          * header
00657                          */
00658                         LM_DBG("No MIN-SE header found.\n");
00659                         minse = 90; /* default by RFC4028, $5 */
00660                 }
00661                 
00662                 LM_DBG("Session-Expires: %d; MIN-SE: %d\n",     se.interval, minse);
00663 
00664                 /*
00665                  * Now compare our MIN-SE with the messages and see if it is
00666                  * too small. We will take the smaller of the messages
00667                  * Session-expires and min-se if stated.
00668                  */
00669                 if (sst_min_se < MIN(minse, se.interval)) {
00670                         /*
00671                          * Too small. See if we need to send the 422 and are able
00672                          * to send it.
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; /* return true */
00684                 }
00685         }
00686         LM_DBG("Done returning false (-1)\n");
00687         /*
00688          * All is good.
00689          */
00690         return -1; /* return false */
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                 /* Add new headers if not null or zero length */
00712                 if ((header) && (header_len)) {
00713                         if (add_lump_rpl(request, header, header_len, LUMP_RPL_HDR) == 0) {
00714                                 /* An error with adding the lump */
00715                                 LM_ERR("unable to append header.\n");
00716                                 return -1;
00717                         }
00718                 }
00719                 /* Now using the sl function, send the reply/response */
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; /* assume failure */
00822         pv_value_t pv_val;
00823         int result = 0;
00824 
00825         /* Set the dialog timeout HERE */
00826         if (timeout_avp) {
00827                 if ((result = pv_get_spec_value(msg, timeout_avp, &pv_val)) == 0) {
00828                         /* We now hold a reference to the AVP */
00829                         if (pv_val.flags & PV_VAL_INT && pv_val.ri == value) {
00830                                 /* INT AVP with the same value */
00831                                 LM_DBG("Current timeout value already set to %d\n",
00832                                         value);
00833                                 rtn = 0;
00834                         } else {
00835                                 /* AVP not found or non-INT value -> add a new one*/
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          * parse the supported infor
00875          */
00876         minfo->supported = 0; /*Clear it */
00877         minfo->se = 0;
00878         minfo->refresher = sst_refresher_unspecified;
00879         minfo->min_se = 0;
00880 
00881         /*
00882          * The parse_supported() will return 0 if found and parsed OK, -1
00883          * if not found or an error parsing the one it did find! So assume
00884          * it is not found if unsuccessfull.
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          * Parse the Min-SE: header next.
00894          */
00895         minfo->min_se = 0;
00896         if ((rtn = parse_min_se(msg, &minfo->min_se)) != parse_sst_success) {
00897                 minfo->min_se = 0; /* Make sure it statys clean */
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          * Register for the other callbacks from the dialog.
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 /* USE_CONFIRM_CALLBACK */
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         /* This is for the reINVITE/UPDATE requests */
00956         dlg_binds->register_dlgcb(did, DLGCB_REQ_WITHIN,
00957                         sst_dialog_request_within_CB, info, NULL);
00958         /* 
00959          * This is for the final configuration of who will do SST for
00960          * us. In the DLGCB_CONFIRMED callback the message is
00961          * immutable! we must do all the real work in the DLGCB_FRD
00962          * callback were we can change the message.
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 }