[svn-commits] murf: branch murf/bug11210 r94807 - /team/murf/bug11210/channels/chan_sip.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Dec 26 14:24:28 CST 2007
Author: murf
Date: Wed Dec 26 14:24:27 2007
New Revision: 94807
URL: http://svn.digium.com/view/asterisk?view=rev&rev=94807
Log:
Seems only practical that this code survive a 'sip reload' without a crash. And, I temporarily rewrote find_call to use rizzo's callback-linear-search approach when pedantic is turned on.
Modified:
team/murf/bug11210/channels/chan_sip.c
Modified: team/murf/bug11210/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/murf/bug11210/channels/chan_sip.c?view=diff&rev=94807&r1=94806&r2=94807
==============================================================================
--- team/murf/bug11210/channels/chan_sip.c (original)
+++ team/murf/bug11210/channels/chan_sip.c Wed Dec 26 14:24:27 2007
@@ -3256,7 +3256,6 @@
if (peer->dnsmgr)
ast_dnsmgr_release(peer->dnsmgr);
clear_peer_mailboxes(peer);
- ast_free(peer);
}
/*! \brief Update peer data in database (if used) */
@@ -3557,7 +3556,6 @@
ruserobjs--;
else
suserobjs--;
- ast_free(user);
}
/*! \brief Load user from realtime storage
@@ -4084,7 +4082,7 @@
p->packets = p->packets->next;
if (cp->retransid > -1) {
ast_log(LOG_WARNING,"About to sched_del retransid(%d) in __sip_destroy\n", cp->retransid);
- ast_sched_del(sched, cp->retransid); /* HUH??? */
+ ast_sched_del(sched, cp->retransid); /* HUH??? well, ok, sip_pkt's are not refcounted objects */
}
cp->owner = dialog_unref(cp->owner,"free cp->owner dialog before freeing the pkt");
@@ -4099,8 +4097,6 @@
ast_string_field_free_memory(p);
ast_log(LOG_NOTICE,"Destroying dialog;\n");
-
- ast_free(p);
}
/*! \brief update_call_counter: Handle call_limit for SIP users
@@ -5523,6 +5519,57 @@
return p;
}
+/*! \brief argument to the helper function to identify a call */
+struct find_call_cb_arg {
+ enum sipmethod method;
+ const char *callid;
+ const char *fromtag;
+ const char *totag;
+ const char *tag;
+};
+
+/*!
+ * code to determine whether this is the pvt that we are looking for.
+ * Return FALSE if not found, true otherwise. p is unlocked.
+ */
+static int find_call_cb(void *__p, void *__arg, int flags)
+{
+ struct sip_pvt *p = __p;
+ struct find_call_cb_arg *arg = __arg;
+ /* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
+ int found = FALSE;
+ static int prof_id = -1;
+ if (prof_id == -1)
+ prof_id = ast_add_profile("find_call_cb", 0);
+
+ ast_mark(prof_id, 1);
+ if (!ast_strlen_zero(p->callid)) { /* XXX double check, do we allow match on empty p->callid ? */
+ if (arg->method == SIP_REGISTER)
+ found = (!strcmp(p->callid, arg->callid));
+ else
+ found = (!strcmp(p->callid, arg->callid) &&
+ (!pedanticsipchecking || !arg->tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, arg->tag))) ;
+
+ ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
+
+ /* If we get a new request within an existing to-tag - check the to tag as well */
+ if (pedanticsipchecking && found && arg->method != SIP_RESPONSE) { /* SIP Request */
+ if (p->tag[0] == '\0' && arg->totag[0]) {
+ /* We have no to tag, but they have. Wrong dialog */
+ found = FALSE;
+ } else if (arg->totag[0]) { /* Both have tags, compare them */
+ if (strcmp(arg->totag, p->tag)) {
+ found = FALSE; /* This is not our packet */
+ }
+ }
+ if (!found)
+ ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, arg->totag, sip_methods[arg->method].text);
+ }
+ }
+ ast_mark(prof_id, 0);
+ return found;
+}
+
/*! \brief find or create a dialog structure for an incoming SIP message.
* Connect incoming SIP message to current dialog or create new dialog structure
* Returns a reference to the sip_pvt object, remember to give it back once done.
@@ -5534,17 +5581,38 @@
char *tag = ""; /* note, tag is never NULL */
char totag[128];
char fromtag[128];
+ struct find_call_cb_arg arg;
const char *callid = get_header(req, "Call-ID");
const char *from = get_header(req, "From");
const char *to = get_header(req, "To");
const char *cseq = get_header(req, "Cseq");
struct sip_pvt tmp_dialog, *sip_pvt_ptr;
+ static int prof_head = -1, prof_find = -1, prof_tail = -1;
+ if (prof_head == -1) {
+ prof_head = ast_add_profile("find_call-headers", 0);
+ prof_find = ast_add_profile("find_call-find", 0);
+ prof_tail = ast_add_profile("find_call-tail", 0);
+ }
+ ast_mark(prof_head, 1);
+
+ callid = get_header(req, "Call-ID");
+ from = get_header(req, "From");
+ to = get_header(req, "To");
+ cseq = get_header(req, "Cseq");
+ ast_mark(prof_head, 0);
+
/* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
/* get_header always returns non-NULL so we must use ast_strlen_zero() */
if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
ast_strlen_zero(from) || ast_strlen_zero(cseq))
return NULL; /* Invalid packet */
+
+ arg.method = req->method;
+ arg.callid = callid;
+ arg.fromtag = fromtag;
+ arg.totag = totag;
+ arg.tag = ""; /* make sure tag is never NULL */
if (pedanticsipchecking) {
/* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
@@ -5572,67 +5640,53 @@
return NULL;
}
}
+
+ ast_mark(prof_find, 1);
+
+ if (!pedanticsipchecking) {
+ if (!ast_string_field_init(&tmp_dialog, 100)) {
+ int rc;
+ ast_string_field_set(&tmp_dialog, callid, callid);
+
+ sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find in dialogs");
+ if (sip_pvt_ptr) {
+ rc = ao2_ref(sip_pvt_ptr,0,"");
+ ast_log(LOG_NOTICE,"Found CALL dialog %s, refcount = %d\n", tmp_dialog.callid, rc);
+ }
+
+ if (!sip_pvt_ptr) {
+ struct ao2_iterator i;
+ struct sip_pvt *d2;
+
+ ast_log(LOG_NOTICE,"Dialog %s not found\n", callid);
+ i = ao2_iterator_init(dialogs, 0);
+
+ while ((d2 = ao2_iterator_next(&i,"iterate thru dialogs "))) {
+ ast_log(LOG_NOTICE, "Dialogs: %s\n", d2->callid);
+ ao2_ref(d2,-1,"done with d2 pointer");
+ }
+ }
+ ast_string_field_free_memory(&tmp_dialog);
+ if (sip_pvt_ptr) { /* well, if we don't find it-- what IS in there? */
+ /* Found the call */
+ sip_pvt_lock(sip_pvt_ptr);
+ dialoglist_unlock();
+ return sip_pvt_ptr;
+ }
+ } else { /* in pedantic mode! -- do the fancy linear search */
+ p = ao2_callback(dialogs, 0 /* single, data */, find_call_cb, &arg, "pedantic linear search for dialog");
+ if (p) {
+ sip_pvt_lock(p);
+ ast_mark(prof_find, 0);
+ return p;
+ }
+ }
+
+ }
+ ast_mark(prof_find, 0);
- dialoglist_lock();
- if (!ast_string_field_init(&tmp_dialog, 100)) {
- int rc;
- ast_string_field_set(&tmp_dialog, callid, callid);
-
- sip_pvt_ptr = ao2_find(dialogs, &tmp_dialog, OBJ_POINTER, "ao2_find in dialogs");
- if (sip_pvt_ptr) {
- rc = ao2_ref(sip_pvt_ptr,0,"");
- ast_log(LOG_NOTICE,"Found CALL dialog %s, refcount = %d\n", tmp_dialog.callid, rc);
- if (!(!pedanticsipchecking || !tag || ast_strlen_zero(sip_pvt_ptr->theirtag) || !strcmp(sip_pvt_ptr->theirtag, tag)))
- {
- ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (1)\n", callid);
-
- ao2_ref(sip_pvt_ptr,-1,"pedantic failure, pointer erase"); /* basically, if the extra pedanticssipchecking constraints don't pan out,
- the the match is defeated. There should be no other entry that matches
- the callid */
- sip_pvt_ptr = NULL;
- }
- /* If we get a new request within an existing to-tag - check the to tag as well */
- if (pedanticsipchecking && sip_pvt_ptr && req->method != SIP_RESPONSE) { /* SIP Request */
- if (sip_pvt_ptr->tag[0] == '\0' && totag[0]) {
- /* We have no to tag, but they have. Wrong dialog */
- ao2_ref(sip_pvt_ptr,-1,"pedantic failure, pointer erased 2");
- sip_pvt_ptr = NULL;
- ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (2)\n", callid);
- } else if (totag[0]) { /* Both have tags, compare them */
- if (strcmp(totag, sip_pvt_ptr->tag)) {
- ao2_ref(sip_pvt_ptr,-1, "pedantic totag failure, pointer erased 3");
- sip_pvt_ptr = NULL; /* This is not our packet */
- ast_log(LOG_NOTICE,"Pedantic Zero of dialog %s (3)\n", callid);
- }
- }
- if (!sip_pvt_ptr)
- ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", sip_pvt_ptr->callid, totag, sip_methods[req->method].text);
- }
- }
-
- ast_string_field_free_memory(&tmp_dialog);
- if (!sip_pvt_ptr) {
- struct ao2_iterator i;
- struct sip_pvt *d2;
-
- ast_log(LOG_NOTICE,"Dialog %s not found\n", callid);
- i = ao2_iterator_init(dialogs, 0);
-
- while ((d2 = ao2_iterator_next(&i,"iterate thru dialogs "))) {
- ast_log(LOG_NOTICE, "Dialogs: %s\n", d2->callid);
- ao2_ref(d2,-1,"done with d2 pointer");
- }
- }
-
- if (sip_pvt_ptr) {
- /* Found the call */
- sip_pvt_lock(sip_pvt_ptr);
- dialoglist_unlock();
- return sip_pvt_ptr;
- }
- }
- dialoglist_unlock();
-
+ ast_mark(prof_tail, 1);
+
/* See if the method is capable of creating a dialog */
if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG) {
if (intended_method == SIP_REFER) {
@@ -5660,6 +5714,7 @@
ast_debug(4, "Failed allocating SIP dialog, sending 500 Server internal error and giving up\n");
}
}
+ ast_mark(prof_tail, 0);
return p; /* can be NULL */
} else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
/* A method we do not support, let's take it on the volley */
@@ -5675,7 +5730,8 @@
if (intended_method == SIP_RESPONSE)
ast_debug(2, "That's odd... Got a response on a call we dont know about. Callid %s\n", callid ? callid : "<unknown>");
- return p; /* most likely null if returning here */
+ ast_mark(prof_tail, 0);
+ return NULL;
}
/*! \brief Parse register=> line in sip.conf and add to registry */
@@ -9138,7 +9194,6 @@
{
struct sip_peer *peer = (struct sip_peer *)data;
- ast_log(LOG_NOTICE,"SCHED: sip_poke_peer_s called---\n");
peer->pokeexpire = -1;
sip_poke_peer(peer);
return 0;
@@ -11836,7 +11891,7 @@
if (!ast_test_flag(&user->flags[1], SIP_PAGE2_RTCACHEFRIENDS)) {
ast_cli(a->fd, "User '%s' is not a Realtime user, cannot be pruned.\n", name);
/* put it back! */
- ao2_link(users, user, "link user into users table");
+ ao2_link(users, user, "link unlinked user back into users table");
} else
ast_cli(a->fd, "User '%s' pruned.\n", name);
unref_user(user,"unref_user: Tossing temp user ptr");
@@ -18328,7 +18383,6 @@
{
struct sip_user *user;
int format;
- struct ast_ha *oldha = NULL;
struct ast_flags userflags[2] = {{(0)}};
struct ast_flags mask[2] = {{(0)}};
@@ -18339,7 +18393,6 @@
suserobjs++;
ast_copy_string(user->name, name, sizeof(user->name));
- oldha = user->ha;
user->ha = NULL;
ast_copy_flags(&user->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&user->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
@@ -18436,7 +18489,6 @@
ast_copy_flags(&user->flags[1], &userflags[1], mask[1].flags);
if (ast_test_flag(&user->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))
global_allowsubscribe = TRUE; /* No global ban any more */
- ast_free_ha(oldha);
return user;
}
@@ -18864,6 +18916,8 @@
struct sockaddr_in old_bindaddr = bindaddr;
int registry_count = 0, peer_count = 0, user_count = 0;
+ ast_log(LOG_NOTICE,"reload_config begun...\n");
+
cfg = ast_config_load(config, config_flags);
/* We *must* have a config file otherwise stop immediately */
@@ -18882,6 +18936,7 @@
ucfg = ast_config_load("users.conf", config_flags);
}
+ ast_log(LOG_NOTICE,"reload_config 2...\n");
if (reason != CHANNEL_MODULE_LOAD) {
ast_debug(4, "--------------- SIP reload started\n");
@@ -18911,8 +18966,11 @@
ASTOBJ_CONTAINER_DESTROYALL(®l, sip_registry_destroy);
ast_debug(4, "--------------- Done destroying registry list\n");
ao2_callback(peers, OBJ_NODATA, peer_markall_func, 0, "callback to mark all peers");
- }
-
+ /* reinstate the user table */
+ users = ao2_container_alloc(hash_user_size, user_hash_cb, user_cmp_cb,"allocate users");
+ }
+
+ ast_log(LOG_NOTICE,"reload_config 3...\n");
/* Initialize copy of current global_regcontext for later use in removing stale contexts */
ast_copy_string(oldcontexts, global_regcontext, sizeof(oldcontexts));
oldregcontext = oldcontexts;
@@ -18951,6 +19009,7 @@
externexpire = 0; /* Expiration for DNS re-issuing */
externrefresh = 10;
+ ast_log(LOG_NOTICE,"reload_config 4...\n");
/* Reset channel settings to default before re-configuring */
allow_external_domains = DEFAULT_ALLOW_EXT_DOM; /* Allow external invites */
global_regcontext[0] = '\0';
@@ -19020,6 +19079,7 @@
ast_clear_flag(&global_flags[1], SIP_PAGE2_VIDEOSUPPORT);
ast_clear_flag(&global_flags[1], SIP_PAGE2_TEXTSUPPORT);
+ ast_log(LOG_NOTICE,"reload_config 5...\n");
/* Read the [general] config section of sip.conf (or from realtime config) */
for (v = ast_variable_browse(cfg, "general"); v; v = v->next) {
if (handle_common_options(&global_flags[0], &dummy[0], v))
@@ -19316,6 +19376,7 @@
allow_external_domains = 1;
}
+ ast_log(LOG_NOTICE,"reload_config 6...\n");
/* Build list of authentication to various SIP realms, i.e. service providers */
for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
/* Format for authentication is auth = username:password at realm */
@@ -19376,6 +19437,7 @@
}
+ ast_log(LOG_NOTICE,"reload_config 7...\n");
/* Load peers, users and friends */
cat = NULL;
while ( (cat = ast_category_browse(cfg, cat)) ) {
@@ -19417,6 +19479,7 @@
}
}
}
+ ast_log(LOG_NOTICE,"reload_config 8...\n");
bindaddr.sin_family = AF_INET;
internip = bindaddr;
if (ast_find_ourip(&internip.sin_addr, bindaddr)) {
@@ -19466,6 +19529,7 @@
ast_debug(1, "STUN sees us at %s:%d\n",
ast_inet_ntoa(externip.sin_addr) , ntohs(externip.sin_port));
}
+ ast_log(LOG_NOTICE,"reload_config 9...\n");
ast_mutex_unlock(&netlock);
/* Add default domains - host name, IP address and IP:port */
@@ -19494,16 +19558,20 @@
add_sip_domain(temp, SIP_DOMAIN_AUTO, NULL);
}
+ ast_log(LOG_NOTICE,"reload_config 10...\n");
/* Release configuration from memory */
ast_config_destroy(cfg);
+ ast_log(LOG_NOTICE,"reload_config 11...\n");
/* Load the list of manual NOTIFY types to support */
if (notify_types)
ast_config_destroy(notify_types);
notify_types = ast_config_load(notify_config, config_flags);
+ ast_log(LOG_NOTICE,"reload_config 12...\n");
/* Done, tell the manager */
manager_event(EVENT_FLAG_SYSTEM, "ChannelReload", "ChannelType: SIP\r\nReloadReason: %s\r\nRegistry_Count: %d\r\nPeer_Count: %d\r\nUser_Count: %d\r\n", channelreloadreason2txt(reason), registry_count, peer_count, user_count);
+ ast_log(LOG_NOTICE,"reload_config done...\n");
return 0;
}
More information about the svn-commits
mailing list