modules_k/dialog: Add support for spiral detection.
authorTimo Reimann <timo.reimann@1und1.de>
Tue, 27 Jul 2010 16:50:31 +0000 (18:50 +0200)
committerTimo Reimann <timo.reimann@1und1.de>
Tue, 27 Jul 2010 17:51:50 +0000 (19:51 +0200)
- Introduce module parameter "detect_spirals" which controls
  whether spiraling messages should be detected or not.
- If that flag is set, dlg_onreq() will check incoming message's
  dialog identifier (except for not yet existing To tag) against
  its local set of dialogs. If a match is found, the generation of
  a new dialog will be suppressed.
- New dialog callback DLGCB_SPIRALED may be registered to allow
  custom module actions on occurrence of a spiraling event.

modules_k/dialog/dialog.c
modules_k/dialog/dlg_cb.h
modules_k/dialog/dlg_handlers.c
modules_k/dialog/doc/dialog_admin.xml
modules_k/dialog/doc/dialog_devel.xml

index a7e34a2..f965a06 100644 (file)
@@ -99,6 +99,7 @@ pv_elem_t * ruri_param_model = NULL;
 int dlg_enable_stats = 1;
 int active_dlgs_cnt = 0;
 int early_dlgs_cnt = 0;
+int detect_spirals = 1;
 stat_var *active_dlgs = 0;
 stat_var *processed_dlgs = 0;
 stat_var *expired_dlgs = 0;
@@ -182,6 +183,7 @@ static param_export_t mod_params[]={
        { "default_timeout",       INT_PARAM, &default_timeout          },
        { "dlg_extra_hdrs",        STR_PARAM, &dlg_extra_hdrs.s         },
        { "dlg_match_mode",        INT_PARAM, &seq_match_mode           },
+       { "detect_spirals",        INT_PARAM, &detect_spirals,          },
        { "db_url",                STR_PARAM, &db_url.s                 },
        { "db_mode",               INT_PARAM, &dlg_db_mode              },
        { "table_name",            STR_PARAM, &dialog_table_name        },
@@ -473,6 +475,11 @@ static int mod_init(void)
                return -1;
        }
 
+       if (detect_spirals != 0 && detect_spirals != 1) {
+               LM_ERR("invalid value %d for detect_spirals param!!\n",detect_spirals);
+               return -1;
+       }
+
        /* if statistics are disabled, prevent their registration to core */
        if (dlg_enable_stats==0)
                exports.stats = 0;
index 3013809..fc8b05a 100644 (file)
@@ -66,6 +66,7 @@ typedef int (*register_dlgcb_f)(struct dlg_cell* dlg, int cb_types,
 #define DLGCB_MI_CONTEXT      (1<<10)
 #define DLGCB_RPC_CONTEXT     (1<<11)
 #define DLGCB_DESTROY         (1<<12)
+#define DLGCB_SPIRALED        (1<<13)
 
 struct dlg_callback {
        int types;
index a3610cc..77ad7ca 100644 (file)
@@ -84,6 +84,7 @@ static pv_spec_t *timeout_avp;                /*!< AVP for timeout setting */
 static int       default_timeout;      /*!< default dialog timeout */
 static int       seq_match_mode;       /*!< dlg_match mode */ 
 static int       shutdown_done = 0;    /*!< 1 when destroy_dlg_handlers was called */
+extern int       detect_spirals;
 
 extern struct rr_binds d_rrb;          /*!< binding to record-routing module */
 
@@ -483,6 +484,50 @@ inline static int get_dlg_timeout(struct sip_msg *req)
 }
 
 
+/*!
+ * \brief Helper function to get the necessary content from SIP message
+ * \param req SIP request
+ * \param callid found callid
+ * \param ftag found from tag
+ * \param ttag found to tag
+ * \param with_ttag flag set if to tag must be found for success
+ * \return 0 on success, -1 on failure
+ */
+static inline int pre_match_parse( struct sip_msg *req, str *callid,
+               str *ftag, str *ttag, int with_ttag)
+{
+       if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
+                       !req->to ) {
+               LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
+               return -1;
+       }
+
+       if (get_to(req)->tag_value.len==0) {
+               if (with_ttag == 1) {
+                       /* out of dialog request with preloaded Route headers; ignore. */
+                       return -1;
+               } else {
+                       ttag->s = NULL;
+                       ttag->len = 0;
+               }
+       } else {
+               *ttag = get_to(req)->tag_value;
+       }
+
+       if (parse_from_header(req)<0 || get_from(req)->tag_value.len==0) {
+               LM_ERR("failed to get From header\n");
+               return -1;
+       }
+
+       /* callid */
+       *callid = req->callid->body;
+       trim(callid);
+       /* from tag */
+       *ftag = get_from(req)->tag_value;
+       return 0;
+}
+
+
 /*!
  * \brief Function that is registered as TM callback and called on requests
  * \see dlg_new_dialog
@@ -492,13 +537,48 @@ inline static int get_dlg_timeout(struct sip_msg *req)
  */
 void dlg_onreq(struct cell* t, int type, struct tmcb_params *param)
 {
-       struct sip_msg *msg;
-       msg = param->req;
-       if((msg->flags&dlg_flag)!=dlg_flag)
+       struct dlg_cell *dlg;
+       str callid;
+       str ftag;
+       str ttag;
+       unsigned int dir;
+       struct sip_msg *req = param->req;
+
+       if((req->flags&dlg_flag)!=dlg_flag)
                return;
        if (current_dlg_pointer!=NULL)
                return;
-       dlg_new_dialog(msg, t);
+       if (!detect_spirals)
+               goto create;
+
+       /* skip initial requests - they may end up here because of the
+        * preloaded route */
+       if ( (!req->to && parse_headers(req, HDR_TO_F,0)<0) || !req->to ) {
+               LM_ERR("bad request or missing TO hdr :-/\n");
+               return;
+       }
+
+       dlg = 0;
+       dir = DLG_DIR_NONE;
+
+       if (pre_match_parse( req, &callid, &ftag, &ttag, 0)<0) {
+               LM_WARN("pre-matching failed\n");
+               return;
+       }
+       dlg = get_dlg(&callid, &ftag, &ttag, &dir);
+       if (!dlg){
+               LM_DBG("Callid '%.*s' not found, must be a new dialog\n",
+                               req->callid->body.len, req->callid->body.s);
+               goto create;
+       }
+
+       run_dlg_callbacks( DLGCB_SPIRALED, dlg, req, DLG_DIR_DOWNSTREAM, 0);
+
+       unref_dlg(dlg, 1);
+       return;
+
+create:
+       dlg_new_dialog(req, t);
 }
 
 
