diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 11d55d3647..d6deac7797 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -820,6 +820,15 @@ struct chan_iax2_pvt { int frames_received; /*! num bytes used for calltoken ie, even an empty ie should contain 2 */ unsigned char calltoken_ie_len; + /*! hold all signaling frames from the pbx thread until we have a destination callno */ + char hold_signaling; + /*! frame queue for signaling frames from pbx thread waiting for destination callno */ + AST_LIST_HEAD_NOLOCK(signaling_queue, signaling_queue_entry) signaling_queue; +}; + +struct signaling_queue_entry { + struct ast_frame f; + AST_LIST_ENTRY(signaling_queue_entry) next; }; /*! table of available call numbers */ @@ -1703,10 +1712,56 @@ static int scheduled_destroy(const void *vid) return 0; } +static void free_signaling_queue_entry(struct signaling_queue_entry *s) +{ + ast_free(s->f.data.ptr); + ast_free(s); +} + +/*! \brief This function must be called once we are sure the other side has + * given us a call number. All signaling is held here until that point. */ +static void send_signaling(struct chan_iax2_pvt *pvt) +{ + struct signaling_queue_entry *s = NULL; + + while ((s = AST_LIST_REMOVE_HEAD(&pvt->signaling_queue, next))) { + iax2_send(pvt, &s->f, 0, -1, 0, 0, 0); + free_signaling_queue_entry(s); + } + pvt->hold_signaling = 0; +} + +/*! \brief All frames other than that of type AST_FRAME_IAX must be held until + * we have received a destination call number. */ +static int queue_signalling(struct chan_iax2_pvt *pvt, struct ast_frame *f) +{ + struct signaling_queue_entry *new; + + if (f->frametype == AST_FRAME_IAX || !pvt->hold_signaling) { + return 1; /* do not queue this frame */ + } else if (!(new = ast_calloc(1, sizeof(struct signaling_queue_entry)))) { + return -1; /* out of memory */ + } + + memcpy(&new->f, f, sizeof(new->f)); /* copy ast_frame into our queue entry */ + + if (new->f.datalen) { /* if there is data in this frame copy it over as well */ + if (!(new->f.data.ptr = ast_calloc(1, new->f.datalen))) { + free_signaling_queue_entry(new); + return -1; + } + memcpy(new->f.data.ptr, f->data.ptr, sizeof(*new->f.data.ptr)); + } + AST_LIST_INSERT_TAIL(&pvt->signaling_queue, new, next); + + return 0; +} + static void pvt_destructor(void *obj) { struct chan_iax2_pvt *pvt = obj; struct iax_frame *cur = NULL; + struct signaling_queue_entry *s = NULL; ast_mutex_lock(&iaxsl[pvt->callno]); @@ -1725,6 +1780,10 @@ static void pvt_destructor(void *obj) ast_mutex_unlock(&iaxsl[pvt->callno]); + while ((s = AST_LIST_REMOVE_HEAD(&pvt->signaling_queue, next))) { + free_signaling_queue_entry(s); + } + if (pvt->reg) { pvt->reg->callno = 0; } @@ -1781,6 +1840,9 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host) AST_LIST_HEAD_INIT_NOLOCK(&tmp->dpentries); + tmp->hold_signaling = 1; + AST_LIST_HEAD_INIT_NOLOCK(&tmp->signaling_queue); + return tmp; } @@ -7148,6 +7210,7 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig int now, int transfer, int final) { struct ast_frame f = { 0, }; + int res = 0; f.frametype = type; f.subclass = command; @@ -7155,6 +7218,10 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig f.src = __FUNCTION__; f.data.ptr = (void *) data; + if ((res = queue_signalling(i, &f)) <= 0) { + return res; + } + return iax2_send(i, &f, ts, seqno, now, transfer, final); } @@ -9634,19 +9701,15 @@ static int socket_process(struct iax2_thread *thread) int check_dcallno = 0; /* - * We enforce accurate destination call numbers for all full frames except - * LAGRQ and PING commands. This is because older versions of Asterisk - * schedule these commands to get sent very quickly, and they will sometimes - * be sent before they receive the first frame from the other side. When - * that happens, it doesn't contain the destination call number. However, - * not checking it for these frames is safe. - * + * We enforce accurate destination call numbers for ACKs. This forces the other + * end to know the destination call number before call setup can complete. + * * Discussed in the following thread: * http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html */ - if (ntohs(mh->callno) & IAX_FLAG_FULL) { - check_dcallno = f.frametype == AST_FRAME_IAX ? (f.subclass != IAX_COMMAND_PING && f.subclass != IAX_COMMAND_LAGRQ) : 1; + if ((ntohs(mh->callno) & IAX_FLAG_FULL) && ((f.frametype == AST_FRAME_IAX) && (f.subclass == IAX_COMMAND_ACK))) { + check_dcallno = 1; } if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno))) { @@ -9922,6 +9985,12 @@ static int socket_process(struct iax2_thread *thread) } } + /* once we receive our first IAX Full Frame that is not CallToken related, send all + * queued signaling frames that were being held. */ + if ((f.frametype == AST_FRAME_IAX) && (f.subclass != IAX_COMMAND_CALLTOKEN) && iaxs[fr->callno]->hold_signaling) { + send_signaling(iaxs[fr->callno]); + } + if (f.frametype == AST_FRAME_VOICE) { if (f.subclass != iaxs[fr->callno]->voiceformat) { iaxs[fr->callno]->voiceformat = f.subclass;