Module: sip-router
Branch: master
Commit: 6fb686de57f783b3c29e5b4e11ad1509882616bb
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=6fb686de57f783b3c29e5b4e11ad1509882616bb

Author: Daniel-Constantin Mierla <[email protected]>
Committer: Daniel-Constantin Mierla <[email protected]>
Date:   Thu Aug 14 17:49:18 2014 +0200

dialog: when adding a new dialog, lock the slot until the structure is linked

- search for dialog based on sip attributes and if no result found, then
  lock the hash table slot until the new structure is built and linked
  in the table
- should avoid simulataneous creation for same dialog if there is a
  not-handled retransmission or parallel forking upstream, resulting in
  many processing managing duplicated requests

---

 modules/dialog/dlg_db_handler.c |    2 +-
 modules/dialog/dlg_handlers.c   |   45 +++++++++++++++-----------
 modules/dialog/dlg_hash.c       |   65 +++++++++++++++++++++++++++++++++++---
 modules/dialog/dlg_hash.h       |   31 ++++++++++++++++++-
 4 files changed, 116 insertions(+), 27 deletions(-)

diff --git a/modules/dialog/dlg_db_handler.c b/modules/dialog/dlg_db_handler.c
index f61aae5..7e83729 100644
--- a/modules/dialog/dlg_db_handler.c
+++ b/modules/dialog/dlg_db_handler.c
@@ -360,7 +360,7 @@ static int load_dialog_info_from_db(int dlg_hash_size, int 
fetch_num_rows)
                        }
 
                        /*link the dialog*/
-                       link_dlg(dlg, 0);
+                       link_dlg(dlg, 0, 0);
 
                        dlg->h_id = VAL_INT(values+1);
                        next_id = d_table->entries[dlg->h_entry].next_id;
diff --git a/modules/dialog/dlg_handlers.c b/modules/dialog/dlg_handlers.c
index a0daa39..093b774 100644
--- a/modules/dialog/dlg_handlers.c
+++ b/modules/dialog/dlg_handlers.c
@@ -776,6 +776,7 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
     str ttag;
     str req_uri;
     unsigned int dir;
+    int mlock;
 
        dlg = dlg_get_ctx_dialog();
     if(dlg != NULL) {
@@ -800,18 +801,20 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
     }
     trim(&req_uri);
 