@@ -684,44 +764,6 @@ static inline int parse_dlg_rr_param(char *p, char *end, int *h_entry, int *h_id
 }
 
 
-/*!
- * \brief Helper function to get the necessary content from SIP message
- * \param req SIP request
- * \param callid found callid
- * \param ftag found from tag
- * \param ttag found to tag
- * \return 0 on succes, -1 on failure
- */
-static inline int pre_match_parse( struct sip_msg *req, str *callid,
-               str *ftag, str *ttag)
-{
-       if (parse_headers(req,HDR_CALLID_F|HDR_TO_F,0)<0 || !req->callid ||
-       !req->to ) {
-               LM_ERR("bad request or missing CALLID/TO hdr :-/\n");
-               return -1;
-       }
-
-       if (get_to(req)->tag_value.len==0) {
-               /* out of dialog request with preloaded Route headers; ignore. */
-               return -1;
-       }
-
-       if (parse_from_header(req)<0 || get_from(req)->tag_value.len==0) {
-               LM_ERR("failed to get From header\n");
-               return -1;
-       }
-
-       /* callid */
-       *callid = req->callid->body;
-       trim(callid);
-       /* to tag */
-       *ttag = get_to(req)->tag_value;
-       /* from tag */
-       *ftag = get_from(req)->tag_value;
-       return 0;
-}
-
-
 /*!
  * \brief Update the saved CSEQ information in dialog from SIP message
  * \param dlg updated dialog
@@ -838,7 +880,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
                                        return;
                        } else {
                                // lookup_dlg has incremented the ref count by 1
-                               if (pre_match_parse( req, &callid, &ftag, &ttag)<0) {
+                               if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0) {
                                        unref_dlg(dlg, 1);
                                        return;
                                }
@@ -871,7 +913,7 @@ void dlg_onroute(struct sip_msg* req, str *route_params, void *param)
        }
 
        if (dlg==0) {
-               if (pre_match_parse( req, &callid, &ftag, &ttag)<0)
+               if (pre_match_parse( req, &callid, &ftag, &ttag, 1)<0)
                        return;
                /* TODO - try to use the RR dir detection to speed up here the
                 * search -bogdan */
index 56c4b7b..af697d9 100644 (file)
@@ -324,6 +324,30 @@ modparam("dialog", "dlg_match_mode", 1)
                </example>
        </section>
 
+       <section>
+               <title><varname>detect_spirals</varname> (integer)</title>
+               <para>
+                       Whether spirals (i.e., messages routed through the proxy multiple times)
+                       should be detected or not.
+               </para>
+               <para>
+                       If set to 0, spirals will not be detected and result in the generation of a
+                       new, possibly dangling dialog structure per occurring spiral. If set to 1,
+                       spirals are detected and internally mapped to existing dialog structures.
+               </para>
+               <para>
+                       Default value is 1.
+               </para>
+               <example>
+                       <title>Set <varname>detect_spirals</varname> parameter</title>
+                       <programlisting format="linespecific">
+                               ...
+                               modparam("dialog", "detect_spirals", 1)
+                               ...
+                       </programlisting>
+               </example>
+       </section>
+
        <section>
                <title><varname>db_url</varname> (string)</title>
                <para>
index a32739f..4865dee 100644 (file)
                                mi dlg_list_ctx command is invoked - it's a per dialog type.
                                </para>
                        </listitem>
+                       <listitem>
+                               <para><emphasis>DLGCB_SPIRALED</emphasis> - called when the
+                               dialog matches a spiraling request - it's a per dialog type.
+                               </para>
+                       </listitem>
                        <listitem>
                                <para><emphasis>DLGCB_DESTROY</emphasis>
                                </para>