dialog: Add setting to loop BYE through proxy
authorAlex Hermann <alex@speakup.nl>
Thu, 10 Jul 2014 10:56:49 +0000 (12:56 +0200)
committerHenning Westerholt <henningw@users.noreply.github.com>
Mon, 15 Jul 2019 19:15:57 +0000 (21:15 +0200)
The setting "keep_proxy_rr" will add the Record-Route headers added by the
proxy to the route_set stored in the dialog. When in use, sending locally
generated in-dialog requests will loop back to the proxy with a proper
Record-Route header, including any parameters.

src/modules/dialog/dialog.c
src/modules/dialog/dlg_handlers.c
src/modules/dialog/dlg_handlers.h
src/modules/dialog/dlg_hash.c
src/modules/dialog/dlg_hash.h
src/modules/dialog/doc/dialog_admin.xml

index b8b6843..5df35de 100644 (file)
@@ -103,6 +103,7 @@ static char* profiles_nv_s = NULL;
 str dlg_extra_hdrs = {NULL,0};
 static int db_fetch_rows = 200;
 static int db_skip_load = 0;
+static int dlg_keep_proxy_rr = 0;
 int initial_cbs_inscript = 1;
 int dlg_wait_ack = 1;
 static int dlg_timer_procs = 0;
@@ -322,6 +323,7 @@ static param_export_t mod_params[]={
        { "end_timeout",           PARAM_INT, &dlg_end_timeout          },
        { "h_id_start",            PARAM_INT, &dlg_h_id_start           },
        { "h_id_step",             PARAM_INT, &dlg_h_id_step            },
+       { "keep_proxy_rr",         INT_PARAM, &dlg_keep_proxy_rr        },
        { 0,0,0 }
 };
 
@@ -528,6 +530,11 @@ static int mod_init(void)
                return -1;
        }
 
