Module: sip-router
Branch: master
Commit: 6fb686de57f783b3c29e5b4e11ad1509882616bb
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=6fb686d…
Author: Daniel-Constantin Mierla <miconda(a)gmail.com>
Committer: Daniel-Constantin Mierla <miconda(a)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);
/*!