[sr-dev] git:master: dialog: when adding a new dialog, lock the slot until the structure is linked

Daniel-Constantin Mierla miconda at gmail.com
Thu Aug 14 17:52:26 CEST 2014


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 <miconda at gmail.com>
Committer: Daniel-Constantin Mierla <miconda at gmail.com>
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);
 
 
 /*!




More information about the sr-dev mailing list