Merged revisions 160003 via svnmerge from
authorRussell Bryant <russell@russellbryant.com>
Mon, 1 Dec 2008 17:34:31 +0000 (17:34 +0000)
committerRussell Bryant <russell@russellbryant.com>
Mon, 1 Dec 2008 17:34:31 +0000 (17:34 +0000)
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

index bbc08d9..1c1888a 100644 (file)
@@ -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) {