chan_iax2 has an extremely large function, socket_process(), to handle incoming
[asterisk/asterisk.git] / channels / chan_iax2.c
index e493a04..efe946d 100644 (file)
@@ -1087,10 +1087,6 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, int lockpeer, cons
        }
                
        tmp->prefs = prefs;
-       tmp->callno = 0;
-       tmp->peercallno = 0;
-       tmp->transfercallno = 0;
-       tmp->bridgecallno = 0;
        tmp->pingid = -1;
        tmp->lagid = -1;
        tmp->autoid = -1;
@@ -6280,36 +6276,156 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        return 1;
 }
 
+static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd,
+       struct iax_frame *fr)
+{
+       unsigned char metatype;
+       struct ast_iax2_meta_trunk_mini *mtm;
+       struct ast_iax2_meta_trunk_hdr *mth;
+       struct ast_iax2_meta_trunk_entry *mte;
+       struct iax2_trunk_peer *tpeer;
+       unsigned int ts;
+       void *ptr;
+       struct timeval rxtrunktime;
+       struct ast_frame f = { 0, };
+
+       if (packet_len < sizeof(*meta)) {
+               ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", 
+                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               return 1;
+       }
+
+       if (meta->metacmd != IAX_META_TRUNK)
+               return 1;
+
+       if (packet_len < (sizeof(*meta) + sizeof(*mth))) {
+               ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %zd min)\n", packet_len,
+                       sizeof(*meta) + sizeof(*mth));
+               return 1;
+       }
+       mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
+       ts = ntohl(mth->ts);
+       metatype = meta->cmddata;
+       packet_len -= (sizeof(*meta) + sizeof(*mth));
+       ptr = mth->data;
+       tpeer = find_tpeer(sin, sockfd);
+       if (!tpeer) {
+               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", 
+                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               return 1;
+       }
+       tpeer->trunkact = ast_tvnow();
+       if (!ts || ast_tvzero(tpeer->rxtrunktime))
+               tpeer->rxtrunktime = tpeer->trunkact;
+       rxtrunktime = tpeer->rxtrunktime;
+       ast_mutex_unlock(&tpeer->lock);
+       while (packet_len >= sizeof(*mte)) {
+               /* Process channels */
+               unsigned short callno, trunked_ts, len;
+
+               if (metatype == IAX_META_TRUNK_MINI) {
+                       mtm = (struct ast_iax2_meta_trunk_mini *) ptr;
+                       ptr += sizeof(*mtm);
+                       packet_len -= sizeof(*mtm);
+                       len = ntohs(mtm->len);
+                       callno = ntohs(mtm->mini.callno);
+                       trunked_ts = ntohs(mtm->mini.ts);
+               } else if (metatype == IAX_META_TRUNK_SUPERMINI) {
+                       mte = (struct ast_iax2_meta_trunk_entry *)ptr;
+                       ptr += sizeof(*mte);
+                       packet_len -= sizeof(*mte);
+                       len = ntohs(mte->len);
+                       callno = ntohs(mte->callno);
+                       trunked_ts = 0;
+               } else {
+                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+                       break;
+               }
+               /* Stop if we don't have enough data */
+               if (len > packet_len)
+                       break;
+               fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, 1, sockfd);
+               if (!fr->callno)
+                       continue;
+
+               ast_mutex_lock(&iaxsl[fr->callno]);
+
+               /* If it's a valid call, deliver the contents.  If not, we
+                  drop it, since we don't have a scallno to use for an INVAL */
+               /* Process as a mini frame */
+               f.frametype = AST_FRAME_VOICE;
+               if (!iaxs[fr->callno]) {
+                       /* drop it */
+               } else if (iaxs[fr->callno]->voiceformat == 0) {
+                       ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n ");
+                       iax2_vnak(fr->callno);
+               } else {
+                       f.subclass = iaxs[fr->callno]->voiceformat;
+                       f.datalen = len;
+                       if (f.datalen >= 0) {
+                               if (f.datalen)
+                                       f.data = ptr;
+                               else
+                                       f.data = NULL;
+                               if (trunked_ts)
+                                       fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
+                               else
+                                       fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
+                               /* Don't pass any packets until we're started */
+                               if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
+                                       struct iax_frame *duped_fr;
+
+                                       /* Common things */
+                                       f.src = "IAX2";
+                                       f.mallocd = 0;
+                                       f.offset = 0;
+                                       if (f.datalen && (f.frametype == AST_FRAME_VOICE)) 
+                                               f.samples = ast_codec_get_samples(&f);
+                                       else
+                                               f.samples = 0;
+                                       fr->outoforder = 0;
+                                       iax_frame_wrap(fr, &f);
+                                       duped_fr = iaxfrdup2(fr);
+                                       if (duped_fr)
+                                               schedule_delivery(duped_fr, 1, 1, &fr->ts);
+                                       if (iaxs[fr->callno]->last < fr->ts)
+                                               iaxs[fr->callno]->last = fr->ts;
+                               }
+                       } else {
+                               ast_log(LOG_WARNING, "Datalen < 0?\n");
+                       }
+               }
+               ast_mutex_unlock(&iaxsl[fr->callno]);
+               ptr += len;
+               packet_len -= len;
+       }
+
+       return 1;
+}
+
 static int socket_process(struct iax2_thread *thread)
 {
        struct sockaddr_in sin;
        int res;
        int updatehistory=1;
        int new = NEW_PREVENT;
-       void *ptr;
        int dcallno = 0;
        struct ast_iax2_full_hdr *fh = (struct ast_iax2_full_hdr *)thread->buf;
        struct ast_iax2_mini_hdr *mh = (struct ast_iax2_mini_hdr *)thread->buf;
        struct ast_iax2_meta_hdr *meta = (struct ast_iax2_meta_hdr *)thread->buf;
        struct ast_iax2_video_hdr *vh = (struct ast_iax2_video_hdr *)thread->buf;
-       struct ast_iax2_meta_trunk_hdr *mth;
-       struct ast_iax2_meta_trunk_entry *mte;
-       struct ast_iax2_meta_trunk_mini *mtm;
        struct iax_frame *fr;
        struct iax_frame *cur;
        struct ast_frame f;
        struct ast_channel *c;
        struct iax2_dpcache *dp;
        struct iax2_peer *peer;
-       struct iax2_trunk_peer *tpeer;
-       struct timeval rxtrunktime;
        struct iax_ies ies;
        struct iax_ie_data ied0, ied1;
        int format;
        int fd;
        int exists;
        int minivid = 0;
-       unsigned int ts;
        char empty[32]="";              /* Safety measure */
        struct iax_frame *duped_fr;
        char host_pref_buf[128];
@@ -6339,123 +6455,8 @@ static int socket_process(struct iax2_thread *thread)
                /* This is a video frame, get call number */
                fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, 1, fd);
                minivid = 1;
