From 15431e294852bba458917b6bf11f1e7bf13e80fb Mon Sep 17 00:00:00 2001 From: Russell Bryant Date: Mon, 1 Dec 2008 17:34:31 +0000 Subject: Merged revisions 160003 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r160003 | russell | 2008-12-01 11:27:30 -0600 (Mon, 01 Dec 2008) | 6 lines Apply some logic used in iax2_indicate() to iax2_setoption(), as well, since they both have the potential to send control frames in the middle of call setup. We have to wait until we have received a message back from the remote end before we try to send any more frames. Otherwise, the remote end will consider it invalid, and we'll get stuck in an INVAL/VNAK storm. ........ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@160004 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channels/chan_iax2.c | 54 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index bbc08d9e1..1c1888a1e 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -3939,6 +3939,28 @@ static int iax2_hangup(struct ast_channel *c) return 0; } +/*! + * \note expects the pvt to be locked + */ +static int wait_for_peercallno(struct chan_iax2_pvt *pvt) +{ + unsigned short callno = pvt->callno; + + if (!pvt->peercallno) { + /* We don't know the remote side's call number, yet. :( */ + int count = 10; + while (count-- && pvt && !pvt->peercallno) { + DEADLOCK_AVOIDANCE(&iaxsl[callno]); + pvt = iaxs[callno]; + } + if (!pvt->peercallno) { + return -1; + } + } + + return 0; +} + static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen) { struct ast_option_header *h; @@ -3954,8 +3976,23 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat errno = EINVAL; return -1; default: - if (!(h = ast_malloc(datalen + sizeof(*h)))) + { + unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); + struct chan_iax2_pvt *pvt; + + ast_mutex_lock(&iaxsl[callno]); + pvt = iaxs[callno]; + + if (wait_for_peercallno(pvt)) { + ast_mutex_unlock(&iaxsl[callno]); + return -1; + } + + ast_mutex_unlock(&iaxsl[callno]); + + if (!(h = ast_malloc(datalen + sizeof(*h)))) { return -1; + } h->flag = AST_OPTION_FLAG_REQUEST; h->option = htons(option); @@ -3966,6 +4003,7 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat ast_free(h); return res; } + } } static struct ast_frame *iax2_read(struct ast_channel *c) @@ -4252,17 +4290,9 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data, ast_mutex_lock(&iaxsl[callno]); pvt = iaxs[callno]; - if (!pvt->peercallno) { - /* We don't know the remote side's call number, yet. :( */ - int count = 10; - while (count-- && pvt && !pvt->peercallno) { - DEADLOCK_AVOIDANCE(&iaxsl[callno]); - pvt = iaxs[callno]; - } - if (!pvt->peercallno) { - res = -1; - goto done; - } + if (wait_for_peercallno(pvt)) { + res = -1; + goto done; } switch (condition) { -- cgit v1.2.3