+       if (dlg_keep_proxy_rr < 0 || dlg_keep_proxy_rr > 3) {
+               LM_ERR("invalid value for keep_proxy_rr\n");
+               return -1;
+       }
+
        if (timeout_spec.s) {
                if ( pv_parse_spec(&timeout_spec, &timeout_avp)==0
                                && (timeout_avp.type!=PVT_AVP)){
@@ -655,7 +662,7 @@ static int mod_init(void)
 
        /* init handlers */
        init_dlg_handlers( rr_param, dlg_flag,
-               timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode);
+               timeout_spec.s?&timeout_avp:0, default_timeout, seq_match_mode, dlg_keep_proxy_rr);
 
        /* init timer */
        if (init_dlg_timer(dlg_ontimeout)!=0) {
index 7e8d72b..adb0278 100644 (file)
@@ -62,6 +62,7 @@ static int       dlg_flag_mask=0;     /*!< flag for dialog tracking */
 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       keep_proxy_rr;                /*!< keep the proxy's record-route in both route-sets */
 static int       shutdown_done = 0;    /*!< 1 when destroy_dlg_handlers was called */
 extern int       detect_spirals;
 extern int       dlg_timeout_noreset;
@@ -103,7 +104,7 @@ int dlg_set_tm_waitack(tm_cell_t *t, dlg_cell_t *dlg);
  */
 void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
                pv_spec_t *timeout_avp_p ,int default_timeout_p,
-               int seq_match_mode_p)
+               int seq_match_mode_p, int keep_proxy_rr_p)
 {
        rr_param.s = rr_param_p;
        rr_param.len = strlen(rr_param.s);
@@ -113,6 +114,7 @@ void init_dlg_handlers(char *rr_param_p, int dlg_flag_p,
        timeout_avp = timeout_avp_p;
        default_timeout = default_timeout_p;
        seq_match_mode = seq_match_mode_p;
+       keep_proxy_rr = keep_proxy_rr_p;
 }
 
 
@@ -184,7 +186,7 @@ static inline int add_dlg_rr_param(struct sip_msg *req, unsigned int entry,
 int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
        struct cell* t, unsigned int leg, str *tag)
 {
-       unsigned int skip_recs;
+       unsigned int skip_recs, own_rr = 0;
        str cseq;
        str contact;
        str rr_set;
@@ -233,11 +235,11 @@ int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
                skip_recs = 0;
        } else {
                /* was the 200 OK received or local generated */
-               skip_recs = dlg->from_rr_nb +
-                       ((t->relayed_reply_branch>=0)?
+               own_rr = ((t->relayed_reply_branch>=0)?
                                ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_R2)?2:
                                 ((t->uac[t->relayed_reply_branch].flags&TM_UAC_FLAG_RR)?1:0))
                                :0);
+               skip_recs = dlg->from_rr_nb + ((keep_proxy_rr & 1) > 0 ? 0 : own_rr);
        }
 
        if(msg->record_route){
@@ -269,6 +271,25 @@ int populate_leg_info( struct dlg_cell *dlg, struct sip_msg *msg,
 
        if (rr_set.s) pkg_free(rr_set.s);
 
+       if ((keep_proxy_rr & 2) > 0 && leg==DLG_CALLEE_LEG && msg->record_route && own_rr > 0) {
+               /* skip_recs contains the number of RR's for the callee */
+               skip_recs -= own_rr;
+               /* Add local RR's to caller's routeset */
+               if( print_rr_body(msg->record_route, &rr_set, DLG_CALLER_LEG,
+                                &skip_recs) != 0) {
+                       LM_ERR("failed to print route records \n");
+                       goto error0;
+               }
+               LM_DBG("updating caller route_set %.*s\n",
+                       rr_set.len, rr_set.s);
+               if (dlg_update_rr_set( dlg, DLG_CALLER_LEG, &rr_set)!=0) {
+                       LM_ERR("dlg_update_rr_set failed\n");
+                       if (rr_set.s) pkg_free(rr_set.s);
+                       goto error0;
+               }
+               if (rr_set.s) pkg_free(rr_set.s);
+       }
+
        return 0;
 error0:
        return -1;
index eb41797..3ff364a 100644 (file)
@@ -55,7 +55,7 @@
  */
 void init_dlg_handlers(char *rr_param, int dlg_flag,
                pv_spec_t *timeout_avp, int default_timeout,
-               int seq_match_mode);
+               int seq_match_mode, int keep_proxy_rr);
 
 
 /*!
index 6035a74..4e0e28b 100644 (file)
@@ -394,6 +394,12 @@ void destroy_dlg(struct dlg_cell *dlg)
        if (dlg->cseq[DLG_CALLEE_LEG].s)
                shm_free(dlg->cseq[DLG_CALLEE_LEG].s);
 
+       if (dlg->route_set[DLG_CALLER_LEG].s)
+               shm_free(dlg->route_set[DLG_CALLER_LEG].s);
+
+       if (dlg->route_set[DLG_CALLEE_LEG].s)
+               shm_free(dlg->route_set[DLG_CALLEE_LEG].s);
+
        if (dlg->toroute_name.s)
                shm_free(dlg->toroute_name.s);
 
@@ -518,7 +524,6 @@ struct dlg_cell* build_new_dlg( str *callid, str *from_uri, str *to_uri,
 int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
                                        str *cseq, unsigned int leg)
 {
-       char *p;
        str cs = {"0", 1};
 
        /* if we don't have cseq, set it to 0 */
@@ -528,7 +533,7 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
 
        if(dlg->tag[leg].s)
                shm_free(dlg->tag[leg].s);
-       dlg->tag[leg].s = (char*)shm_malloc( tag->len + rr->len );
+       dlg->tag[leg].s = (char*)shm_malloc(tag->len);
 
        if(dlg->cseq[leg].s) {
                if (dlg->cseq[leg].len < cs.len) {
@@ -548,8 +553,17 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
                dlg->contact[leg].s = (char*)shm_malloc( contact->len );
        }
 
+       if(dlg->route_set[leg].s) {
+               if (dlg->route_set[leg].len < rr->len) {
+                       shm_free(dlg->route_set[leg].s);
+                       dlg->route_set[leg].s = (char*)shm_malloc(rr->len);
+               }
+       } else {
+               dlg->route_set[leg].s = (char*)shm_malloc(rr->len);
+       }
+
        if ( dlg->tag[leg].s==NULL || dlg->cseq[leg].s==NULL
-                       || dlg->contact[leg].s==NULL) {
+                       || dlg->contact[leg].s==NULL || dlg->route_set[leg].s==NULL) {
                LM_ERR("no more shm mem\n");
                if (dlg->tag[leg].s)
                {
@@ -566,20 +580,23 @@ int dlg_set_leg_info(struct dlg_cell *dlg, str* tag, str *rr, str *contact,
                        shm_free(dlg->contact[leg].s);
                        dlg->contact[leg].s = NULL;
                }
+               if (dlg->route_set[leg].s)
+               {
+                       shm_free(dlg->route_set[leg].s);
+                       dlg->route_set[leg].s = NULL;
+               }
 
                return -1;
        }
-       p = dlg->tag[leg].s;
 
        /* tag */
        dlg->tag[leg].len = tag->len;
-       memcpy( p, tag->s, tag->len);
-       p += tag->len;
+       memcpy( dlg->tag[leg].s, tag->s, tag->len);
+
        /* rr */
        if (rr->len) {
-               dlg->route_set[leg].s = p;
                dlg->route_set[leg].len = rr->len;
-               memcpy( p, rr->s, rr->len);
+               memcpy(dlg->route_set[leg].s, rr->s, rr->len);
        }
 
        /* contact */
@@ -689,6 +706,55 @@ error:
 }
 
 
+/*!
+ * \brief Update or set the routeset for an existing dialog
+ * \param dlg dialog
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \param rr routeset
+ * \return 0 on success, -1 on failure
+ */
+int dlg_update_rr_set(struct dlg_cell * dlg, unsigned int leg, str *rr)
+{
+       dlg_entry_t *d_entry;
+
+       d_entry = &(d_table->entries[dlg->h_entry]);
+
+       dlg_lock(d_table, d_entry);
+
+       if ( dlg->route_set[leg].s ) {
+               if(dlg->route_set[leg].len == rr->len
+                               && memcmp(dlg->route_set[leg].s, rr->s, rr->len)==0) {
+                       LM_DBG("same route_set for leg[%d] - [%.*s]\n", leg,
+                               dlg->route_set[leg].len, dlg->route_set[leg].s);
+                       goto done;
+               }
+               if (dlg->route_set[leg].len < rr->len) {
+                       shm_free(dlg->route_set[leg].s);
+                       dlg->route_set[leg].s = (char*)shm_malloc(rr->len);
+                       if (dlg->route_set[leg].s==NULL)
+                               goto error;
+               }
+       } else {
+               dlg->route_set[leg].s = (char*)shm_malloc(rr->len);
+               if (dlg->route_set[leg].s==NULL)
+                       goto error;
+       }
+
+       memcpy( dlg->route_set[leg].s, rr->s, rr->len );
+       dlg->route_set[leg].len = rr->len;
+
+       LM_DBG("route_set of leg[%d] is %.*s\n", leg,
+                       dlg->route_set[leg].len, dlg->route_set[leg].s);
+done:
+       dlg_unlock(d_table, d_entry);
+       return 0;
+error:
+       dlg_unlock(d_table, d_entry);
+       LM_ERR("not more shm mem\n");
+       return -1;
+}
+
+
 /*!
  * \brief Lookup a dialog in the global list
  *
index 85fdc6c..33b36a7 100644 (file)
@@ -291,6 +291,15 @@ int dlg_update_contact(struct dlg_cell * dlg, unsigned int leg, str *ct);
  */
 int dlg_update_cseq(dlg_cell_t *dlg, unsigned int leg, str *cseq);
 
+/*!
+ * \brief Update or set the routeset for an existing dialog
+ * \param dlg dialog
+ * \param leg must be either DLG_CALLER_LEG, or DLG_CALLEE_LEG
+ * \param rr routeset
+ * \return 0 on success, -1 on failure
+ */
+int dlg_update_rr_set(struct dlg_cell * dlg, unsigned int leg, str *rr);
+
 /*!
  * \brief Set time-out route
  * \param dlg dialog
index c74140e..ff60006 100644 (file)
@@ -1604,6 +1604,42 @@ modparam("dialog", "h_id_step", 10)
 
        </section>
 
+       <section id="dialog.p.keep_proxy_rr">
+               <title><varname>keep_proxy_rr</varname> (string)</title>
+               <para>
+                       Whether to keep the record-route header added by the proxy.
+                       When enabled, it will keep this proxy&apos;s record-route
+                       header from the reply. The result is that generated requests
+                       like the BYE from the dlg_end_dlg mi function will pass
+                       through the proxy (looped).
+               </para>
+               <para>
+                       Valid values are:
+               </para>
+               <itemizedlist>
+                       <listitem><para>
+                               <emphasis>0</emphasis> - Don&apos;t keep any proxy Record-Route headers
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>1</emphasis> - Keep Record-route headers for the callee leg
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>2</emphasis> - Keep Record-route headers for the caller leg
+                       </para></listitem>
+                       <listitem><para>
+                               <emphasis>3</emphasis> - Keep Record-route headers for both legs
+                       </para></listitem>
+               </itemizedlist>
+               <emphasis>
+                       Default value is <quote>0</quote>.
+               </emphasis>
+               <title>Set <varname>dlg_keep_proxy_rr</varname> parameter</title>
+               <programlisting format="linespecific">
+...
+modparam("dialog", "keep_proxy_rr", 1)
+</programlisting>
+               </example>
+       </section>
 
        <section>
        <title>Functions</title>