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

Author: Alex Balashov <[email protected]>
Committer: Alex Balashov <[email protected]>
Date:   Fri Dec 21 21:08:39 2012 -0500

dialog(k): Reworked dlg_set_timeout_by_profile() code to change dialog
timeouts outside of a profile lock.

This is in order to avoid deadlock complications arising from lock/ref
count operations upstream.  It appears that when update_dlg_timer()
fails, it does not relinquish control back to the calling function, which
created problems with unreleased profile locks.

---

 modules_k/dialog/dlg_profile.c |   78 ++++++++++++++++++++++++++++++++++------
 1 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/modules_k/dialog/dlg_profile.c b/modules_k/dialog/dlg_profile.c
index 41802ea..5b388d8 100644
--- a/modules_k/dialog/dlg_profile.c
+++ b/modules_k/dialog/dlg_profile.c
@@ -714,9 +714,23 @@ int        is_known_dlg(struct sip_msg *msg) {
 int    dlg_set_timeout_by_profile(struct dlg_profile_table *profile, 
                                   str *value, int timeout) 
 {
-       unsigned int            i;
+       unsigned int            i = 0;
+       dlg_cell_t              *this_dlg = NULL;
        struct dlg_profile_hash *ph = NULL;
 
+       /* Private structure necessary for manipulating dialog 
+         * timeouts outside of profile locks.  Admittedly, an
+         * ugly hack, but avoids some concurrency issues.
+         */
+
+       struct dlg_map_list {
+               unsigned int            h_id;
+               unsigned int            h_entry;
+               struct dlg_map_list     *next;
+       } *map_head, *map_scan, *map_scan_next;
+
+       map_head = NULL;
+
        /* If the profile has no value, iterate through every 
         * node and set its timeout.
         */
@@ -730,11 +744,23 @@ int       dlg_set_timeout_by_profile(struct 
dlg_profile_table *profile,
                        if(!ph) continue;
                        
                        do { 
-                               if(update_dlg_timeout(ph->dlg, timeout) < 0) {
-                                       lock_release(&profile->lock);
+                               struct dlg_map_list *d = malloc(sizeof(struct 
dlg_map_list));
+
+                               if(!d)
                                        return -1;
-                               }
 
+                               memset(d, 0, sizeof(struct dlg_map_list));
+
+                               d->h_id = ph->dlg->h_id;
+                               d->h_entry = ph->dlg->h_entry;
+
+                               if(map_head == NULL)
+                                       map_head = d;
+                               else {
+                                       d->next = map_head;
+                                       map_head = d;
+                               }
+       
                                ph = ph->next;
                        } while(ph != profile->entries[i].first);
                } 
@@ -750,15 +776,24 @@ int       dlg_set_timeout_by_profile(struct 
dlg_profile_table *profile,
                ph = profile->entries[i].first;
 
                if(ph) {
-                       do { 
-                               if(value->len == ph->value.len &&
-                                  memcmp(value->s, ph->value.s, 
-                                         value->len) == 0) {
+                       do {
+                               if(ph && value->len == ph->value.len &&
+                                  memcmp(value->s, ph->value.s, value->len) == 
0) {
+                                       struct dlg_map_list *d = 
malloc(sizeof(struct dlg_map_list));
 
-                                       if(update_dlg_timeout(ph->dlg, 
-                                                       timeout) < 0) {
-                                               lock_release(&profile->lock);
+                                       if(!d)
                                                return -1;
+
+                                       memset(d, 0, sizeof(struct 
dlg_map_list));
+
+                                       d->h_id = ph->dlg->h_id;
+                                       d->h_entry = ph->dlg->h_entry;
+
+                                       if(map_head == NULL)
+                                               map_head = d;
+                                       else {
+                                               d->next = map_head;
+                                               map_head = d;
                                        }
                                }
 
@@ -769,6 +804,27 @@ int        dlg_set_timeout_by_profile(struct 
dlg_profile_table *profile,
                lock_release(&profile->lock);
        }
 
+       /* Walk the list and bulk-set the timeout */
+       
+       for(map_scan = map_head; map_scan != NULL; map_scan = map_scan_next) {
+               map_scan_next = map_scan->next;
+
+               this_dlg = dlg_lookup(map_scan->h_entry, map_scan->h_id);
+
+               if(!this_dlg) {
+                       LM_CRIT("Unable to find dialog %d:%d\n", 
map_scan->h_entry, map_scan->h_id);
+               } else if(this_dlg->state >= DLG_STATE_EARLY) { 
+                       if(update_dlg_timeout(this_dlg, timeout) < 0) {
+                                       LM_ERR("Unable to set timeout on 
%d:%d\n", map_scan->h_entry,
+                                       map_scan->h_id);
+                       }
+
+                       dlg_release(this_dlg);
+               }
+
+               free(map_scan);
+       }
+
        return 0;
 }
 


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

Reply via email to