-    if (detect_spirals)
-    {
-        if (spiral_detected == 1)
-            return 0;
-
-        dir = DLG_DIR_NONE;
+       dir = DLG_DIR_NONE;
+       mlock = 1;
+       /* search dialog by SIP attributes
+        * - if not found, hash table slot is left locked, to avoid races
+        *   to add 'same' dialog on parallel forking or not-handled-yet
+        *   retransmissions. Release slot after linking new dialog */
+       dlg = search_dlg(&callid, &ftag, &ttag, &dir);
+       if(dlg) {
+               mlock = 0;
+               if (detect_spirals) {
+                       if (spiral_detected == 1)
+                               return 0;
 
-        dlg = get_dlg(&callid, &ftag, &ttag, &dir);
-        if (dlg)
-        {
-                       if ( dlg->state != DLG_STATE_DELETED )
-                       {
+                       if ( dlg->state != DLG_STATE_DELETED ) {
                                LM_DBG("Callid '%.*s' found, must be a spiraled 
request\n",
                                        callid.len, callid.s);
                                spiral_detected = 1;
@@ -819,9 +822,12 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
                                if (run_initial_cbs)
                                        run_dlg_callbacks( DLGCB_SPIRALED, dlg, 
req, NULL,
                                                        DLG_DIR_DOWNSTREAM, 0);
-                               /* get_dlg() has incremented the ref count by 1 
*/
+                               /* set ctx dlg id shortcuts */
+                               _dlg_ctx.iuid.h_entry = dlg->h_entry;
+                               _dlg_ctx.iuid.h_id = dlg->h_id;
+                               /* search_dlg() has incremented the ref count 
by 1 */
                                dlg_release(dlg);
-                               goto finish;
+                               return 0;
                        }
                        dlg_release(dlg);
         }
@@ -834,16 +840,16 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
                          &ftag/*from_tag*/,
                          &req_uri /*r-uri*/ );
 
-       if (dlg==0)
-       {
+       if (dlg==0) {
+               if(likely(mlock==1)) dlg_hash_release(&callid);
                LM_ERR("failed to create new dialog\n");
                return -1;
        }
 
        /* save caller's tag, cseq, contact and record route*/
        if (populate_leg_info(dlg, req, t, DLG_CALLER_LEG,
-                       &(get_from(req)->tag_value)) !=0)
-       {
+                       &(get_from(req)->tag_value)) !=0) {
+               if(likely(mlock==1)) dlg_hash_release(&callid);
                LM_ERR("could not add further info to the dialog\n");
                shm_free(dlg);
                return -1;
@@ -852,7 +858,9 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
        /* Populate initial varlist: */
        dlg->vars = get_local_varlist_pointer(req, 1);
 
-       link_dlg(dlg, 0);
+       /* if search_dlg() returned NULL, slot was kept locked */
+       link_dlg(dlg, 0, mlock);
+       if(likely(mlock==1)) dlg_hash_release(&callid);
 
        dlg->lifetime = get_dlg_timeout(req);
        s.s   = _dlg_ctx.to_route_name;
@@ -876,7 +884,6 @@ int dlg_new_dialog(sip_msg_t *req, struct cell *t, const 
int run_initial_cbs)
     if_update_stat( dlg_enable_stats, processed_dlgs, 1);
 
        _dlg_ctx.cpid = my_pid();
-finish:
     _dlg_ctx.iuid.h_entry = dlg->h_entry;
     _dlg_ctx.iuid.h_id = dlg->h_id;
     set_current_dialog(req, dlg);
diff --git a/modules/dialog/dlg_hash.c b/modules/dialog/dlg_hash.c
index 8220104..1e27b3b 100644
--- a/modules/dialog/dlg_hash.c
+++ b/modules/dialog/dlg_hash.c
@@ -691,10 +691,12 @@ dlg_cell_t* dlg_get_by_iuid(dlg_iuid_t *diuid)
  * \param ftag from tag
  * \param ttag to tag
  * \param dir direction
+ * \param mode let hash table slot locked if dialog is not found
  * \return dialog structure on success, NULL on failure
  */
 static inline struct dlg_cell* internal_get_dlg(unsigned int h_entry,
-                                               str *callid, str *ftag, str 
*ttag, unsigned int *dir)
+                                               str *callid, str *ftag, str 
*ttag,
+                                               unsigned int *dir, int mode)
 {
        struct dlg_cell *dlg;
        struct dlg_entry *d_entry;
@@ -714,7 +716,7 @@ static inline struct dlg_cell* internal_get_dlg(unsigned 
int h_entry,
                }
        }
 
-       dlg_unlock( d_table, d_entry);
+       if(likely(mode==0)) dlg_unlock( d_table, d_entry);
        LM_DBG("no dialog callid='%.*s' found\n", callid->len, callid->s);
        return 0;
 }
@@ -743,7 +745,7 @@ struct dlg_cell* get_dlg( str *callid, str *ftag, str 
*ttag, unsigned int *dir)
        unsigned int he;
 
        he = core_hash(callid, 0, d_table->size);
-       dlg = internal_get_dlg(he, callid, ftag, ttag, dir);
+       dlg = internal_get_dlg(he, callid, ftag, ttag, dir, 0);
 
        if (dlg == 0) {
                LM_DBG("no dialog callid='%.*s' found\n", callid->len, 
callid->s);
@@ -754,17 +756,68 @@ struct dlg_cell* get_dlg( str *callid, str *ftag, str 
*ttag, unsigned int *dir)
 
 
 /*!
+ * \brief Search dialog that corresponds to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:
+ * "The combination of the To tag, From tag, and Call-ID completely
+ * defines a peer-to-peer SIP relationship between [two UAs] and is
+ * referred to as a dialog."
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * If the dialog is not found, the hash slot is left locked, to allow
+ * linking the structure of a new dialog.
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure (and slot locked)
+ */
+dlg_cell_t* search_dlg( str *callid, str *ftag, str *ttag, unsigned int *dir)
+{
+       struct dlg_cell *dlg;
+       unsigned int he;
+
+       he = core_hash(callid, 0, d_table->size);
+       dlg = internal_get_dlg(he, callid, ftag, ttag, dir, 1);
+
+       if (dlg == 0) {
+               LM_DBG("dialog with callid='%.*s' not found\n", callid->len, 
callid->s);
+               return 0;
+       }
+       return dlg;
+}
+
+
+/*!
+ * \brief Release hash table slot by call-id
+ * \param callid call-id value
+ */
+void dlg_hash_release(str *callid)
+{
+       unsigned int he;
+       struct dlg_entry *d_entry;
+
+       he = core_hash(callid, 0, d_table->size);
+       d_entry = &(d_table->entries[he]);
+       dlg_unlock(d_table, d_entry);
+}
+
+
+
+/*!
  * \brief Link a dialog structure
  * \param dlg dialog
  * \param n extra increments for the reference counter
+ * \param mode link in safe mode (0 - lock slot; 1 - don't)
  */
-void link_dlg(struct dlg_cell *dlg, int n)
+void link_dlg(struct dlg_cell *dlg, int n, int mode)
 {
        struct dlg_entry *d_entry;
 
        d_entry = &(d_table->entries[dlg->h_entry]);
 
-       dlg_lock( d_table, d_entry);
+       if(unlikely(mode==0)) dlg_lock( d_table, d_entry);
 
        /* keep id 0 for special cases */
        dlg->h_id = 1 + d_entry->next_id++;
@@ -780,7 +833,7 @@ void link_dlg(struct dlg_cell *dlg, int n)
 
        ref_dlg_unsafe(dlg, 1+n);
 
-       dlg_unlock( d_table, d_entry);
+       if(unlikely(mode==0)) dlg_unlock( d_table, d_entry);
        return;
 }
 
diff --git a/modules/dialog/dlg_hash.h b/modules/dialog/dlg_hash.h
index ec3ffbb..8798ccc 100644
--- a/modules/dialog/dlg_hash.h
+++ b/modules/dialog/dlg_hash.h
@@ -318,11 +318,40 @@ dlg_cell_t* get_dlg(str *callid, str *ftag, str *ttag, 
unsigned int *dir);
 
 
 /*!
+ * \brief Search dialog that corresponds to CallId, From Tag and To Tag
+ *
+ * Get dialog that correspond to CallId, From Tag and To Tag.
+ * See RFC 3261, paragraph 4. Overview of Operation:
+ * "The combination of the To tag, From tag, and Call-ID completely
+ * defines a peer-to-peer SIP relationship between [two UAs] and is
+ * referred to as a dialog."
+ * Note that the caller is responsible for decrementing (or reusing)
+ * the reference counter by one again if a dialog has been found.
+ * If the dialog is not found, the hash slot is left locked, to allow
+ * linking the structure of a new dialog.
+ * \param callid callid
+ * \param ftag from tag
+ * \param ttag to tag
+ * \param dir direction
+ * \return dialog structure on success, NULL on failure (and slot locked)
+ */
+dlg_cell_t* search_dlg(str *callid, str *ftag, str *ttag, unsigned int *dir);
+
+
+/*!
+ * \brief Release hash table slot by call-id
+ * \param callid call-id value
+ */
+void dlg_hash_release(str *callid);
+
+
+/*!
  * \brief Link a dialog structure
  * \param dlg dialog
  * \param n extra increments for the reference counter
+ * \param mode link in safe mode (0 - lock slot; 1 - don't)
  */
-void link_dlg(dlg_cell_t *dlg, int n);
+void link_dlg(struct dlg_cell *dlg, int n, int mode);
 
 
 /*!


_______________________________________________
sr-dev mailing list
[email protected]
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev

Reply via email to