diff options
author | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-12-01 17:27:30 +0000 |
---|---|---|
committer | russell <russell@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-12-01 17:27:30 +0000 |
commit | 0b308eadda9bab5ec24952f15405cd60b3b9b62b (patch) | |
tree | cb1f028f59a754e8eacc5530b9fc30db3de0d0e5 | |
parent | 94dea32406fd4eb54dfff80a043ed5022e63a977 (diff) |
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.4@160003 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | channels/chan_iax2.c | 54 |
1 files changed, 42 insertions, 12 deletions
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index f0c6cfe23..820a127f9 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -3481,6 +3481,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; @@ -3493,8 +3515,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); @@ -3505,6 +3542,7 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat free(h); return res; } + } } static struct ast_frame *iax2_read(struct ast_channel *c) @@ -3724,17 +3762,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) { |