Module: sip-router Branch: master Commit: 0b665153a93ae7f1ff9d25b2ca1e30d9fbbe248b URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=0b665153...
Author: Timo Reimann timo.reimann@1und1.de Committer: Timo Reimann timo.reimann@1und1.de Date: Tue Jul 27 18:50:31 2010 +0200
modules_k/dialog: Add support for spiral detection.
- 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 | 7 ++ modules_k/dialog/dlg_cb.h | 1 + modules_k/dialog/dlg_handlers.c | 130 ++++++++++++++++++++++----------- modules_k/dialog/doc/dialog_admin.xml | 24 ++++++ modules_k/dialog/doc/dialog_devel.xml | 5 + 5 files changed, 123 insertions(+), 44 deletions(-)
diff --git a/modules_k/dialog/dialog.c b/modules_k/dialog/dialog.c index a7e34a2..f965a06 100644 --- a/modules_k/dialog/dialog.c +++ b/modules_k/dialog/dialog.c @@ -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; diff --git a/modules_k/dialog/dlg_cb.h b/modules_k/dialog/dlg_cb.h index 3013809..fc8b05a 100644 --- a/modules_k/dialog/dlg_cb.h +++ b/modules_k/dialog/dlg_cb.h @@ -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; diff --git a/modules_k/dialog/dlg_handlers.c b/modules_k/dialog/dlg_handlers.c index a3610cc..77ad7ca 100644 --- a/modules_k/dialog/dlg_handlers.c +++ b/modules_k/dialog/dlg_handlers.c @@ -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 */
@@ -484,6 +485,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 * \param t transaction, used to created the 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); }
@@ -685,44 +765,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 * \param req SIP request @@ -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 */ diff --git a/modules_k/dialog/doc/dialog_admin.xml b/modules_k/dialog/doc/dialog_admin.xml index 56c4b7b..af697d9 100644 --- a/modules_k/dialog/doc/dialog_admin.xml +++ b/modules_k/dialog/doc/dialog_admin.xml @@ -325,6 +325,30 @@ modparam("dialog", "dlg_match_mode", 1) </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> If you want to store the information about the dialogs in a database diff --git a/modules_k/dialog/doc/dialog_devel.xml b/modules_k/dialog/doc/dialog_devel.xml index a32739f..4865dee 100644 --- a/modules_k/dialog/doc/dialog_devel.xml +++ b/modules_k/dialog/doc/dialog_devel.xml @@ -95,6 +95,11 @@ </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> </listitem>