Tue Mar 18 07:00:01 CET 2003
authorMatteo Brancaleoni <mbrancaleoni@espia.it>
Tue, 18 Mar 2003 06:00:18 +0000 (06:00 +0000)
committerMatteo Brancaleoni <mbrancaleoni@espia.it>
Tue, 18 Mar 2003 06:00:18 +0000 (06:00 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@652 65c4cc65-6c06-0410-ace0-fbb531ad65f3

17 files changed:
Makefile
apps/app_substring.c
channel.c
channels/chan_iax.c
channels/chan_iax2.c
channels/chan_sip.c
channels/chan_zap.c
channels/iax2-parser.c
channels/iax2-parser.h
channels/iax2.h
codecs/gsm/Makefile
codecs/lpc10/Makefile
configs/extensions.conf.sample
frame.c
pbx.c
pbx/pbx_config.c
res/res_musiconhold.c

index cd2a4a1..9edd35c 100755 (executable)
--- a/Makefile
+++ b/Makefile
 
 .EXPORT_ALL_VARIABLES:
 
+# Pentium Pro Optimize
+#PROC=i686
+# Pentium Optimize
+#PROC=i586
+#PROC=k6
+#PROC=ppc
+PROC=$(shell uname -m)
+
+######### More GSM codec optimization
+######### Uncomment to enable MMXTM optimizations for x86 architecture CPU's
+######### which support MMX instructions.  This should be newer pentiums,
+######### ppro's, etc, as well as the AMD K6 and K7.  
+K6OPT  = #-DK6OPT
+
+#Tell gcc to optimize the asterisk's code
+OPTIMIZE=-O6
+
+#Include debug symbols in the executables (-g) and profiling info (-pg)
+DEBUG=-g #-pg
+
+# Optional debugging parameters
+DEBUG_THREADS = #-DDO_CRASH -DDEBUG_THREADS
+
+# Uncomment next one to enable ast_frame tracing (for debugging)
+TRACE_FRAMES = #-DTRACE_FRAMES
+
+# Where to install asterisk after compiling
+# Default -> leave empty
 INSTALL_PREFIX=
 
 ASTLIBDIR=$(INSTALL_PREFIX)/usr/lib/asterisk
@@ -30,18 +58,9 @@ ASTVARRUNDIR=$(INSTALL_PREFIX)/var/run
 MODULES_DIR=$(ASTLIBDIR)/modules
 AGI_DIR=$(ASTVARLIBDIR)/agi-bin
 
-# Pentium Pro Optimize
-#PROC=i686
-# Pentium Optimize
-#PROC=i586
-#PROC=k6
-#PROC=ppc
-PROC=$(shell uname -m)
-
-DEBUG=-g #-pg
 INCLUDE=-Iinclude -I../include
 CFLAGS=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
-#CFLAGS+=-O6
+CFLAGS+=$(OPTIMIZE)
 CFLAGS+=$(shell if $(CC) -march=$(PROC) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=$(PROC)"; fi)
 CFLAGS+=$(shell if uname -m | grep -q ppc; then echo "-fsigned-char"; fi)
 
@@ -62,10 +81,8 @@ CFLAGS+=-DASTCONFPATH=\"$(ASTCONFPATH)\"
 CFLAGS+=-DASTMODDIR=\"$(MODULES_DIR)\"
 CFLAGS+=-DASTAGIDIR=\"$(AGI_DIR)\"
 
-# Optional debugging parameters
-CFLAGS+= -DDO_CRASH -DDEBUG_THREADS
-# Uncomment next one to enable ast_frame tracing (for debugging)
-#CFLAGS+= -DTRACE_FRAMES
+CFLAGS+= $(DEBUG_THREADS)
+CFLAGS+= $(TRACE_FRAMES)
 CFLAGS+=# -fomit-frame-pointer 
 SUBDIRS=res channels pbx apps codecs formats agi cdr astman
 LIBS=-ldl -lpthread -lncurses -lm  #-lnjamd
@@ -311,3 +328,7 @@ config:
        fi 
 
        
+dont-optimize:
+       make OPTIMIZE= K6OPT= install
+
+valgrind: dont-optimize
index 97f0fea..4d3ccce 100755 (executable)
@@ -56,6 +56,7 @@ static int substring_exec(struct ast_channel *chan, void *data)
   char *count1, *count2;
   char *first, *second, *stringp;
   stringp=alloca(strlen(data)+1);
+  ast_log(LOG_WARNING, "The use of Substring application is deprecated. Please use ${variable:a:b} instead\n");
   strncpy(stringp,data,strlen(data)+1);
   if (strchr(stringp,'|')&&strchr(stringp,'=')) {
     int icount1,icount2;
index 0a7eed3..684adac 100755 (executable)
--- a/channel.c
+++ b/channel.c
@@ -347,7 +347,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
                cur = cur->next;
                qlen++;
        }
-       if (qlen  > 128) {
+       /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
+       if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen  > 128)) {
                if (fin->frametype != AST_FRAME_VOICE) {
                        ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
                        CRASH;
index 3cf6813..894aa67 100755 (executable)
@@ -3409,7 +3409,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        char rel0[256];
        char rel1[255];
        char empty[32]="";              /* Safety measure */
-       fr.ts=0;        /* make Valgrind happy */
        res = recvfrom(netsocket, buf, sizeof(buf), 0,(struct sockaddr *) &sin, &len);
        if (res < 0) {
                if (errno != ECONNREFUSED)
@@ -3473,6 +3472,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", ntohs(fh->seqno), f.frametype, f.subclass);
                /* Check if it's out of order (and not an ACK or INVAL) */
                fr.seqno = ntohs(fh->seqno);
+               fr.ts = ntohl(fh->ts);
                if ((iaxs[fr.callno]->iseqno != fr.seqno) &&
                        (iaxs[fr.callno]->iseqno ||
                                ((f.subclass != AST_IAX_COMMAND_TXCNT) &&
@@ -3525,7 +3525,6 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        f.data = buf + sizeof(struct ast_iax_full_hdr);
                else
                        f.data = empty;
-               fr.ts = ntohl(fh->ts);
                /* Unless this is an ACK or INVAL frame, ack it */
                if ((f.frametype != AST_FRAME_IAX) || 
                         ((f.subclass != AST_IAX_COMMAND_ACK) && 
index c58e24e..b1d2402 100755 (executable)
@@ -1786,6 +1786,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
        struct ast_frame *f;
        struct chan_iax2_pvt *p0 = c0->pvt->pvt;
        struct chan_iax2_pvt *p1 = c1->pvt->pvt;
+       struct timeval waittimer = {0, 0}, tv;
 
        /* Put them in native bridge mode */
        p0->bridgecallno = p1->callno;
@@ -1814,13 +1815,18 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                
                if ((p0->transferring == TRANSFER_RELEASED) && (p1->transferring == TRANSFER_RELEASED)) {
                        /* Call has been transferred.  We're no longer involved */
-                       sleep(1);
-                       c0->_softhangup |= AST_SOFTHANGUP_DEV;
-                       c1->_softhangup |= AST_SOFTHANGUP_DEV;
-                       *fo = NULL;
-                       *rc = c0;
-                       res = 0;
-                       break;
+                       gettimeofday(&tv, NULL);
+                       if (!waittimer.tv_sec && !waittimer.tv_usec) {
+                               waittimer.tv_sec = tv.tv_sec;
+                               waittimer.tv_usec = tv.tv_usec;
+                       } else if (tv.tv_sec - waittimer.tv_sec > IAX_LINGER_TIMEOUT) {
+                               c0->_softhangup |= AST_SOFTHANGUP_DEV;
+                               c1->_softhangup |= AST_SOFTHANGUP_DEV;
+                               *fo = NULL;
+                               *rc = c0;
+                               res = 0;
+                               break;
+                       }
                }
                to = 1000;
                who = ast_waitfor_n(cs, 2, &to);
@@ -2164,7 +2170,10 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                fh->scallno = htons(fr->callno | IAX_FLAG_FULL);
                fh->ts = htonl(fr->ts);
                fh->oseqno = fr->oseqno;
-               fh->iseqno = fr->iseqno;
+               if (transfer) {
+                       fh->iseqno = 0;
+               } else
+                       fh->iseqno = fr->iseqno;
                /* Keep track of the last thing we've acknowledged */
                pvt->aseqno = fr->iseqno;
                fh->type = fr->af.frametype & 0xFF;
@@ -2206,6 +2215,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                                        ast_log(LOG_WARNING, "Out of trunk data space on call number %d, dropping\n", pvt->callno);
                                pvt->trunkerror = 1;
                        }
+                       res = 0;
                } else {
                        /* Mini-frames have no sequence number */
                        fr->oseqno = -1;
@@ -3355,146 +3365,6 @@ static int iax2_poke_peer_s(void *data)
        return 0;
 }
 
-static int parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
-{
-       /* Parse data into information elements */
-       int len;
-       int ie;
-       memset(ies, 0, sizeof(struct iax_ies));
-       ies->msgcount = -1;
-       while(datalen >= 2) {
-               ie = data[0];
-               len = data[1];
-               if (len > datalen - 2) {
-                       ast_log(LOG_WARNING, "Information element length exceeds message size\n");
-                       return -1;
-               }
-               switch(ie) {
-               case IAX_IE_CALLED_NUMBER:
-                       ies->called_number = data + 2;
-                       break;
-               case IAX_IE_CALLING_NUMBER:
-                       ies->calling_number = data + 2;
-                       break;
-               case IAX_IE_CALLING_ANI:
-                       ies->calling_ani = data + 2;
-                       break;
-               case IAX_IE_CALLING_NAME:
-                       ies->calling_name = data + 2;
-                       break;
-               case IAX_IE_CALLED_CONTEXT:
-                       ies->called_context = data + 2;
-                       break;
-               case IAX_IE_USERNAME:
-                       ies->username = data + 2;
-                       break;
-               case IAX_IE_PASSWORD:
-                       ies->password = data + 2;
-                       break;
-               case IAX_IE_CAPABILITY:
-                       if (len != sizeof(unsigned int)) 
-                               ast_log(LOG_WARNING, "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
-                       else
-                               ies->capability = ntohl(*((unsigned int *)(data + 2)));
-                       break;
-               case IAX_IE_FORMAT:
-                       if (len != sizeof(unsigned int)) 
-                               ast_log(LOG_WARNING, "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
-                       else
-                               ies->format = ntohl(*((unsigned int *)(data + 2)));
-                       break;
-               case IAX_IE_LANGUAGE:
-                       ies->language = data + 2;
-                       break;
-               case IAX_IE_VERSION:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->version = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_ADSICPE:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_DNID:
-                       ies->dnid = data + 2;
-                       break;
-               case IAX_IE_AUTHMETHODS:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_CHALLENGE:
-                       ies->challenge = data + 2;
-                       break;
-               case IAX_IE_MD5_RESULT:
-                       ies->md5_result = data + 2;
-                       break;
-               case IAX_IE_RSA_RESULT:
-                       ies->rsa_result = data + 2;
-                       break;
-               case IAX_IE_APPARENT_ADDR:
-                       ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
-                       break;
-               case IAX_IE_REFRESH:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->refresh = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_DPSTATUS:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_CALLNO:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->callno = ntohs(*((unsigned short *)(data + 2)));
-                       break;
-               case IAX_IE_CAUSE:
-                       ies->cause = data + 2;
-                       break;
-               case IAX_IE_IAX_UNKNOWN:
-                       if (len == 1)
-                               ies->iax_unknown = data[2];
-                       else
-                               ast_log(LOG_WARNING, "Expected single byte Unknown command, but was %d long\n", len);
-                       break;
-               case IAX_IE_MSGCOUNT:
-                       if (len != sizeof(unsigned short)) 
-                               ast_log(LOG_WARNING, "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
-                       else
-                               ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
-                       break;
-               case IAX_IE_AUTOANSWER:
-                       ies->autoanswer = 1;
-                       break;
-               case IAX_IE_MUSICONHOLD:
-                       ies->musiconhold = 1;
-                       break;
-               default:
-                       ast_log(LOG_NOTICE, "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
-               }
-               /* Overwrite information element with 0, to null terminate previous portion */
-               data[0] = 0;
-               datalen -= (len + 2);
-               data += (len + 2);
-       }
-       /* Null-terminate last field */
-       *data = '\0';
-       if (datalen) {
-               ast_log(LOG_WARNING, "Invalid information element contents, strange boundary\n");
-               return -1;
-       }
-       return 0;
-}
-
 static int send_trunk(struct iax2_peer *peer)
 {
        int x;
@@ -3777,9 +3647,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
                return 1;
        }
-       if (((f.subclass != IAX_COMMAND_TXCNT) &&
-            (f.subclass != IAX_COMMAND_TXACC)) || (f.frametype != AST_FRAME_IAX))
-               iaxs[fr.callno]->peercallno = (short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
+       if (!memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)))
+               iaxs[fr.callno]->peercallno = (unsigned short)(ntohs(mh->callno) & ~IAX_FLAG_FULL);
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
                if (option_debug)
                        ast_log(LOG_DEBUG, "Received packet %d, (%d, %d)\n", fh->oseqno, f.frametype, f.subclass);
@@ -3840,9 +3709,11 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                }
                f.datalen = res - sizeof(struct ast_iax2_full_hdr);
 
-               /* Handle implicit ACKing unless this is an INVAL */
-               if (((f.subclass != IAX_COMMAND_INVAL)) ||
-                       (f.frametype != AST_FRAME_IAX)) {
+               /* Handle implicit ACKing unless this is an INVAL, and only if this is 
+                  from the real peer, not the transfer peer */
+               if (!memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)) && 
+                       (((f.subclass != IAX_COMMAND_INVAL)) ||
+                       (f.frametype != AST_FRAME_IAX))) {
                        unsigned char x;
                        /* XXX This code is not very efficient.  Surely there is a better way which still
                               properly handles boundary conditions? XXX */
@@ -3883,10 +3754,18 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        } else
                                ast_log(LOG_DEBUG, "Received iseqno %d not within window %d->%d\n", fr.iseqno, iaxs[fr.callno]->rseqno, iaxs[fr.callno]->oseqno);
                }
+               if (memcmp(&sin, &iaxs[fr.callno]->addr, sizeof(sin)) && 
+                       ((f.frametype != AST_FRAME_IAX) || 
+                        ((f.subclass != IAX_COMMAND_TXACC) &&
+                         (f.subclass != IAX_COMMAND_TXCNT)))) {
+                       /* Only messages we accept from a transfer host are TXACC and TXCNT */
+                       ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
+                       return 1;
+               }
 
                if (f.datalen) {
                        if (f.frametype == AST_FRAME_IAX) {
-                               if (parse_ies(&ies, buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
+                               if (iax_parse_ies(&ies, buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
                                        ast_log(LOG_WARNING, "undecodable frame received\n");
                                        ast_pthread_mutex_unlock(&iaxsl[fr.callno]);
                                        return 1;
@@ -4385,6 +4264,8 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                        send_command_transfer(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_TXACC, 0, NULL, 0);
                                break;
                        case IAX_COMMAND_TXREL:
+                               /* Send ack immediately, rather than waiting until we've changed addresses */
+                               send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.iseqno);
                                complete_transfer(fr.callno, &ies);
                                break;  
                        case IAX_COMMAND_DPREP:
index ff47ba8..cb9bb6f 100755 (executable)
@@ -473,7 +473,7 @@ static void sip_prefs_free(void)
 
 static void sip_pref_remove(int format)
 {
-       struct sip_codec_pref *cur, *prev;
+       struct sip_codec_pref *cur, *prev=NULL;
        cur = prefs;
        while(cur) {
                if (cur->codec == format) {
@@ -744,10 +744,9 @@ static int sip_hangup(struct ast_channel *ast)
 
 static int sip_answer(struct ast_channel *ast)
 {
-       int res = 0,fmt,capability;
+       int res = 0,fmt;
        char *codec;
        struct sip_pvt *p = ast->pvt->pvt;
-       struct sip_codec_pref *oldpref=NULL;
 
        
        if (ast->_state != AST_STATE_UP) {
@@ -759,10 +758,6 @@ static int sip_answer(struct ast_channel *ast)
                        ast_log(LOG_NOTICE, "Changing codec to '%s' for this call because of ${SIP_CODEC) variable\n",codec);
                        fmt=ast_getformatbyname(codec);
                        if (fmt) {
-                               oldpref=prefs;
-                               prefs=NULL;
-                               sip_pref_append(fmt);
-                               capability=p->capability;
                                p->capability=fmt;
                        } else ast_log(LOG_NOTICE, "Ignoring ${SIP_CODEC} variable because of unrecognized codec: %s\n",codec);
                }
@@ -771,11 +766,6 @@ static int sip_answer(struct ast_channel *ast)
                if (option_debug)
                        ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name);
                res = transmit_response_with_sdp(p, "200 OK", &p->initreq);
-               sip_prefs_free();
-               if (oldpref) {
-                       prefs=oldpref;
-                       p->capability=capability;
-               }
        }
        return res;
 }
index 4d8e460..ac51aad 100755 (executable)
@@ -2732,6 +2732,7 @@ static struct ast_frame *zt_handle_event(struct ast_channel *ast)
                                                                p->owner = p->subs[SUB_REAL].owner;
                                                                if (p->subs[SUB_REAL].owner && p->subs[SUB_REAL].owner->bridge)
                                                                        ast_moh_stop(p->subs[SUB_REAL].owner->bridge);
+                                                               zt_enable_ec(p);
                                                        }
                                                        
                                                }
index 6e27d6f..f702056 100755 (executable)
@@ -342,3 +342,157 @@ void iax_set_error(void (*func)(const char *))
 {
        errorf = func;
 }
+
+int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
+{
+       /* Parse data into information elements */
+       int len;
+       int ie;
+       char tmp[256];
+       memset(ies, 0, sizeof(struct iax_ies));
+       ies->msgcount = -1;
+       while(datalen >= 2) {
+               ie = data[0];
+               len = data[1];
+               if (len > datalen - 2) {
+                       errorf("Information element length exceeds message size\n");
+                       return -1;
+               }
+               switch(ie) {
+               case IAX_IE_CALLED_NUMBER:
+                       ies->called_number = data + 2;
+                       break;
+               case IAX_IE_CALLING_NUMBER:
+                       ies->calling_number = data + 2;
+                       break;
+               case IAX_IE_CALLING_ANI:
+                       ies->calling_ani = data + 2;
+                       break;
+               case IAX_IE_CALLING_NAME:
+                       ies->calling_name = data + 2;
+                       break;
+               case IAX_IE_CALLED_CONTEXT:
+                       ies->called_context = data + 2;
+                       break;
+               case IAX_IE_USERNAME:
+                       ies->username = data + 2;
+                       break;
+               case IAX_IE_PASSWORD:
+                       ies->password = data + 2;
+                       break;
+               case IAX_IE_CAPABILITY:
+                       if (len != sizeof(unsigned int)) {
+                               snprintf(tmp, sizeof(tmp), "Expecting capability to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else
+                               ies->capability = ntohl(*((unsigned int *)(data + 2)));
+                       break;
+               case IAX_IE_FORMAT:
+                       if (len != sizeof(unsigned int)) {
+                               snprintf(tmp, sizeof(tmp), "Expecting format to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else
+                               ies->format = ntohl(*((unsigned int *)(data + 2)));
+                       break;
+               case IAX_IE_LANGUAGE:
+                       ies->language = data + 2;
+                       break;
+               case IAX_IE_VERSION:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp),  "Expecting version to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->version = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_ADSICPE:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp), "Expecting adsicpe to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->adsicpe = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_DNID:
+                       ies->dnid = data + 2;
+                       break;
+               case IAX_IE_AUTHMETHODS:
+                       if (len != sizeof(unsigned short))  {
+                               snprintf(tmp, sizeof(tmp), "Expecting authmethods to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->authmethods = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_CHALLENGE:
+                       ies->challenge = data + 2;
+                       break;
+               case IAX_IE_MD5_RESULT:
+                       ies->md5_result = data + 2;
+                       break;
+               case IAX_IE_RSA_RESULT:
+                       ies->rsa_result = data + 2;
+                       break;
+               case IAX_IE_APPARENT_ADDR:
+                       ies->apparent_addr = ((struct sockaddr_in *)(data + 2));
+                       break;
+               case IAX_IE_REFRESH:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp),  "Expecting refresh to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->refresh = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_DPSTATUS:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp),  "Expecting dpstatus to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->dpstatus = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_CALLNO:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp),  "Expecting callno to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->callno = ntohs(*((unsigned short *)(data + 2)));
+                       break;
+               case IAX_IE_CAUSE:
+                       ies->cause = data + 2;
+                       break;
+               case IAX_IE_IAX_UNKNOWN:
+                       if (len == 1)
+                               ies->iax_unknown = data[2];
+                       else {
+                               snprintf(tmp, sizeof(tmp), "Expected single byte Unknown command, but was %d long\n", len);
+                               errorf(tmp);
+                       }
+                       break;
+               case IAX_IE_MSGCOUNT:
+                       if (len != sizeof(unsigned short)) {
+                               snprintf(tmp, sizeof(tmp), "Expecting msgcount to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+                               errorf(tmp);
+                       } else
+                               ies->msgcount = ntohs(*((unsigned short *)(data + 2))); 
+                       break;
+               case IAX_IE_AUTOANSWER:
+                       ies->autoanswer = 1;
+                       break;
+               case IAX_IE_MUSICONHOLD:
+                       ies->musiconhold = 1;
+                       break;
+               default:
+                       snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
+                       errorf(tmp);
+               }
+               /* Overwrite information element with 0, to null terminate previous portion */
+               data[0] = 0;
+               datalen -= (len + 2);
+               data += (len + 2);
+       }
+       /* Null-terminate last field */
+       *data = '\0';
+       if (datalen) {
+               errorf("Invalid information element contents, strange boundary\n");
+               return -1;
+       }
+       return 0;
+}
+
index 903a443..e34ca1c 100755 (executable)
@@ -106,5 +106,6 @@ extern int iax_ie_append_short(struct iax_ie_data *ied, unsigned char ie, unsign
 extern int iax_ie_append_str(struct iax_ie_data *ied, unsigned char ie, unsigned char *str);
 extern int iax_ie_append_byte(struct iax_ie_data *ied, unsigned char ie, unsigned char dat);
 extern int iax_ie_append(struct iax_ie_data *ied, unsigned char ie);
+extern int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen);
 
 #endif
index e42591c..88ffe0c 100755 (executable)
@@ -66,6 +66,8 @@
 
 #define IAX_DEFAULT_REG_EXPIRE  60     /* By default require re-registration once per minute */
 
+#define IAX_LINGER_TIMEOUT             10 /* How long to wait before closing bridged call */
+
 #define IAX_DEFAULT_PORTNO             4569
 
 /* IAX Information elements */
index 9e211f5..721879d 100755 (executable)
@@ -31,7 +31,7 @@ WAV49 = -DWAV49
 ######### manual page on gsm_option(3).
 
 #K6OPT = -DK6OPT
-K6OPT  =
+#K6OPT =
 ######### Define to enable MMXTM optimizations for x86 architecture CPU's
 ######### which support MMX instructions.  This should be newer pentiums,
 ######### ppro's, etc, as well as the AMD K6 and K7.  The compile will
@@ -54,7 +54,7 @@ PG =
 # CC           = /usr/lang/acc
 # CCFLAGS      = -c -O
 
-CC             = gcc -ansi -pedantic -O6 -mpentium -fschedule-insns2  -fomit-frame-pointer 
+CC             = gcc -ansi -pedantic $(OPTIMIZE) -march=$(PROC) -fschedule-insns2  -fomit-frame-pointer 
 CCFLAGS        += -c -DNeedFunctionPrototypes=1 -finline-functions -funroll-loops
 
 LD             = $(CC)
index af5131d..61d8774 100755 (executable)
@@ -22,8 +22,9 @@ LIB_TARGET_DIR = .
 # 
 
 WARNINGS = -Wall -Wno-comment -Wno-error
-CFLAGS = -O6 -I$(LIB_TARGET_DIR) $(WARNINGS)
-CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi)
+CFLAGS = $(OPTIMIZE) -I$(LIB_TARGET_DIR) $(WARNINGS)
+#CFLAGS+= $(shell if uname -m | grep -q 86; then echo "-mpentium" ; fi)
+CFLAGS+= -march=$(PROC)
 
 LIB = $(LIB_TARGET_DIR)/liblpc10.a
 
index 0499a33..f7135ec 100755 (executable)
@@ -31,7 +31,7 @@ CONSOLE=Console/dsp                           ; Console interface for demo
 IAXINFO=guest                                  ; IAXtel username/password
 ;IAXINFO=myuser:mypass
 TRUNK=Zap/g2                                   ; Trunk interface
-;TRUNK=IAX/user:pass@provider
+;TRUNK=IAX2/user:pass@provider
 
 ;
 ; Any category other than "General" and "Globals" represent 
@@ -84,10 +84,10 @@ TRUNK=Zap/g2                                        ; Trunk interface
 ; up, please go to www.gnophone.com or www.iaxtel.com
 ;
 [iaxtel700]
-exten => _91700NXXXXXX,1,Dial(IAX/${IAXINFO}@iaxtel.com/${EXTEN:1}@iaxtel)
+exten => _91700NXXXXXX,1,Dial(IAX2/${IAXINFO}@iaxtel.com/${EXTEN:1}@iaxtel)
 
 [iaxprovider]
-;switch => IAX/user:[key]@myserver/mycontext
+;switch => IAX2/user:[key]@myserver/mycontext
 
 [trunkint]
 ;
@@ -155,7 +155,7 @@ include => provider
 ; extensions that are not known here, for example with remote 
 ; IAX switching you transparently get access to the remote
 ; 
-; switch => IAX/user:password@bigserver/local
+; switch => IAX2/user:password@bigserver/local
 
 [macro-stdexten];
 ;
@@ -218,7 +218,7 @@ exten => i,1,Playback(invalid)              ; "That's not valid, try again"
 ; Asterisk demo.
 ;
 exten => 500,1,Playback(demo-abouttotry); Let them know what's going on
-exten => 500,2,Dial(IAX/guest@misery.digium.com/s@default)     ; Call the Asterisk demo
+exten => 500,2,Dial(IAX2/guest@misery.digium.com/s@default)    ; Call the Asterisk demo
 exten => 500,3,Playback(demo-nogo)     ; Couldn't connect to the demo site
 exten => 500,4,Goto(s,6)               ; Return to the start over message.
 
diff --git a/frame.c b/frame.c
index 34ec995..695c557 100755 (executable)
--- a/frame.c
+++ b/frame.c
@@ -238,15 +238,37 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
 
 struct ast_frame *ast_frdup(struct ast_frame *f)
 {
-       struct ast_frame *ret;
-       int p;
-       p = f->mallocd;
-       f->mallocd = 0;
-       /* Make frisolate think this is a 100% static frame, and make a duplicate */
-       ret = ast_frisolate(f);
-       /* Restore its true malloc status */
-       f->mallocd = p;
-       return ret;
+       struct ast_frame *out;
+       int len;
+       void *buf;
+       /* Start with standard stuff */
+       len = sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET + f->datalen;
+       /* If we have a source, add space for it */
+       if (f->src && strlen(f->src))
+               len += strlen(f->src) + 1;
+       buf = malloc(len);
+       if (!buf)
+               return NULL;
+       out = buf;
+       /* Set us as having malloc'd header only, so it will eventually
+          get freed. */
+       out->frametype = f->frametype;
+       out->subclass = f->subclass;
+       out->datalen = f->datalen;
+       out->samples = f->samples;
+       out->mallocd = AST_MALLOCD_HDR;
+       out->offset = AST_FRIENDLY_OFFSET;
+       out->data = buf + sizeof(struct ast_frame) + AST_FRIENDLY_OFFSET;
+       if (f->src && strlen(f->src)) {
+               out->src = out->data + f->datalen;
+               /* Must have space since we allocated for it */
+               strcpy(out->src, f->src);
+       } else
+               out->src = NULL;
+       out->prev = NULL;
+       out->next = NULL;
+       memcpy(out->data, f->data, out->datalen);       
+       return out;
 }
 
 struct ast_frame *ast_fr_fdread(int fd)
diff --git a/pbx.c b/pbx.c
index 63f251e..1115580 100755 (executable)
--- a/pbx.c
+++ b/pbx.c
@@ -678,97 +678,125 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *cont
 
 static void pbx_substitute_variables_temp(struct ast_channel *c,char *cp3,char **cp4)
 {
-       int offset;
+       char *first,*second;
+       int offset,offset2;
        struct ast_var_t *variables;
        char *name, *num; /* for callerid name + num variables */
        struct varshead *headp;
        char pri[80];
         headp=&c->varshead;
         *cp4=NULL;
-                               /* Now we have the variable name on cp3 */
-                               if (!strcmp(cp3, "CALLERIDNUM")) {
-                                               char cid[256] = "";
-                                               if (c->callerid)
-                                                       strncpy(cid, c->callerid, sizeof(cid) - 1);
-                                               ast_callerid_parse(cid, &name, &num);
-                                               if (num) {
-                                                       ast_shrink_phone_number(num);
-                                                       *cp4 = num;
-                                               } else
-                                                       *cp4 = "";
-                                       } else if (!strcmp(cp3, "CALLERIDNAME")) {
-                                               char cid[256] = "";
-                                               if (c->callerid)
-                                                       strncpy(cid, c->callerid, sizeof(cid) - 1);
-                                               ast_callerid_parse(cid, &name, &num);
-                                               if (name)
-                                                       *cp4 = name;
-                                               else
-                                                       *cp4 = "";
-                                       } else if (!strcmp(cp3, "CALLERID")) {
-                                               *cp4 = c->callerid;
-                                               if (!(*cp4))
-                                                       *cp4 = "";
-                                       } else if (!strcmp(cp3, "EXTEN")) {
-                                               *cp4 = c->exten;
-                                       } else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && 
-                                               /* XXX Remove me eventually */
-                                               (sscanf(cp3 + strlen("EXTEN-"), "%d", &offset) == 1)) {
-                                               if (offset < 0)
-                                                       offset=0;
-                                               if (offset > strlen(c->exten))
-                                                       offset = strlen(c->exten);
-                                               *cp4 = c->exten + offset;
-                                               ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
-                                       } else if (!strncmp(cp3, "EXTEN:", strlen("EXTEN:")) && 
-                                               (sscanf(cp3 + strlen("EXTEN:"), "%d", &offset) == 1)) {
-                                               if (offset < 0)
-                                                       offset=0;
-                                               if (offset > strlen(c->exten))
-                                                       offset = strlen(c->exten);
-                                               *cp4 = c->exten + offset;
-                                       } else if (!strcmp(cp3, "RDNIS")) {
-                                               *cp4 = c->rdnis;
-                                               if (!(*cp4))
-                                                       *cp4 = "";
-                                       } else if (!strcmp(cp3, "CONTEXT")) {
-                                               *cp4 = c->context;
-                                       } else if (!strcmp(cp3, "PRIORITY")) {
-                                               snprintf(pri, sizeof(pri), "%d", c->priority);
-                                               *cp4 = pri;
-                                       } else {
-                                       AST_LIST_TRAVERSE(headp,variables,entries) {
+        /* Now we have the variable name on cp3 */
+       if ((first=strchr(cp3,':'))) {
+               *first='\0';
+               offset=atoi(first+1);
+               if ((second=strchr(first+1,':'))) {
+                       *second='\0';
+                       offset2=atoi(second+1);
+               } else {
+                       offset2=offset;
+                       offset=0;
+               }
+               pbx_substitute_variables_temp(c,cp3,cp4);
+               if (!(*cp4)) return;
+               if (abs(offset)>strlen(*cp4)) {
+                       if (offset>=0) offset=strlen(*cp4);
+                       else offset=-strlen(*cp4);
+               }
+               if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*cp4))) {
+                       if (offset>=0) offset2=strlen(*cp4)-offset;
+                       else offset2=strlen(*cp4)+offset;
+               }
+               if (offset>=0)
+                       *cp4+=offset;
+               else
+                       *cp4+=strlen(*cp4)+offset;
+               (*cp4)[offset2] = '\0';
+       } else if (!strcmp(cp3, "CALLERIDNUM")) {
+               char cid[256] = "";
+               if (c->callerid)
+                       strncpy(cid, c->callerid, sizeof(cid) - 1);
+               ast_callerid_parse(cid, &name, &num);
+               if (num) {
+                       ast_shrink_phone_number(num);
+                       *cp4 = num;
+               } else
+                       *cp4 = "";
+       } else if (!strcmp(cp3, "CALLERIDNAME")) {
+               char cid[256] = "";
+               if (c->callerid)
+                       strncpy(cid, c->callerid, sizeof(cid) - 1);
+               ast_callerid_parse(cid, &name, &num);
+               if (name)
+                       *cp4 = name;
+               else
+                       *cp4 = "";
+       } else if (!strcmp(cp3, "CALLERID")) {
+               *cp4 = c->callerid;
+               if (!(*cp4))
+                       *cp4 = "";
+       } else if (!strcmp(cp3, "EXTEN")) {
+               *cp4 = c->exten;
+       } else if (!strncmp(cp3, "EXTEN-", strlen("EXTEN-")) && 
+               /* XXX Remove me eventually */
+               (sscanf(cp3 + strlen("EXTEN-"), "%d", &offset) == 1)) {
+               if (offset < 0)
+                       offset=0;
+               if (offset > strlen(c->exten))
+                       offset = strlen(c->exten);
+               *cp4 = c->exten + offset;
+               ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been derprecated in favor of 'EXTEN:foo'\n");
 #if 0
-                                               ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+       } else if (!strncmp(cp3, "EXTEN:", strlen("EXTEN:")) && 
+               (sscanf(cp3 + strlen("EXTEN:"), "%d", &offset) == 1)) {
+               if (offset < 0)
+                       offset=0;
+               if (offset > strlen(c->exten))
+                       offset = strlen(c->exten);
+               *cp4 = c->exten + offset;
 #endif
-                                                       if (strcasecmp(ast_var_name(variables),cp3)==0)
-                                                               *cp4=ast_var_value(variables);
-                                               }
-                                               if (!(*cp4)) {
-                                                       /* Try globals */
-                                               AST_LIST_TRAVERSE(&globals,variables,entries) {
+       } else if (!strcmp(cp3, "RDNIS")) {
+               *cp4 = c->rdnis;
+               if (!(*cp4))
+                       *cp4 = "";
+       } else if (!strcmp(cp3, "CONTEXT")) {
+               *cp4 = c->context;
+       } else if (!strcmp(cp3, "PRIORITY")) {
+               snprintf(pri, sizeof(pri), "%d", c->priority);
+               *cp4 = pri;
+       } else {
+               AST_LIST_TRAVERSE(headp,variables,entries) {
 #if 0
-                                                       ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+                       ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
 #endif
-                                                               if (strcasecmp(ast_var_name(variables),cp3)==0)
-                                                                       *cp4=ast_var_value(variables);
-                                                       }
-                                               }
-                                               if (!(*cp4)) {
-                                                       int len=strlen(cp3);
-                                                       int len_env=strlen("ENV(");
-                                                       if (len > (len_env+1) && !strncasecmp(cp3,"ENV(",len_env) && !strcmp(cp3+len-1,")")) {
-                                                               cp3[len-1]='\0';
-                                                               *cp4=getenv(cp3+len_env);
-                                                       }
-                                               }
-                                       }
+                       if (strcasecmp(ast_var_name(variables),cp3)==0)
+                               *cp4=ast_var_value(variables);
+               }
+               if (!(*cp4)) {
+                       /* Try globals */
+                       AST_LIST_TRAVERSE(&globals,variables,entries) {
+#if 0
+                               ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",cp3,ast_var_name(variables));
+#endif
+                               if (strcasecmp(ast_var_name(variables),cp3)==0)
+                                       *cp4=ast_var_value(variables);
+                       }
+               }
+               if (!(*cp4)) {
+                       int len=strlen(cp3);
+                       int len_env=strlen("ENV(");
+                       if (len > (len_env+1) && !strncasecmp(cp3,"ENV(",len_env) && !strcmp(cp3+len-1,")")) {
+                               cp3[len-1]='\0';
+                               *cp4=getenv(cp3+len_env);
+                       }
+               }
+       }
 }
 
 static void pbx_substitute_variables_helper(struct ast_channel *c,char *cp1,char **ecp2,int count)
 {
        char *cp4,*cp2;
-       char *tmp,*wherearewe,*finish,*ltmp,*lval,*nextvar;
+       char *tmp,*wherearewe,*finish=NULL,*ltmp,*lval,*nextvar;
        int length,variables=0;
 
        wherearewe=tmp=cp1;
index ab25438..f7b143d 100755 (executable)
@@ -1512,8 +1512,12 @@ static int pbx_load_module(void)
                                                        appl = stringp;
                                                        if (!appl)
                                                                appl="";
-                                                       if (!(start = strchr(appl, '(')))
-                                                               appl = strsep(&stringp, ",");
+                                                       if (!(start = strchr(appl, '('))) {
+                                                               if (stringp)
+                                                                       appl = strsep(&stringp, ",");
+                                                               else
+                                                                       appl = "";
+                                                       }
                                                        if (start && (end = strrchr(appl, ')'))) {
                                                                *start = *end = '\0';
                                                                data = start + 1;
@@ -1525,7 +1529,10 @@ static int pbx_load_module(void)
                                                                data = strsep(&stringp, "\"");
                                                                stringp++;
                                                        } else {
-                                                               data = strsep(&stringp, ",");
+                                                               if (stringp)
+                                                                       data = strsep(&stringp, ",");
+                                                               else
+                                                                       data = "";
                                                        }
                                                        cidmatch = strchr(ext, '/');
                                                        if (cidmatch) {
index ab347f9..dc1839d 100755 (executable)
@@ -221,8 +221,8 @@ static void *monmp3thread(void *data)
                        res = read(class->pseudofd, buf, sizeof(buf));
                } else {
                        /* otherwise just sleep (unreliable) */
-                       usleep(250000);
-                       res = 2000;
+                       usleep(100000); /* Sleep 100 ms */
+                       res = 800;              /* 800 samples */
                }
                if (!class->members)
                        continue;
@@ -328,7 +328,7 @@ static struct mohdata *mohalloc(struct mohclass *cl)
 static void moh_release(struct ast_channel *chan, void *data)
 {
        struct mohdata *moh = data, *prev, *cur;
-       int oldrfmt, oldwfmt;
+       int oldwfmt;
        ast_pthread_mutex_lock(&moh_lock);
        /* Unlink */
        prev = NULL;
@@ -350,8 +350,8 @@ static void moh_release(struct ast_channel *chan, void *data)
        oldwfmt = moh->origwfmt;
        free(moh);
        if (chan) {
-               if (ast_set_write_format(chan, oldwfmt)) 
-                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d/%d\n", chan->name, oldwfmt, oldrfmt);
+               if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
+                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d\n", chan->name, oldwfmt);
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
        }