From 8ac7c1c09c647adf2e81d86e2215fbcf76045583 Mon Sep 17 00:00:00 2001 From: russell Date: Mon, 1 Dec 2008 17:39:33 +0000 Subject: Merged revisions 160004 via svnmerge from https://origsvn.digium.com/svn/asterisk/trunk ................ r160004 | russell | 2008-12-01 11:34:31 -0600 (Mon, 01 Dec 2008) | 14 lines 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: http://svn.digium.com/svn/asterisk/branches/1.6.0@160005 f38db490-d61c-443f-a65b-d21fe96a405b --- channels/chan_iax2.c | 54 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) (limited to 'channels') diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 36d8aae43..2c2e11c52 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -3769,6 +3769,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; @@ -3781,8 +3803,23 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat errno = ENOSYS; 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); @@ -3793,6 +3830,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) @@ -4019,17 +4057,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