mirror of
https://github.com/asterisk/asterisk.git
synced 2026-07-23 16:05:30 -07:00
Merged revisions 87686 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r87686 | russell | 2007-10-30 16:19:09 -0500 (Tue, 30 Oct 2007) | 11 lines Merge the changes from team/russell/iax2_poke_fix and iax2-poke-fix-trunk There was a race condition related to the handling of POKEing peers. Essentially, a reference to a peer is held by the scheduler when there are pending callbacks, but the reference count didn't reflect it. So, it was possible for a peer to hit a reference count of zero and have its destructor begin to be called at the same time that the scheduler thread ran a POKE related callback. If that happened, a crash would likely occur. (closes issue #11082, closes issue #11094) ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@87687 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
+96
-38
@@ -2288,7 +2288,7 @@ static char *handle_cli_iax2_prune_realtime(struct ast_cli_entry *e, int cmd, st
|
||||
} else if ((peer = find_peer(a->argv[3], 0))) {
|
||||
if(ast_test_flag(peer, IAX_RTCACHEFRIENDS)) {
|
||||
ast_set_flag(peer, IAX_RTAUTOCLEAR);
|
||||
expire_registry((const void *) peer->name);
|
||||
expire_registry(peer_ref(peer));
|
||||
ast_cli(a->fd, "Peer %s was removed from the cache.\n", a->argv[3]);
|
||||
} else {
|
||||
ast_cli(a->fd, "Peer %s is not eligible for this operation.\n", a->argv[3]);
|
||||
@@ -3006,8 +3006,15 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
|
||||
if (ast_test_flag((&globalflags), IAX_RTCACHEFRIENDS)) {
|
||||
ast_copy_flags(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
|
||||
if (ast_test_flag(peer, IAX_RTAUTOCLEAR)) {
|
||||
peer->expire = iax2_sched_replace(peer->expire, sched,
|
||||
(global_rtautoclear) * 1000, expire_registry, (const void *)peer->name);
|
||||
if (peer->expire > -1) {
|
||||
if (!ast_sched_del(sched, peer->expire)) {
|
||||
peer->expire = -1;
|
||||
peer_unref(peer);
|
||||
}
|
||||
}
|
||||
peer->expire = iax2_sched_add(sched, (global_rtautoclear) * 1000, expire_registry, peer_ref(peer));
|
||||
if (peer->expire == -1)
|
||||
peer_unref(peer);
|
||||
}
|
||||
ao2_link(peers, peer_ref(peer));
|
||||
if (ast_test_flag(peer, IAX_DYNAMIC))
|
||||
@@ -4818,8 +4825,19 @@ static char *handle_cli_iax2_unregister(struct ast_cli_entry *e, int cmd, struct
|
||||
p = find_peer(a->argv[2], 1);
|
||||
if (p) {
|
||||
if (p->expire > 0) {
|
||||
expire_registry(a->argv[2]);
|
||||
ast_cli(a->fd, "Peer %s unregistered\n", a->argv[2]);
|
||||
struct iax2_peer tmp_peer = {
|
||||
.name = a->argv[2],
|
||||
};
|
||||
struct iax2_peer *peer;
|
||||
|
||||
peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
|
||||
if (peer) {
|
||||
expire_registry(peer_ref(peer)); /* will release its own reference when done */
|
||||
peer_unref(peer); /* ref from ao2_find() */
|
||||
ast_cli(a->fd, "Peer %s unregistered\n", a->argv[2]);
|
||||
} else {
|
||||
ast_cli(a->fd, "Peer %s not found\n", a->argv[2]);
|
||||
}
|
||||
} else {
|
||||
ast_cli(a->fd, "Peer %s not registered\n", a->argv[2]);
|
||||
}
|
||||
@@ -6324,15 +6342,29 @@ static void register_peer_exten(struct iax2_peer *peer, int onoff)
|
||||
}
|
||||
static void prune_peers(void);
|
||||
|
||||
static void unlink_peer(struct iax2_peer *peer)
|
||||
{
|
||||
if (peer->expire > -1) {
|
||||
if (!ast_sched_del(sched, peer->expire)) {
|
||||
peer->expire = -1;
|
||||
peer_unref(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (peer->pokeexpire > -1) {
|
||||
if (!ast_sched_del(sched, peer->pokeexpire)) {
|
||||
peer->pokeexpire = -1;
|
||||
peer_unref(peer);
|
||||
}
|
||||
}
|
||||
|
||||
unlink_peer(peer);
|
||||
}
|
||||
|
||||
static void __expire_registry(const void *data)
|
||||
{
|
||||
const char *name = data;
|
||||
struct iax2_peer *peer = NULL;
|
||||
struct iax2_peer tmp_peer = {
|
||||
.name = name,
|
||||
};
|
||||
struct iax2_peer *peer = (struct iax2_peer *) data;
|
||||
|
||||
peer = ao2_find(peers, &tmp_peer, OBJ_POINTER);
|
||||
if (!peer)
|
||||
return;
|
||||
|
||||
@@ -6354,7 +6386,7 @@ static void __expire_registry(const void *data)
|
||||
iax2_regfunk(peer->name, 0);
|
||||
|
||||
if (ast_test_flag(peer, IAX_RTAUTOCLEAR))
|
||||
ao2_unlink(peers, peer);
|
||||
unlink_peer(peer);
|
||||
|
||||
peer_unref(peer);
|
||||
}
|
||||
@@ -6393,9 +6425,16 @@ static void reg_source_db(struct iax2_peer *p)
|
||||
p->addr.sin_family = AF_INET;
|
||||
p->addr.sin_addr = in;
|
||||
p->addr.sin_port = htons(atoi(c));
|
||||
ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
|
||||
p->expire = iax2_sched_replace(p->expire, sched,
|
||||
(p->expiry + 10) * 1000, expire_registry, (const void *)p->name);
|
||||
if (p->expire > -1) {
|
||||
if (!ast_sched_del(sched, p->expire)) {
|
||||
p->expire = -1;
|
||||
peer_unref(p);
|
||||
}
|
||||
}
|
||||
ast_device_state_changed("IAX2/%s", p->name); /* Activate notification */
|
||||
p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
|
||||
if (p->expire == -1)
|
||||
peer_unref(p);
|
||||
if (iax2_regfunk)
|
||||
iax2_regfunk(p->name, 1);
|
||||
register_peer_exten(p, 1);
|
||||
@@ -6482,8 +6521,12 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
|
||||
/* Store socket fd */
|
||||
p->sockfd = fd;
|
||||
/* Setup the expiry */
|
||||
if (p->expire > -1)
|
||||
ast_sched_del(sched, p->expire);
|
||||
if (p->expire > -1) {
|
||||
if (!ast_sched_del(sched, p->expire)) {
|
||||
p->expire = -1;
|
||||
peer_unref(p);
|
||||
}
|
||||
}
|
||||
/* treat an unspecified refresh interval as the minimum */
|
||||
if (!refresh)
|
||||
refresh = min_reg_expire;
|
||||
@@ -6498,8 +6541,11 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
|
||||
} else {
|
||||
p->expiry = refresh;
|
||||
}
|
||||
if (p->expiry && sin->sin_addr.s_addr)
|
||||
p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, (const void *)p->name);
|
||||
if (p->expiry && sin->sin_addr.s_addr) {
|
||||
p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
|
||||
if (p->expire == -1)
|
||||
peer_unref(p);
|
||||
}
|
||||
iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
|
||||
iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
|
||||
if (sin->sin_addr.s_addr) {
|
||||
@@ -6760,6 +6806,7 @@ static void __iax2_poke_peer_s(const void *data)
|
||||
{
|
||||
struct iax2_peer *peer = (struct iax2_peer *)data;
|
||||
iax2_poke_peer(peer, 0);
|
||||
peer_unref(peer);
|
||||
}
|
||||
|
||||
static int iax2_poke_peer_s(const void *data)
|
||||
@@ -8301,13 +8348,19 @@ retryowner2:
|
||||
peer->historicms = iaxs[fr->callno]->pingtime;
|
||||
|
||||
/* Remove scheduled iax2_poke_noanswer */
|
||||
if (peer->pokeexpire > -1)
|
||||
ast_sched_del(sched, peer->pokeexpire);
|
||||
if (peer->pokeexpire > -1) {
|
||||
if (!ast_sched_del(sched, peer->pokeexpire)) {
|
||||
peer_unref(peer);
|
||||
peer->pokeexpire = -1;
|
||||
}
|
||||
}
|
||||
/* Schedule the next cycle */
|
||||
if ((peer->lastms < 0) || (peer->historicms > peer->maxms))
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer);
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
|
||||
else
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqok, iax2_poke_peer_s, peer);
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqok, iax2_poke_peer_s, peer_ref(peer));
|
||||
if (peer->pokeexpire == -1)
|
||||
peer_unref(peer);
|
||||
/* and finally send the ack */
|
||||
send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
|
||||
/* And wrap up the qualify call */
|
||||
@@ -9245,7 +9298,9 @@ static void __iax2_poke_noanswer(const void *data)
|
||||
peer->callno = 0;
|
||||
peer->lastms = -1;
|
||||
/* Try again quickly */
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer);
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_peer_s, peer_ref(peer));
|
||||
if (peer->pokeexpire == -1)
|
||||
peer_unref(peer);
|
||||
}
|
||||
|
||||
static int iax2_poke_noanswer(const void *data)
|
||||
@@ -9256,6 +9311,7 @@ static int iax2_poke_noanswer(const void *data)
|
||||
if (schedule_action(__iax2_poke_noanswer, data))
|
||||
#endif
|
||||
__iax2_poke_noanswer(data);
|
||||
peer_unref(peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9298,16 +9354,23 @@ static int iax2_poke_peer(struct iax2_peer *peer, int heldcall)
|
||||
/* Speed up retransmission times for this qualify call */
|
||||
iaxs[peer->callno]->pingtime = peer->maxms / 4 + 1;
|
||||
iaxs[peer->callno]->peerpoke = peer;
|
||||
|
||||
|
||||
if (peer->pokeexpire > -1) {
|
||||
if (!ast_sched_del(sched, peer->pokeexpire)) {
|
||||
peer->pokeexpire = -1;
|
||||
peer_unref(peer);
|
||||
}
|
||||
}
|
||||
|
||||
/* Queue up a new task to handle no reply */
|
||||
/* If the host is already unreachable then use the unreachable interval instead */
|
||||
if (peer->lastms < 0) {
|
||||
peer->pokeexpire = iax2_sched_replace(peer->pokeexpire,
|
||||
sched, peer->pokefreqnotok, iax2_poke_noanswer, peer);
|
||||
} else {
|
||||
peer->pokeexpire = iax2_sched_replace(peer->pokeexpire,
|
||||
sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer);
|
||||
}
|
||||
if (peer->lastms < 0)
|
||||
peer->pokeexpire = iax2_sched_add(sched, peer->pokefreqnotok, iax2_poke_noanswer, peer_ref(peer));
|
||||
else
|
||||
peer->pokeexpire = iax2_sched_add(sched, DEFAULT_MAXMS * 2, iax2_poke_noanswer, peer_ref(peer));
|
||||
|
||||
if (peer->pokeexpire == -1)
|
||||
peer_unref(peer);
|
||||
|
||||
/* And send the poke */
|
||||
send_command(iaxs[peer->callno], AST_FRAME_IAX, IAX_COMMAND_POKE, 0, NULL, 0, -1);
|
||||
@@ -9658,11 +9721,6 @@ static void peer_destructor(void *obj)
|
||||
|
||||
ast_free_ha(peer->ha);
|
||||
|
||||
/* Delete it, it needs to disappear */
|
||||
if (peer->expire > -1)
|
||||
ast_sched_del(sched, peer->expire);
|
||||
if (peer->pokeexpire > -1)
|
||||
ast_sched_del(sched, peer->pokeexpire);
|
||||
if (peer->callno > 0) {
|
||||
ast_mutex_lock(&iaxsl[peer->callno]);
|
||||
iax2_destroy(peer->callno);
|
||||
@@ -10209,7 +10267,7 @@ static void prune_peers(void)
|
||||
i = ao2_iterator_init(peers, 0);
|
||||
while ((peer = ao2_iterator_next(&i))) {
|
||||
if (ast_test_flag(peer, IAX_DELME))
|
||||
ao2_unlink(peers, peer);
|
||||
unlink_peer(peer);
|
||||
peer_unref(peer);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user