-       } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000)) {
-               unsigned char metatype;
-
-               if (res < sizeof(*meta)) {
-                       ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-                       return 1;
-               }
-
-               /* This is a meta header */
-               switch(meta->metacmd) {
-               case IAX_META_TRUNK:
-                       if (res < (sizeof(*meta) + sizeof(*mth))) {
-                               ast_log(LOG_WARNING, "midget meta trunk packet received (%d of %zd min)\n", res,
-                                       sizeof(*meta) + sizeof(*mth));
-                               return 1;
-                       }
-                       mth = (struct ast_iax2_meta_trunk_hdr *)(meta->data);
-                       ts = ntohl(mth->ts);
-                       metatype = meta->cmddata;
-                       res -= (sizeof(*meta) + sizeof(*mth));
-                       ptr = mth->data;
-                       tpeer = find_tpeer(&sin, fd);
-                       if (!tpeer) {
-                               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-                               return 1;
-                       }
-                       tpeer->trunkact = ast_tvnow();
-                       if (!ts || ast_tvzero(tpeer->rxtrunktime))
-                               tpeer->rxtrunktime = tpeer->trunkact;
-                       rxtrunktime = tpeer->rxtrunktime;
-                       ast_mutex_unlock(&tpeer->lock);
-                       while(res >= sizeof(*mte)) {
-                               /* Process channels */
-                               unsigned short callno, trunked_ts, len;
-
-                               if (metatype == IAX_META_TRUNK_MINI) {
-                                       mtm = (struct ast_iax2_meta_trunk_mini *)ptr;
-                                       ptr += sizeof(*mtm);
-                                       res -= sizeof(*mtm);
-                                       len = ntohs(mtm->len);
-                                       callno = ntohs(mtm->mini.callno);
-                                       trunked_ts = ntohs(mtm->mini.ts);
-                               } else if (metatype == IAX_META_TRUNK_SUPERMINI) {
-                                       mte = (struct ast_iax2_meta_trunk_entry *)ptr;
-                                       ptr += sizeof(*mte);
-                                       res -= sizeof(*mte);
-                                       len = ntohs(mte->len);
-                                       callno = ntohs(mte->callno);
-                                       trunked_ts = 0;
-                               } else {
-                                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-                                       break;
-                               }
-                               /* Stop if we don't have enough data */
-                               if (len > res)
-                                       break;
-                               fr->callno = find_callno(callno & ~IAX_FLAG_FULL, 0, &sin, NEW_PREVENT, 1, fd);
-                               if (fr->callno) {
-                                       ast_mutex_lock(&iaxsl[fr->callno]);
-                                       /* If it's a valid call, deliver the contents.  If not, we
-                                          drop it, since we don't have a scallno to use for an INVAL */
-                                       /* Process as a mini frame */
-                                       f.frametype = AST_FRAME_VOICE;
-                                       if (iaxs[fr->callno]) {
-                                               if (iaxs[fr->callno]->voiceformat > 0) {
-                                                       f.subclass = iaxs[fr->callno]->voiceformat;
-                                                       f.datalen = len;
-                                                       if (f.datalen >= 0) {
-                                                               if (f.datalen)
-                                                                       f.data = ptr;
-                                                               else
-                                                                       f.data = NULL;
-                                                               if(trunked_ts) {
-                                                                       fr->ts = (iaxs[fr->callno]->last & 0xFFFF0000L) | (trunked_ts & 0xffff);
-                                                               } else
-                                                                       fr->ts = fix_peerts(&rxtrunktime, fr->callno, ts);
-                                                               /* Don't pass any packets until we're started */
-                                                               if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED)) {
-                                                                       /* Common things */
-                                                                       f.src = "IAX2";
-                                                                       f.mallocd = 0;
-                                                                       f.offset = 0;
-                                                                       if (f.datalen && (f.frametype == AST_FRAME_VOICE)) 
-                                                                               f.samples = ast_codec_get_samples(&f);
-                                                                       else
-                                                                               f.samples = 0;
-                                                                       fr->outoforder = 0;
-                                                                       iax_frame_wrap(fr, &f);
-                                                                       duped_fr = iaxfrdup2(fr);
-                                                                       if (duped_fr) {
-                                                                               schedule_delivery(duped_fr, updatehistory, 1, &fr->ts);
-                                                                       }
-                                                                       if (iaxs[fr->callno]->last < fr->ts) {
-                                                                               iaxs[fr->callno]->last = fr->ts;
-#if 1
-                                                                               if (option_debug && iaxdebug)
-                                                                                       ast_log(LOG_DEBUG, "For call=%d, set last=%d\n", fr->callno, fr->ts);
-#endif
-                                                                       }
-                                                               }
-                                                       } else {
-                                                               ast_log(LOG_WARNING, "Datalen < 0?\n");
-                                                       }
-                                               } else {
-                                                       ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n ");
-                                                       iax2_vnak(fr->callno);
-                                               }
-                                       }
-                                       ast_mutex_unlock(&iaxsl[fr->callno]);
-                               }
-                               ptr += len;
-                               res -= len;
-                       }
-                       
-               }
-               return 1;
-       }
+       } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
+               return socket_process_meta(res, meta, &sin, fd, fr);
 
 #ifdef DEBUG_SUPPORT
        if (iaxdebug && (res >= sizeof(*fh)))