sst_handlers.c

Go to the documentation of this file.
00001 /*
00002  * $Id: sst_handlers.c 5777 2009-03-30 19:32:53Z henningw $
00003  *
00004  * Copyright (C) 2006 SOMA Networks, Inc.
00005  * Written by Ron Winacott (karwin)
00006  *
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio 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  * Kamailio 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 
00025 /*!
00026  * \file sst/sst_handlers.c
00027  * \brief Functions for the SST module
00028  * \ingroup sst
00029  * Module: \ref sst
00030  */
00031 
00032 /*!
00033  * \page SST_support SST support:
00034  *
00035  * The Session-Expires header conveys the session interval for a SIP
00036  * call. It is placed in an INVITE request and is allowed in any 2xx
00037  * class response to an INVITE. Its presence indicates that the UAC
00038  * wishes to use the session timer for this call. Unlike the
00039  * SIP-Expires header, it can only contain a delta-time, which is the
00040  * current time, plus the session interval from the response.
00041  *
00042  * For example, if a UAS generates a 200 OK response to a re-INVITE
00043  * that contained a Session-Expires header with a value of 1800
00044  * seconds (30 minutes), the UAS computes the session expiration as 30
00045  * minutes after the time when the 200 OK response was sent. For each
00046  * proxy, the session expiration is 30 minutes after the time when the
00047  * 2xx was received or sent. For the UAC, the expiration time is 30
00048  * minutes after the receipt of the final response.
00049  *
00050  */
00051 
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 "../../parser/parse_sst.h"
00058 #include "../../parser/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 "../../dprint.h"
00065 #include "../../sr_module.h" /* Needed for find_export() */
00066 #include "../sl/sl_api.h"
00067 
00068 #include "sst_handlers.h"
00069 #include "sst_mi.h"
00070 
00071 /*
00072  * My own LM_*() macros to add the correct message prefix and
00073  * file/function/line number information to all LOG messages.
00074  */
00075 
00076 #ifdef USE_CONFIRM_CALLBACK
00077 #define DLOGMSG(msg) {                             \
00078       if (msg->first_line.type == SIP_REQUEST) {         \
00079          LM_INFO("REQUEST: %.*s\n",                \
00080                msg->first_line.u.request.method.len,  \
00081                msg->first_line.u.request.method.s);   \
00082       }                                      \
00083       else {                                    \
00084          LM_INFO("RESPONSE: %d %.*s\n",               \
00085                msg->first_line.u.reply.statuscode,    \
00086                msg->first_line.u.reply.reason.len,    \
00087                msg->first_line.u.reply.reason.s);     \
00088       }                                      \
00089 }
00090 #endif
00091 
00092 
00093 /**
00094  * The binding to the dialog module functions. Most importantly the
00095  * register_dlgcb function.
00096  */
00097 extern struct dlg_binds *dlg_binds;
00098 
00099 /**
00100  * A collection of information about SST in the current SIP message
00101  * being processed.
00102  */
00103 typedef struct sst_msg_info_st {
00104    int supported;             /* supported = timer in message */
00105    unsigned int min_se;    /* The Min-SE: value or zero    */
00106    unsigned int se;     /* The Sesion-Expires: header   */
00107    enum sst_refresher refresher;/* The refresher (parse_sst.h)  */
00108 } sst_msg_info_t;
00109 
00110 /**
00111  * Local function prototypes See function definition for
00112  * documentation.
00113  */
00114 #ifdef USE_CONFIRM_CALLBACK
00115 static void sst_dialog_confirmed_CB(struct dlg_cell* did, int type,
00116       struct dlg_cb_params * params);
00117 #endif /* USE_CONFIRM_CALLBACK */
00118 static void sst_dialog_terminate_CB(struct dlg_cell* did, int type,
00119       struct dlg_cb_params * params);
00120 static void sst_dialog_request_within_CB(struct dlg_cell* did, int type,
00121       struct dlg_cb_params * params);
00122 static void sst_dialog_response_fwded_CB(struct dlg_cell* did, int type,
00123       struct dlg_cb_params * params);
00124 static int send_response(struct sip_msg *request, int code, str *reason,
00125       char *header, int header_len);
00126 static int append_header(struct sip_msg *msg, const char *header);
00127 static int remove_header(struct sip_msg *msg, const char *header);
00128 static int set_timeout_avp(struct sip_msg *msg, unsigned int value);
00129 static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo);
00130 static int send_reject(struct sip_msg *msg, unsigned int min_se);
00131 static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info);
00132 
00133 /**
00134  * The pointer to the stateless reply function This is used to send a
00135  * 422 reply if asked to with a Min-SE: header value to small.
00136  */
00137 extern struct sl_binds slb;
00138 
00139 /**
00140  * The dialog modules timeout AVP spac.
00141  */
00142 static pv_spec_t *timeout_avp = 0;
00143 
00144 /**
00145  * Our Min-SE: header field value and test.
00146  */
00147 static unsigned int sst_min_se = 0;
00148 
00149 /**
00150  * Should the SE < sst_min_se be rehected with a 422 reply?
00151  */
00152 static unsigned int sst_reject = 1;
00153 
00154 /**
00155  * The value of the message flag to flag an INVITE we want to process
00156  * through the SST module.
00157  */
00158 static int sst_flag = 0;
00159 
00160 
00161 static str sst_422_rpl = str_init("Session Timer Too Small");
00162 
00163 
00164 /* fixme: copied from functions, but size is too much */
00165 #define SST_SE_BUF_SIZE 80
00166 static char sst_se_buf[SST_SE_BUF_SIZE];
00167 static inline int sst_build_minse_hdr(int seval, str *sehdr)
00168 {
00169    if(sehdr==NULL)
00170       return -1;
00171 
00172    sehdr->len = snprintf(sst_se_buf, SST_SE_BUF_SIZE,
00173          "Min-SE: %d\r\n", seval);
00174    sehdr->s = sst_se_buf;
00175    return 0;
00176 }
00177 static inline int sst_build_se_hdr(int seval, str *sehdr)
00178 {
00179    if(sehdr==NULL)
00180       return -1;
00181 
00182    sehdr->len = snprintf(sst_se_buf, SST_SE_BUF_SIZE,
00183          "Session-Expires: %d\r\n", seval);
00184    sehdr->s = sst_se_buf;
00185    return 0;
00186 }
00187 
00188 /**
00189  * This is not a public API. This function is called when the module
00190  * is loaded from the mod_init() function in sst.c to initialize the
00191  * callback handlers and local variables.
00192  *
00193  * @param timeout_avp_p - The pointer to the dialog modules timeout AVP.
00194  * @param min_se - The minimum session expire value allowed by this PROXY.
00195  * @param flag - sst flag
00196  * @param reject - reject state
00197  */
00198 void sst_handler_init(pv_spec_t *timeout_avp_p, unsigned int min_se,
00199       int flag, unsigned int reject)
00200 {
00201    timeout_avp = timeout_avp_p;
00202    sst_min_se = min_se;
00203    sst_flag = 1 << flag;
00204    sst_reject = reject;
00205 }
00206 
00207 /**
00208  * Every time a new dialog is created (from a new INVITE) the dialog
00209  * module will call this callback function. We need to track the
00210  * dialogs lifespan from this point forward until it is terminated
00211  * with a BYE, CANCEL, etc. In the process, we will see if either or
00212  * both ends of the conversation supports SIP Session Timers and setup
00213  * the dialog timeout to expire at the session timer expire time. Each
00214  * time the new re-INVITE is seen to update the SST, we will reset the
00215  * life span of the dialog to match it.
00216  *
00217  * This function will setup the other types of dialog callbacks
00218  * required to track the lifespan of the dialog. It will also start
00219  * the state tracking to figure out if and who supports SST.
00220  *
00221  * As per RFC4028: Request handling:
00222  * 
00223  * - The proxy may insert a SE header if none found.
00224  * - The SE value can be anything >= Min-SE (if found)
00225  * - The proxy MUST NOT add a refresher parameter to the SE.
00226  *
00227  * - If SE is already there, the Proxy can reduce its value but no
00228  *   lower then the Min-SE value if present.
00229  * - If the SE value is >= Min-SE the proxy MUST NOT increase it!
00230  * - If the SE value is < Min-SE (settable by the proxy) the proxy
00231  *   MUST increase the SE value to >= the new Min-SE.
00232  * - The proxy MUST NOT insert or change the refresher parameter.
00233  *
00234  * - If the supported=timer is found, the proxy may reject the request
00235  *   with a 422 if the SE value is smaller then the local policy. The
00236  *   422 MUST hold the proxies Min-SE value >= 90.
00237  * - If support=timer is NOT indecated, the proxy can't reject with a
00238  *   422 but can include/increase the MIN-SE: to be = to local policy.
00239  *   and increase the SE to match the new Min-SE value.
00240  * - the proxy MUST NOT insert/change the Min-SE header if
00241  *   supported=timer is present. (DoS attacks)
00242  *
00243  * @param did - The dialog ID
00244  * @param type - The trigger event type (CREATED)
00245  * @param params - The pointer to nothing. As we did not attach
00246  *                anything to this callback in the dialog module.
00247  */
00248 void sst_dialog_created_CB(struct dlg_cell *did, int type,
00249       struct dlg_cb_params * params)
00250 {
00251    sst_info_t *info = NULL;
00252    sst_msg_info_t minfo;
00253    struct sip_msg* msg = params->msg;
00254 
00255    memset(&minfo, 0, sizeof(sst_msg_info_t));
00256    /*
00257     * Only deal with messages flaged as SST interested.
00258     */
00259    if ((msg->flags & sst_flag) != sst_flag) {
00260       LM_DBG("SST flag was not set for this request\n");
00261       return;
00262    }
00263 
00264    /* 
00265     * look only at INVITE
00266     */
00267    if (msg->first_line.type != SIP_REQUEST ||
00268          msg->first_line.u.request.method_value != METHOD_INVITE) {
00269       LM_WARN("dialog create callback called with a non-INVITE request.\n");
00270       return;
00271    }
00272 
00273    /*
00274     * Gather all he information about SST for this message
00275     */
00276    if (parse_msg_for_sst_info(msg, &minfo)) {
00277       LM_ERR("failed to parse sst information\n");
00278       return;
00279    }
00280 
00281    info = (sst_info_t *)shm_malloc(sizeof(sst_info_t));
00282    memset(info, 0, sizeof(sst_info_t));
00283    info->requester = (minfo.se?SST_UAC:SST_UNDF);
00284    info->supported = (minfo.supported?SST_UAC:SST_UNDF);
00285    info->interval = MAX(sst_min_se, 90); /* For now, will set for real
00286                                 * later */
00287 
00288    if (minfo.se != 0) {
00289       /* 
00290        * There is a SE already there, this is good, we just need to
00291        * check the values out a little before passing it along.
00292        */
00293       if (minfo.se < sst_min_se) {
00294          /* 
00295           * Problem, the requested Session-Expires is too small for
00296           * our local policy. We need to fix it, or reject it or
00297           * ignore it.
00298           */
00299          if (!minfo.supported) {
00300             /* 
00301              * Increase the Min-SE: value in the request and
00302              * forward it.
00303              */
00304             str msehdr;
00305             if (minfo.min_se) {
00306                /* We need to update, which means, remove +
00307                 * insert */
00308                remove_header(msg, "Min-SE");
00309             }
00310             info->interval = MAX(sst_min_se, minfo.min_se);
00311             sst_build_minse_hdr(info->interval, &msehdr);
00312             if (append_header(msg, msehdr.s)) {
00313                LM_ERR("Could not append modified Min-SE: header\n");
00314             }
00315          }
00316          else if (sst_reject) {
00317             /* Make sure that that all are at least 90 */
00318             send_reject(msg, MAX(MAX(sst_min_se, minfo.min_se), 90));
00319             shm_free(info);
00320             return;
00321          }
00322       }  /* end of se < sst_min_se */
00323       else {
00324          /* Use the INVITE SE: value */
00325          info->interval = minfo.se;
00326       }
00327    }
00328    else {
00329       /* 
00330        * No Session-Expire: stated in request.
00331        */
00332       str msehdr;
00333 
00334       info->interval = MAX(minfo.min_se, sst_min_se);
00335 
00336       if (minfo.min_se && minfo.min_se < sst_min_se) {
00337          remove_header(msg, "Min-SE");
00338          sst_build_minse_hdr(info->interval, &msehdr);
00339          if (append_header(msg, msehdr.s)) {
00340             LM_ERR("failed to append modified Min-SE: header\n");
00341             /* What to do? Let is slide, we can still work */
00342          }
00343       }
00344       
00345       info->requester = SST_PXY;
00346       sst_build_se_hdr(info->interval, &msehdr);
00347       if (append_header(msg, msehdr.s)) {
00348          LM_ERR("failed to append Session-Expires header to proxy "
00349                "requested SST.\n");
00350          shm_free(info);
00351          return; /* Nothing we can do! */
00352       }
00353    }
00354    setup_dialog_callbacks(did, info);
00355    set_timeout_avp(msg, info->interval);
00356    return;
00357 }
00358 
00359 #ifdef USE_CONFIRM_CALLBACK
00360 /**
00361  * Play time. Please ignore this call.
00362  */
00363 static void sst_dialog_confirmed_CB(struct dlg_cell *did, int type,
00364       struct dlg_cb_params * params)
00365 {
00366    struct sip_msg* msg = params->msg;
00367 
00368    LM_DBG("confirmed dialog CB %p\n", did);
00369    DLOGMSG(msg);
00370 }
00371 #endif /* USE_CONFIRM_CALLBACK */
00372 
00373 /**
00374  * This callback is called when ever a dialog is terminated. The cause
00375  * of the termination can be normal, failed call, or expired. It is
00376  * the expired dialog we are really interested in.
00377  *
00378  * @param did - The Dialog ID / structure pointer. Used as an ID only.
00379  * @param type - The termination cause/reason.
00380  * @param params - The sst information
00381  */
00382 static void sst_dialog_terminate_CB(struct dlg_cell* did, int type,
00383       struct dlg_cb_params * params)
00384 {
00385    switch (type) {
00386       case DLGCB_FAILED:
00387          LM_DBG("DID %p failed (canceled). "
00388             "Terminating session.\n", did);
00389          break;
00390       case DLGCB_EXPIRED:
00391          /* In the case of expired, the msg is pointing at a
00392           * FAKED_REPLY (-1)
00393           */
00394          LM_DBG("Terminating session.\n");
00395          break;
00396       default: /* Normal termination. */
00397          LM_DBG("Terminating DID %p session\n", did);
00398          break;
00399    }
00400    /*
00401     * Free the param sst_info_t memory
00402     */
00403    if (*(params->param)) {
00404       LM_DBG("freeing the sst_info_t from dialog %p\n", did);
00405       shm_free(*(params->param));
00406       *(params->param) = NULL;
00407    }
00408    return;
00409 }
00410 
00411 /**
00412  * Callback from the dialog module when the dialog is being updated in
00413  * its life span. We are only interested in the INVITE or UPDATE if
00414  * SST is supported and active for this dialog. In this case, we need
00415  * to update the expire time for the dialog based on the
00416  * Session-Expires: header in the reINVITE/UPDATE request.
00417  *
00418  * When this callback returns control to the dialog module it WILL
00419  * reset the timeout of the dialog. We need to make sure we set the
00420  * AVP here or the dialog timeout will be reset to the DEFAULT value
00421  * if this is a different transaction. (so the AVP value is gone)
00422  *
00423  * @param did - The dialog structure. The pointer is used as an ID.
00424  * @param type - The reason for the callback. DLGCB_REQ_WITHIN
00425  * @param params - The sst information
00426  */
00427 static void sst_dialog_request_within_CB(struct dlg_cell* did, int type,
00428       struct dlg_cb_params * params)
00429 {
00430    sst_info_t *info = (sst_info_t *)*(params->param);
00431    sst_msg_info_t minfo = {0,0,0,0};
00432    struct sip_msg* msg = params->msg;
00433 
00434    if (msg->first_line.type == SIP_REQUEST) {
00435       if ((msg->first_line.u.request.method_value == METHOD_INVITE ||
00436                   msg->first_line.u.request.method_value == METHOD_UPDATE)) {
00437 
00438          LM_DBG("Update by a REQUEST. %.*s\n", 
00439                msg->first_line.u.request.method.len, 
00440                msg->first_line.u.request.method.s);
00441          if (parse_msg_for_sst_info(msg, &minfo)) {
00442             LM_ERR("failed to parse sst information\n"); 
00443             return;
00444          }
00445          /* Early resetting of the value here */
00446          set_timeout_avp(msg, minfo.se);
00447          info->interval = minfo.se;
00448       }
00449       else if (msg->first_line.u.request.method_value == METHOD_PRACK) {
00450          /* Special case here. The PRACK will cause the dialog
00451           * module to reset the timeout value to the ldg->lifetime
00452           * value and look for the new AVP value bound to the
00453           * 1XX/PRACK/200OK/ACK transaction and not to the
00454           * INVITE/200OK avp value. So we need to set the AVP
00455           * again! I think this is a bug in the dialog module,
00456           * either it should ignore PRACK like it ignored ACK, or
00457           * the setting of the timeout value when returning to the
00458           * confiremed callback code should look for the new AVP
00459           * value, which is does not.
00460           */
00461          LM_DBG("PRACK workaround applied!\n");
00462          set_timeout_avp(msg, info->interval);
00463       }
00464    }
00465    else if (msg->first_line.type == SIP_REPLY) {
00466       if ((msg->first_line.u.reply.statuscode > 199 &&
00467                   msg->first_line.u.reply.statuscode < 300)) {
00468          /*
00469           * To spec (RFC) the internal time out value so not be reset
00470           * until here.
00471           */
00472          LM_DBG("Update by a REPLY %d %.*s\n", 
00473                msg->first_line.u.reply.statuscode,
00474                msg->first_line.u.reply.reason.len, 
00475                msg->first_line.u.reply.reason.s);
00476          if (parse_msg_for_sst_info(msg, &minfo)) {
00477             LM_ERR("failed to parse sst information\n");
00478             return;
00479          }
00480          set_timeout_avp(msg, minfo.se);
00481          info->interval = minfo.se;
00482       }
00483    }
00484 }
00485 
00486 /**
00487  * This callback is called on any response message in the lifespan of
00488  * the dialog. The callback is called just before the message is
00489  * copied to pkg memory so it is still mutable.
00490  *
00491  * @param did - The dialog structure. The pointer is used as an ID.
00492  * @param type - The reason for the callback. DLGCB_CONFIRMED
00493  * @param params - The sst information
00494  */
00495 static void sst_dialog_response_fwded_CB(struct dlg_cell* did, int type,
00496       struct dlg_cb_params * params) 
00497 {
00498    struct sip_msg* msg = params->msg;
00499 
00500    /*
00501     * This test to see if the message is a response sould ALWAYS be
00502     * true. This callback should not get called for requests. But
00503     * lets be safe.
00504     */
00505    if (msg->first_line.type == SIP_REPLY) {
00506       sst_msg_info_t minfo = {0,0,0,0};
00507       sst_info_t *info = (sst_info_t *)*(params->param);
00508 
00509       LM_DBG("Dialog seen REPLY %d %.*s\n", 
00510             msg->first_line.u.reply.statuscode,
00511             msg->first_line.u.reply.reason.len, 
00512             msg->first_line.u.reply.reason.s);
00513       /*
00514        * Need to check to see if it is a 422 response. If it is,
00515        * make sure our Min-SE: for this dialog is set at least as
00516        * large as in the Min-SE: in the reply 422 message. If not,
00517        * we will create an INVITE, 422 loop.
00518        */
00519       if (msg->first_line.u.reply.statuscode == 422) {
00520          if (parse_msg_for_sst_info(msg, &minfo)) {
00521             LM_ERR("failed to parse sst information for the 422 reply\n");
00522             return;
00523          }
00524          /* Make sure we do not try to use anything smaller */
00525          info->interval = MAX(info->interval, minfo.min_se);
00526          return; /* There is nothing else to do with this */
00527       }
00528       /*
00529        * We need to get the method this reply is for from the CSEQ
00530        * body. The RFC states we can only play with 2XX from the
00531        * INVITE or reINVTE/UPDATE.
00532        */
00533       if (!msg->cseq && ((parse_headers(msg, HDR_CSEQ_F, 0) == -1) || !msg->cseq)) {
00534          LM_ERR("failed to parse CSeq\n");
00535          return;
00536       }
00537       
00538       /* 2XX replies to INVITES only !*/
00539       if (msg->first_line.u.reply.statuscode > 199 &&
00540             msg->first_line.u.reply.statuscode < 300 &&
00541             (get_cseq(msg)->method_id == METHOD_INVITE ||
00542                   get_cseq(msg)->method_id == METHOD_UPDATE)) {
00543          if (parse_msg_for_sst_info(msg, &minfo)) {
00544             LM_ERR("failed to parse sst information for the 2XX reply\n");
00545             return;
00546          }
00547 
00548          if (minfo.se != 0) {
00549             if (set_timeout_avp(msg, info->interval)) {
00550                LM_ERR("failed to set the timeout AVP\n");
00551                return;
00552             }
00553          }
00554          else {
00555             /* no se header found, we want to resquest it. */
00556             if (info->requester == SST_PXY || info->supported == SST_UAC) {
00557                str sehdr;
00558                
00559                LM_DBG("appending the Session-Expires: header to the 2XX reply."
00560                      " UAC will deal with it.\n");
00561                /*
00562                 * GOOD! we can just insert the Session-Expires:
00563                 * header and forward back to the UAC and it will
00564                 * deal with refreshing the session.
00565                 */
00566                sst_build_se_hdr(info->interval, &sehdr);
00567                if (append_header(msg, sehdr.s)) {
00568                   LM_ERR("failed to append Session-Expires header\n");
00569                   return;
00570                }
00571                /* Set the dialog timeout HERE */
00572                if (set_timeout_avp(msg, info->interval)) {
00573                   return;
00574                }
00575             }
00576             else {
00577                /* We are sunk, uac did not request it, and it
00578                 * does not support it */
00579                LM_DBG("UAC and UAS do not support timers!"
00580                      " No session timers for this session.\n");
00581             }
00582          }
00583       } /* End of 2XX for an INVITE */
00584    } /* If the msg is a repsonse and not a request */
00585 }
00586 
00587 /**
00588  * The sstCheckMin() script command handler. Return 1 (true) if the
00589  * MIN-SE: of the message is too small compared to the sst_min_se
00590  * value. This will allow the script to reply to this INVITE with a
00591  * "422 Session Timer Too Small" response. if sst_min_se was never set
00592  * the recommended value of 1800 seconds will be used.
00593  *
00594  * If the flag (str1) is set to 1, the 422 reply will be sent with the
00595  * sst MIN_SE value in the header. If the flag is not set or is NULL,
00596  * no reply is sent.
00597 
00598  * @param msg  - The sip message from the script (INVITE only)
00599  * @param flag - Reply mode Flag. 0/NULL do not send reply, 1 send 422
00600  *               reply if Session-Expires is to small with the MIN-SE
00601  *               header in the reply
00602  * @param str2 - Not used.
00603  *
00604  * @return 1 if the MIN-SE is too small, -1 if it is OK, or It could
00605  *         not be checked.
00606  *
00607  * NOTE: returning 0 == drop message, 1 == true, -1 == false in the
00608  *       script.
00609  */
00610 int sst_check_min(struct sip_msg *msg, char *flag, char *str2)
00611 {
00612    enum parse_sst_result result;
00613    struct session_expires se = {0,0};
00614    unsigned minse = 0;
00615 
00616    /*
00617     * Only look in INVITES. We can't reply with a 422 to a 2xx reply
00618     * now can we. This check can ONLY be done on the INVITE/UPDATE.
00619     */
00620    if (msg->first_line.type == SIP_REQUEST &&
00621          msg->first_line.u.request.method_value == METHOD_INVITE) {
00622       /*
00623        * First see if there is an Session-Expires: header.  If there
00624        * is, also look for a MIN-SE: header. If there is, use the
00625        * minimum value of the two to compare with srt1. All MUST not
00626        * be less then 90 and 1800 is recomended. See RCF section 4.
00627        */
00628       if ((result = parse_session_expires(msg, &se)) != parse_sst_success) {
00629          if (result != parse_sst_header_not_found) {
00630             LM_ERR("failed to parse Session-Expires headers.\n");
00631             return 0; /* Error drop the message */
00632          }
00633          /* Session-Expires not supported/stated */
00634          LM_DBG("No Session-Expires header found. retuning false (-1)\n");
00635          /*
00636           * NOTE: 0 == drop message, 1 == true, -1 == false
00637           */
00638          return -1;
00639       }
00640 
00641       /*
00642        * We have a Session_expire header. Now look for the MIN-SE.
00643        */
00644       if ((result = parse_min_se(msg, &minse)) != parse_sst_success) {
00645          if (result != parse_sst_header_not_found) {
00646             /*
00647              * This is an error. The header was found but could
00648              * not parse it.
00649              */
00650             LM_ERR("failed to parse MIN-SE header.\n");
00651             return -1; 
00652          }
00653          /*
00654           * If not stated, use the value from the session-expires
00655           * header
00656           */
00657          LM_DBG("No MIN-SE header found.\n");
00658          minse = 90; /* default by RFC4028, $5 */
00659       }
00660       
00661       LM_DBG("Session-Expires: %d; MIN-SE: %d\n",  se.interval, minse);
00662 
00663       /*
00664        * Now compare our MIN-SE with the messages and see if it is
00665        * too small. We will take the smaller of the messages
00666        * Session-expires and min-se if stated.
00667        */
00668       if (sst_min_se < MIN(minse, se.interval)) {
00669          /*
00670           * Too small. See if we need to send the 422 and are able
00671           * to send it.
00672           */
00673          if (flag) {
00674             str msehdr;
00675             sst_build_minse_hdr(sst_min_se, &msehdr);
00676             LM_DBG("Sending 422: %.*s\n", msehdr.len, msehdr.s);
00677             if (send_response(msg, 422, &sst_422_rpl, msehdr.s, msehdr.len)){
00678                LM_ERR("Error sending 422 reply.\n");
00679             }
00680          }
00681          LM_DBG("Done returning true (1)\n");
00682          return 1; /* return true */
00683       }
00684    }
00685    LM_DBG("Done returning false (-1)\n");
00686    /*
00687     * All is good.
00688     */
00689    return -1; /* return false */
00690 }
00691 
00692 /**
00693  * Send a reply (response) to the passed in SIP request messsage with
00694  * the code and reason. If the header is not NULL (and header_len !=
00695  * 0) the add the header to the reply message.
00696  *
00697  * @param request The SIP request message to build the reply from.
00698  * @param code The response code. i.e 200
00699  * @param reason The response reason. i.e. "OK"
00700  * @param header the header block to add to the reply.
00701  * @param header_len The length of the header block. (header)
00702  *
00703  * @return 0 on success, none-zero on an error.
00704  */
00705 static int send_response(struct sip_msg *request, int code, str *reason,
00706       char *header, int header_len) 
00707 {
00708 
00709    if (slb.send_reply != 0) {
00710       /* Add new headers if not null or zero length */
00711       if ((header) && (header_len)) {
00712          if (add_lump_rpl(request, header, header_len, LUMP_RPL_HDR) == 0) {
00713             /* An error with adding the lump */
00714             LM_ERR("unable to append header.\n");
00715             return -1;
00716          }
00717       }
00718       /* Now using the sl function, send the reply/response */
00719       if (slb.send_reply(request, code, reason) < 0) {
00720          LM_ERR("Unable to sent reply.\n");
00721          return -1;
00722       }
00723    }
00724    else {
00725       return -1;
00726    }
00727    return(0);
00728 }
00729 
00730 /**
00731  * Given some header text, append it to the passed in message.
00732  *
00733  * @param msg The message to append the header text to.
00734  * @param header The header text to append.
00735  *
00736  * @return 0 on success, non-zero on failure.
00737  */
00738 static int append_header(struct sip_msg *msg, const char *header)
00739 {
00740    struct lump* anchor = NULL;
00741    char *s = NULL;
00742    int len = 0;
00743 
00744    LM_DBG("Appending header: %s", header);
00745 
00746    if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00747       LM_ERR("failed to parse headers in message.\n");
00748       return(1);
00749    }
00750 
00751    if ((anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0)) == 0) {
00752       LM_ERR("failed to get anchor to append header\n");
00753       return(1);
00754    }
00755    len = strlen(header);
00756    if ((s = (char *)pkg_malloc(len)) == 0) {
00757       LM_ERR("No more pkg memory. (size requested = %d)\n", len);
00758       return(1);
00759    }
00760    memcpy(s, header, len);
00761    if (insert_new_lump_before(anchor, s, len, 0) == 0) {
00762       LM_ERR("failed to insert lump\n");
00763       pkg_free(s);
00764       return(1);
00765    }
00766    LM_DBG("Done appending header successfully.\n");
00767    return(0);
00768 }
00769 
00770 /**
00771  * Remove a header from a message if found.
00772  *
00773  * @param msg The message to look for the header to remove.
00774  * @param header The header name: text.
00775  *
00776  * @return 0 if the header was not found, >0 is successful, -1 on an
00777  *         error.
00778  */
00779 static int remove_header(struct sip_msg *msg, const char *header)
00780 {
00781    struct lump* anchor = NULL;
00782    struct hdr_field *hf = NULL;
00783    int cnt = 0;
00784    int len = strlen(header);
00785 
00786    if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
00787       LM_ERR("failed to parse headers in message.\n");
00788       return(-1);
00789    }
00790    
00791    for (hf = msg->headers; hf; hf = hf->next) {
00792       if (hf->name.len != len) {
00793          continue;
00794       }
00795       if (strncasecmp(hf->name.s, header, hf->name.len) != 0) {
00796          continue;
00797       }
00798 
00799       anchor = del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
00800       if (anchor == 0) {
00801          LM_ERR("no more pkg memory\n");
00802          return -1;
00803       }
00804       cnt++;
00805    }
00806    return cnt;
00807 }
00808 
00809 /**
00810  * Set the dialog's AVP value so the dialog module will use this value
00811  * and not the default when returning from the dialog callback.
00812  *
00813  * @param msg The current message to bind the AVP to.
00814  * @param value The value you want to set the AVP to.
00815  *
00816  * @return 0 on success, -1 on an error.
00817  */
00818 static int set_timeout_avp(struct sip_msg *msg, unsigned int value)
00819 {
00820    int rtn = -1; /* assume failure */
00821    pv_value_t pv_val;
00822    int result = 0;
00823 
00824    /* Set the dialog timeout HERE */
00825    if (timeout_avp) {
00826       if ((result = pv_get_spec_value(msg, timeout_avp, &pv_val)) == 0) {
00827          /* We now hold a reference to the AVP */
00828          if (pv_val.flags & PV_VAL_INT && pv_val.ri == value) {
00829             /* INT AVP with the same value */
00830             LM_DBG("Current timeout value already set to %d\n",
00831                value);
00832             rtn = 0;
00833          } else {
00834             /* AVP not found or non-INT value -> add a new one*/
00835             pv_val.flags = PV_VAL_INT;
00836             pv_val.ri = value;
00837             if (timeout_avp->setf(msg,&timeout_avp->pvp,EQ_T,&pv_val)!=0) {
00838                LM_ERR("failed to set new dialog timeout value\n");
00839             } else {
00840                rtn = 0;
00841             }
00842          }
00843       }
00844       else {
00845          LM_ERR("SST not reset. get avp result is %d\n", result);
00846       }
00847    }
00848    else {
00849       LM_ERR("SST needs to know the name of the dialog timeout AVP!\n");
00850    }
00851    return(rtn);
00852 }
00853 
00854 /**
00855  * Gether the message information about SST from the current message
00856  * being processed.
00857  *
00858  * @param msg The current message to parse.
00859  * @param minfo The SST information found in the message.
00860  *
00861  * @return 0 on success, -1 on a parsing error.
00862  */
00863 static int parse_msg_for_sst_info(struct sip_msg *msg, sst_msg_info_t *minfo)
00864 {
00865    int rtn = 0;
00866    struct session_expires se = {0,0};
00867 
00868    if (!msg || !minfo) {
00869       return (-1);
00870    }
00871    
00872    /* 
00873     * parse the supported infor
00874     */
00875    minfo->supported = 0; /*Clear it */
00876    minfo->se = 0;
00877    minfo->refresher = sst_refresher_unspecified;
00878    minfo->min_se = 0;
00879 
00880    /*
00881     * The parse_supported() will return 0 if found and parsed OK, -1
00882     * if not found or an error parsing the one it did find! So assume
00883     * it is not found if unsuccessfull.
00884     */
00885    if ((rtn = parse_supported(msg)) == 0) {
00886       if ((((struct supported_body*)msg->supported->parsed)->supported_all
00887                   & F_SUPPORTED_TIMER)) {
00888          minfo->supported = 1;
00889       }
00890    }
00891    /*
00892     * Parse the Min-SE: header next.
00893     */
00894    minfo->min_se = 0;
00895    if ((rtn = parse_min_se(msg, &minfo->min_se)) != parse_sst_success) {
00896       minfo->min_se = 0; /* Make sure it statys clean */
00897    }
00898    minfo->se = 0;
00899    if ((rtn = parse_session_expires(msg, &se)) == parse_sst_success) {
00900       minfo->se = se.interval;
00901       minfo->refresher = se.refresher;
00902    }
00903    return(0);
00904 }
00905 
00906 /**
00907  * Add the Min-SE: header and send a reply 422.
00908  *
00909  * @param msg The message to opperate on.
00910  * @param min_se The Min-SE: value to use in the heaader.
00911  *
00912  * @return 0 on success, -1 on error.
00913  */
00914 static int send_reject(struct sip_msg *msg, unsigned int min_se) 
00915 {
00916    str msehdr;
00917 
00918    sst_build_minse_hdr(min_se, &msehdr);
00919 
00920    if (send_response(msg, 422, &sst_422_rpl, msehdr.s, msehdr.len)) {
00921       LM_ERR("Error sending 422 reply.\n");
00922       return(-1);
00923    }
00924    LM_DBG("Send reject reply 422 with Min-SE: %d\n", min_se);
00925    return(0);
00926 }
00927 
00928 /**
00929  * A helper function to setup all the callbacks from the dialog module
00930  * after we find interest in the dialog.
00931  *
00932  * @param did The Dialog ID.
00933  * @param info The sst information.
00934  *
00935  */
00936 static void setup_dialog_callbacks(struct dlg_cell *did, sst_info_t *info)
00937 {
00938    /*
00939     * Register for the other callbacks from the dialog.
00940     */
00941 
00942 #ifdef USE_CONFIRM_CALLBACK
00943    LM_DBG("Adding callback DLGCB_CONFIRMED\n");
00944    dlg_binds->register_dlgcb(did,
00945          DLGCB_CONFIRMED, sst_dialog_confirmed_CB, info, NULL);
00946 #endif /* USE_CONFIRM_CALLBACK */
00947 
00948    LM_DBG("Adding callback "
00949          "DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED\n");
00950    dlg_binds->register_dlgcb(did,
00951          DLGCB_FAILED|DLGCB_TERMINATED|DLGCB_EXPIRED,
00952          sst_dialog_terminate_CB, (void *)info, NULL);
00953    LM_DBG("Adding callback DLGCB_REQ_WITHIN\n");
00954    /* This is for the reINVITE/UPDATE requests */
00955    dlg_binds->register_dlgcb(did, DLGCB_REQ_WITHIN,
00956          sst_dialog_request_within_CB, info, NULL);
00957    /* 
00958     * This is for the final configuration of who will do SST for
00959     * us. In the DLGCB_CONFIRMED callback the message is
00960     * immutable! we must do all the real work in the DLGCB_FRD
00961     * callback were we can change the message.
00962     */
00963    LM_DBG("Adding callback DLGCB_RESPONSE_FWDED\n");
00964    dlg_binds->register_dlgcb(did, DLGCB_RESPONSE_FWDED,
00965          sst_dialog_response_fwded_CB, info, NULL);
00966    
00967    LM_DBG("Adding mi handler\n");
00968    dlg_binds->register_dlgcb(did, DLGCB_MI_CONTEXT,
00969          sst_dialog_mi_context_CB, info, NULL);
00970 }

Generated on Thu May 24 14:00:31 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6