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
