Version 0.2.0 from FTP
[asterisk/asterisk.git] / channels / chan_iax.c
index 679ba65..7f8e233 100755 (executable)
@@ -2,7 +2,7 @@
  * Asterisk -- A telephony toolkit for Linux.
  *
  * Implementation of Inter-Asterisk eXchange
- * 
+ *
  * Copyright (C) 1999, Mark Spencer
  *
  * Mark Spencer <markster@linux-support.net>
@@ -11,6 +11,7 @@
  * the GNU General Public License
  */
 
+#include <asterisk/lock.h>
 #include <asterisk/frame.h> 
 #include <asterisk/channel.h>
 #include <asterisk/channel_pvt.h>
@@ -26,6 +27,7 @@
 #include <asterisk/md5.h>
 #include <asterisk/cdr.h>
 #include <asterisk/crypto.h>
+#include <asterisk/acl.h>
 #include <arpa/inet.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 
 #include "iax.h"
 
+/*
+ * Uncomment to try experimental IAX bridge optimization,
+ * designed to reduce latency when IAX calls cannot
+ * be trasnferred
+ */
+
+#define BRIDGE_OPTIMIZATION 
+
+
 #define DEFAULT_RETRY_TIME 1000
 #define MEMORY_SIZE 100
 #define DEFAULT_DROP 3
@@ -74,8 +85,8 @@ static int tos = 0;
 static int expirey = AST_DEFAULT_REG_EXPIRE;
 
 static int usecnt;
-static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t iaxs_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
+static pthread_mutex_t iaxs_lock = AST_MUTEX_INITIALIZER;
 
 int (*regfunk)(char *username, int onoff) = NULL;
 
@@ -114,17 +125,6 @@ static pthread_t netthreadid;
 #define IAX_STATE_AUTHENTICATED (1 << 1)
 #define IAX_STATE_TBD                  (1 << 2)
 
-#define IAX_SENSE_DENY                 0
-#define IAX_SENSE_ALLOW                        1
-
-struct iax_ha {
-       /* Host access rule */
-       struct in_addr netaddr;
-       struct in_addr netmask;
-       int sense;
-       struct iax_ha *next;
-};
-
 struct iax_context {
        char context[AST_MAX_EXTENSION];
        struct iax_context *next;
@@ -139,7 +139,7 @@ struct iax_user {
        int amaflags;
        int hascallerid;
        char callerid[AST_MAX_EXTENSION];
-       struct iax_ha *ha;
+       struct ast_ha *ha;
        struct iax_context *contexts;
        struct iax_user *next;
 };
@@ -149,6 +149,7 @@ struct iax_peer {
        char username[80];              
        char secret[80];
        char outkey[80];                /* What key we use to talk to this peer */
+       char context[AST_MAX_EXTENSION];        /* Default context (for transfer really) */
        struct sockaddr_in addr;
        int formats;
        struct in_addr mask;
@@ -161,12 +162,15 @@ struct iax_peer {
        char inkeys[80];                                /* Key(s) this peer can use to authenticate to us */
 
        int hascallerid;
+       /* Suggested caller id if registering */
        char callerid[AST_MAX_EXTENSION];
+       /* Whether or not to send ANI */
+       int sendani;
        int expire;                                             /* Schedule entry for expirey */
        int expirey;                                    /* How soon to expire */
        int capability;                                 /* Capability */
        int delme;                                              /* I need to be deleted */
-       struct iax_ha *ha;
+       struct ast_ha *ha;
        struct iax_peer *next;
 };
 
@@ -211,7 +215,6 @@ struct chan_iax_pvt {
        /* Pipes for communication.  pipe[1] belongs to the
           network thread (write), and pipe[0] belongs to the individual 
           channel (read) */
-       int pipe[2];
        /* Whether or not we Quelch audio */
        int quelch;
        /* Last received voice format */
@@ -268,8 +271,10 @@ struct chan_iax_pvt {
        char context[80];
        /* Caller ID if available */
        char callerid[80];
-       /* Hidden Caller ID if appropriate */
-       char hidden_callerid[80];
+       /* Hidden Caller ID (i.e. ANI) if appropriate */
+       char ani[80];
+       /* Whether or not ani should be transmitted in addition to Caller*ID */
+       int sendani;
        /* DNID */
        char dnid[80];
        /* Requested Extension */
@@ -347,7 +352,7 @@ struct ast_iax_frame {
        /* Retransmission ID */
        int retrans;
 
-       
+
        /* Easy linking */
        struct ast_iax_frame *next;
        struct ast_iax_frame *prev;
@@ -400,7 +405,7 @@ static struct iax_dpcache {
 pthread_mutex_t dpcache_lock;
 
 #ifdef DEBUG_SUPPORT
-void showframe(struct ast_iax_frame *f, struct ast_iax_full_hdr *fhi, int rx)
+void showframe(struct ast_iax_frame *f, struct ast_iax_full_hdr *fhi, int rx, struct sockaddr_in *sin)
 {
        char *frames[] = {
                "(0?)",
@@ -496,13 +501,14 @@ void showframe(struct ast_iax_frame *f, struct ast_iax_full_hdr *fhi, int rx)
                subclass = subclass2;
        }
        ast_verbose(
-"%s-Frame Retry[%s] -- Seqno: %2.2d  Type: %s Subclass: %s\n", 
+"%s-Frame Retry[%s] -- Seqno: %2.2d  Type: %s Subclass: %s\n",
        (rx ? "Rx" : "Tx"),
        retries, ntohs(fh->seqno), class, subclass);
-               fprintf(stderr, 
-"   Timestamp: %05dms  Callno: %4.4d  DCall: %4.4d\n", 
+               fprintf(stderr,
+"   Timestamp: %05dms  Callno: %5.5d  DCall: %5.5d [%s:%d]\n",
        ntohl(fh->ts),
-       ntohs(fh->callno) & ~AST_FLAG_FULL, (short) ntohs(fh->dcallno));
+       (short)(ntohs(fh->callno) & ~AST_FLAG_FULL), (short) ntohs(fh->dcallno),
+               inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
 }
 #endif
 
@@ -519,8 +525,12 @@ static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts);
 static int send_ping(void *data)
 {
        int callno = (long)data;
+       /* Ping only if it's real, not if it's bridged */
        if (iaxs[callno]) {
-               send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, 0, NULL, 0, -1);
+#ifdef BRIDGE_OPTIMIZATION
+               if (iaxs[callno]->bridgecallno < 0)
+#endif
+                       send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, 0, NULL, 0, -1);
                return 1;
        } else
                return 0;
@@ -529,8 +539,12 @@ static int send_ping(void *data)
 static int send_lagrq(void *data)
 {
        int callno = (long)data;
+       /* Ping only if it's real not if it's bridged */
        if (iaxs[callno]) {
-               send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+#ifdef BRIDGE_OPTIMIZATION
+               if (iaxs[callno]->bridgecallno < 0)
+#endif         
+                       send_command(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
                return 1;
        } else
                return 0;
@@ -568,24 +582,9 @@ static int uncompress_subclass(unsigned char csub)
 static struct chan_iax_pvt *new_iax(void)
 {
        struct chan_iax_pvt *tmp;
-       int flags;
        tmp = malloc(sizeof(struct chan_iax_pvt));
        if (tmp) {
                memset(tmp, 0, sizeof(struct chan_iax_pvt));
-               /* On my linux system, pipe's are more than 2x as fast as socketpairs, but too short, so
-                  I go to socketpairs */
-               if (socketpair(AF_LOCAL, SOCK_STREAM, 0, tmp->pipe)) {
-                       ast_log(LOG_WARNING, "Unable to create pipe: %s\n", strerror(errno));
-                       free(tmp);
-                       return NULL;
-               }
-               flags = fcntl(tmp->pipe[1], F_GETFL);
-               if (flags < 0) 
-                       ast_log(LOG_WARNING, "Unable to get flags\n");
-#if 1
-               if (fcntl(tmp->pipe[1], F_SETFL, flags | O_NONBLOCK))
-                       ast_log(LOG_WARNING, "Unable to set flags\n");
-#endif                 
                tmp->callno = -1;
                tmp->peercallno = -1;
                tmp->transfercallno = -1;
@@ -699,7 +698,7 @@ static int match(struct sockaddr_in *sin, short callno, short dcallno, struct ch
        if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
                (cur->addr.sin_port == sin->sin_port)) {
                /* This is the main host */
-               if ((cur->peercallno == callno) || 
+               if ((cur->peercallno == callno) ||
                        ((dcallno == cur->callno) && (cur->peercallno) == -1)) {
                        /* That's us.  Be sure we keep track of the peer call number */
                        return 1;
@@ -734,7 +733,7 @@ static int find_callno(short callno, short dcallno ,struct sockaddr_in *sin, int
        if ((res < 0) && (new >= NEW_ALLOW)) {
                /* Create a new one */
                start = nextcallno;
-               for (x = nextcallno + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX_MAX_CALLS) 
+               for (x = (nextcallno + 1) % AST_IAX_MAX_CALLS; iaxs[x] && (x != start); x = (x + 1) % AST_IAX_MAX_CALLS)
                if (x == start) {
                        ast_log(LOG_WARNING, "Unable to accept more calls\n");
                        return -1;
@@ -768,7 +767,7 @@ static int iax_send(struct chan_iax_pvt *pvt, struct ast_frame *f, unsigned int
 
 static int do_deliver(void *data)
 {
-       /* Just deliver the packet by writing it to half of the pipe. */
+       /* Just deliver the packet by using queueing */
        struct ast_iax_frame *fr = data;
        unsigned int ts;
        fr->retrans = -1;
@@ -786,7 +785,9 @@ static int do_deliver(void *data)
                                iaxs[fr->callno]->lag = ts - fr->ts;
                        }
                } else {
-                       ast_fr_fdwrite(iaxs[fr->callno]->pipe[1], fr->f);
+                       if (iaxs[fr->callno]->owner) {
+                               ast_queue_frame(iaxs[fr->callno]->owner, fr->f, 1);
+                       }
                }
        }
        /* Free the packet */
@@ -841,23 +842,30 @@ static int send_packet(struct ast_iax_frame *f)
                ast_log(LOG_WARNING, "Call number = %d\n", f->callno);
                return -1;
        }
+       if (!iaxs[f->callno])
+               return -1;
        if (iaxs[f->callno]->error)
                return -1;
+       if (f->transfer) {
 #ifdef DEBUG_SUPPORT
-       if (iaxdebug)
-                       showframe(f, NULL, 0);
+               if (iaxdebug)
+                       showframe(f, NULL, 0, &iaxs[f->callno]->transfer);
 #endif
-       if (f->transfer) {
-               res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->transfer, 
+               res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->transfer,
                                        sizeof(iaxs[f->callno]->transfer));
-       } else                          
-               res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->addr, 
+       } else {
+#ifdef DEBUG_SUPPORT
+               if (iaxdebug)
+                       showframe(f, NULL, 0, &iaxs[f->callno]->addr);
+#endif
+               res = sendto(netsocket, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[f->callno]->addr,
                                        sizeof(iaxs[f->callno]->addr));
-       if (res < 0) { 
+       }
+       if (res < 0) {
                if (option_debug)
                        ast_log(LOG_DEBUG, "Received error: %s\n", strerror(errno));
                handle_error();
-       } else 
+       } else
                res = 0;
        return res;
 }
@@ -883,9 +891,17 @@ static void iax_destroy(int callno)
                pvt->alreadygone = 1;
 
                if (pvt->owner) {
-                       /* If there's an owner, prod it to give up */
-                       ast_fr_fdhangup(pvt->pipe[1]);
-                       return;
+                       if (ast_pthread_mutex_lock(&pvt->owner->lock)) {
+                               ast_log(LOG_WARNING, "Unable to lock channel %s\n", pvt->owner->name);
+                       } else if (!pvt->owner || (pvt->owner->pvt->pvt != pvt)) {
+                               ast_log(LOG_WARNING, "Something very strange happened...\n");
+                       } else {
+                               /* If there's an owner, prod it to give up */
+                               pvt->owner->pvt->pvt = NULL;
+                               pvt->owner->_softhangup |= AST_SOFTHANGUP_DEV;
+                               ast_queue_hangup(pvt->owner, 0);
+                               ast_pthread_mutex_unlock(&pvt->owner->lock);
+                       }
                }
 
                iaxs[callno] = NULL;
@@ -898,8 +914,6 @@ static void iax_destroy(int callno)
                if (pvt->reg) {
                        pvt->reg->callno = -1;
                }
-               close(pvt->pipe[0]);
-               close(pvt->pipe[1]);
                free(pvt);
        }
 }
@@ -911,7 +925,7 @@ static int attempt_transmit(void *data)
        struct ast_iax_frame *f = data;
        int freeme=0;
        /* Make sure this call is still active */
-       if (iaxs[f->callno]) {
+       if ((f->callno > -1) && iaxs[f->callno]) {
                if ((f->retries < 0) /* Already ACK'd */ ||
                    (f->retries >= max_retries) /* Too many attempts */) {
                                /* Record an error if we've transmitted too many times */
@@ -924,12 +938,13 @@ static int attempt_transmit(void *data)
                                                        iax_destroy(f->callno);
                                        } else {
                                                if (iaxs[f->callno]->owner)
-                                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", inet_ntoa(iaxs[f->callno]->addr.sin_addr), f->f->frametype, f->f->subclass, f->ts, f->seqno);
+                                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %d, ts=%d, seqno=%d)\n", inet_ntoa(iaxs[f->callno]->addr.sin_addr),iaxs[f->callno]->owner->name , f->f->frametype, f->f->subclass, f->ts, f->seqno);
                                                iaxs[f->callno]->error = ETIMEDOUT;
-                                               if (iaxs[f->callno]->owner)
+                                               if (iaxs[f->callno]->owner) {
                                                        /* Hangup the fd */
-                                                       ast_fr_fdhangup(iaxs[f->callno]->pipe[1]);
-                                               else {
+                                                       ast_softhangup(iaxs[f->callno]->owner, AST_SOFTHANGUP_DEV);
+                                                       ast_queue_hangup(iaxs[f->callno]->owner, 1);
+                                               } else {
                                                        if (iaxs[f->callno]->reg) {
                                                                memset(&iaxs[f->callno]->reg->us, 0, sizeof(iaxs[f->callno]->reg->us));
                                                                iaxs[f->callno]->reg->regstate = REG_STATE_TIMEOUT;
@@ -1106,6 +1121,26 @@ static struct ast_cli_entry cli_show_cache =
 
 static unsigned int calc_rxstamp(struct chan_iax_pvt *p);
 
+#ifdef BRIDGE_OPTIMIZATION
+static unsigned int calc_fakestamp(struct chan_iax_pvt *from, struct chan_iax_pvt *to, unsigned int ts);
+
+static int forward_delivery(struct ast_iax_frame *fr)
+{
+       struct chan_iax_pvt *p1, *p2;
+       p1 = iaxs[fr->callno];
+       p2 = iaxs[p1->bridgecallno];
+       if (!p1)
+               return -1;
+       if (!p2)
+               return -1;
+       /* Fix relative timestamp */
+       fr->ts = calc_fakestamp(p1, p2, fr->ts);
+       /* Now just send it send on the 2nd one 
+          with adjusted timestamp */
+       return iax_send(p2, fr->f, fr->ts, -1, 0, 0, 0);
+}
+#endif
+
 static int schedule_delivery(struct ast_iax_frame *fr, int reallydeliver)
 {
        int ms,x;
@@ -1114,7 +1149,8 @@ static int schedule_delivery(struct ast_iax_frame *fr, int reallydeliver)
        /* ms is a measure of the "lateness" of the packet relative to the first
           packet we received, which always has a lateness of 1.  */
        ms = calc_rxstamp(iaxs[fr->callno]) - fr->ts;
-       if (ms > 32768) {
+
+       if (ms > 32767) {
                /* What likely happened here is that our counter has circled but we haven't
                   gotten the update from the main packet.  We'll just pretend that we did, and
                   update the timestamp appropriately. */
@@ -1292,11 +1328,13 @@ static int iax_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan
        return 0;
 }
 
-static int create_addr(struct sockaddr_in *sin, int *capability, char *peer)
+static int create_addr(struct sockaddr_in *sin, int *capability, int *sendani, char *peer, char *context)
 {
        struct hostent *hp;
        struct iax_peer *p;
        int found=0;
+       if (sendani)
+               *sendani = 0;
        sin->sin_family = AF_INET;
        ast_pthread_mutex_lock(&peerl.lock);
        p = peerl.peers;
@@ -1306,6 +1344,10 @@ static int create_addr(struct sockaddr_in *sin, int *capability, char *peer)
                        if (capability)
                                *capability = p->capability;
                        if (p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) {
+                               if (sendani)
+                                       *sendani = p->sendani;
+                               if (context)
+                                       strncpy(context, p->context, AST_MAX_EXTENSION - 1);
                                if (p->addr.sin_addr.s_addr) {
                                        sin->sin_addr = p->addr.sin_addr;
                                        sin->sin_port = p->addr.sin_port;
@@ -1345,9 +1387,10 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout)
        char *hname;
        char requeststr[256] = "";
        char myrdest [5] = "s";
+       char context[AST_MAX_EXTENSION] ="";
        char *portno = NULL;
        struct chan_iax_pvt *p = c->pvt->pvt;
-       if ((c->state != AST_STATE_DOWN) && (c->state != AST_STATE_RESERVED)) {
+       if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) {
                ast_log(LOG_WARNING, "Line is already in use (%s)?\n", c->name);
                return -1;
        }
@@ -1376,10 +1419,12 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout)
                strtok(hname, ":");
                portno = strtok(hname, ":");
        }
-       if (create_addr(&sin, NULL, hname)) {
+       if (create_addr(&sin, NULL, NULL, hname, context)) {
                ast_log(LOG_WARNING, "No address associated with '%s'\n", hname);
                return -1;
        }
+       /* Keep track of the context for outgoing calls too */
+       strncpy(c->context, context, sizeof(c->context) - 1);
        if (portno) {
                sin.sin_port = htons(atoi(portno));
        }
@@ -1389,6 +1434,8 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout)
        MYSNPRINTF "exten=%s;", rdest);
        if (c->callerid)
                MYSNPRINTF "callerid=%s;", c->callerid);
+       if (p->sendani && c->ani)
+               MYSNPRINTF "ani=%s;", c->ani);
        if (c->language && strlen(c->language))
                MYSNPRINTF "language=%s;", c->language);
        if (c->dnid)
@@ -1419,7 +1466,7 @@ static int iax_call(struct ast_channel *c, char *dest, int timeout)
                ast_verbose(VERBOSE_PREFIX_3 "Calling using options '%s'\n", requeststr);
        send_command((struct chan_iax_pvt *)c->pvt->pvt, AST_FRAME_IAX,
                AST_IAX_COMMAND_NEW, 0, requeststr, strlen(requeststr) + 1, -1);
-       c->state = AST_STATE_RINGING;
+       ast_setstate(c, AST_STATE_RINGING);
        return 0;
 }
 
@@ -1441,7 +1488,7 @@ static int iax_predestroy(struct chan_iax_pvt *pvt)
        }
        c = pvt->owner;
        if (c) {
-               c->softhangup = 1;
+               c->_softhangup |= AST_SOFTHANGUP_DEV;
                c->pvt->pvt = NULL;
                pvt->owner = NULL;
                ast_pthread_mutex_lock(&usecnt_lock);
@@ -1454,10 +1501,12 @@ static int iax_predestroy(struct chan_iax_pvt *pvt)
        return 0;
 }
 
-static int iax_hangup(struct ast_channel *c) {
+static int iax_hangup(struct ast_channel *c) 
+{
        struct chan_iax_pvt *pvt = c->pvt->pvt;
        int alreadygone;
        if (pvt) {
+               ast_log(LOG_DEBUG, "We're hanging up %s now...\n", c->name);
                alreadygone = pvt->alreadygone;
                /* Send the hangup unless we have had a transmission error or are already gone */
                if (!pvt->error && !alreadygone) 
@@ -1493,19 +1542,9 @@ static int iax_setoption(struct ast_channel *c, int option, void *data, int data
 }
 static struct ast_frame *iax_read(struct ast_channel *c) 
 {
-       struct chan_iax_pvt *pvt = c->pvt->pvt;
-       struct ast_frame *f;
-       if (pvt->error) {
-               ast_log(LOG_DEBUG, "Connection closed, error: %s\n", strerror(pvt->error));
-               return NULL;
-       }
-       f = ast_fr_fdread(pvt->pipe[0]);
-       if (f) {
-               if ((f->frametype == AST_FRAME_CONTROL) &&
-                   (f->subclass == AST_CONTROL_ANSWER))
-                               c->state = AST_STATE_UP;
-       }
-       return f;
+       static struct ast_frame f = { AST_FRAME_NULL, };
+       ast_log(LOG_NOTICE, "I should never be called!\n");
+       return &f;
 }
 
 static int iax_start_transfer(struct ast_channel *c0, struct ast_channel *c1)
@@ -1548,8 +1587,11 @@ static int iax_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
        cs[1] = c1;
        for (/* ever */;;) {
                /* Check in case we got masqueraded into */
-               if ((c0->type != type) || (c1->type != type))
+               if ((c0->type != type) || (c1->type != type)) {
+                       if (option_verbose > 2)
+                               ast_verbose(VERBOSE_PREFIX_3 "Can't masquerade, we're different...\n");
                        return -2;
+               }
                if (!transferstarted) {
                        /* Try the transfer */
                        if (iax_start_transfer(c0, c1))
@@ -1560,8 +1602,8 @@ static int iax_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++;
-                       c1->softhangup++;
+                       c0->_softhangup |= AST_SOFTHANGUP_DEV;
+                       c1->_softhangup |= AST_SOFTHANGUP_DEV;
                        *fo = NULL;
                        *rc = c0;
                        res = 0;
@@ -1679,7 +1721,7 @@ static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int ca
 {
        char host[256];
        struct ast_channel *tmp;
-       tmp = ast_channel_alloc();
+       tmp = ast_channel_alloc(1);
        if (tmp) {
                if (!iax_getpeername(i->addr, host, sizeof(host)))
                        snprintf(host, sizeof(host), "%s:%d", inet_ntoa(i->addr.sin_addr), ntohs(i->addr.sin_port));
@@ -1688,7 +1730,6 @@ static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int ca
                else
                        snprintf(tmp->name, sizeof(tmp->name), "IAX[%s]/%d", host, i->callno);
                tmp->type = type;
-               tmp->fds[0] = i->pipe[0];
                /* We can support any format by default, until we get restricted */
                tmp->nativeformats = capability;
                tmp->readformat = 0;
@@ -1708,8 +1749,8 @@ static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int ca
                tmp->pvt->bridge = iax_bridge;
                if (strlen(i->callerid))
                        tmp->callerid = strdup(i->callerid);
-               if (strlen(i->hidden_callerid))
-                       tmp->hidden_callerid = strdup(i->hidden_callerid);
+               if (strlen(i->ani))
+                       tmp->ani = strdup(i->ani);
                if (strlen(i->language))
                        strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
                if (strlen(i->dnid))
@@ -1724,7 +1765,7 @@ static struct ast_channel *ast_iax_new(struct chan_iax_pvt *i, int state, int ca
                tmp->pvt->fixup = iax_fixup;
                i->owner = tmp;
                i->capability = capability;
-               tmp->state = state;
+               ast_setstate(tmp, state);
                ast_pthread_mutex_lock(&usecnt_lock);
                usecnt++;
                ast_pthread_mutex_unlock(&usecnt_lock);
@@ -1758,13 +1799,42 @@ static unsigned int calc_timestamp(struct chan_iax_pvt *p, unsigned int ts)
        return ms;
 }
 
+#ifdef BRIDGE_OPTIMIZATION
+static unsigned int calc_fakestamp(struct chan_iax_pvt *p1, struct chan_iax_pvt *p2, unsigned int fakets)
+{
+       int ms;
+       /* Receive from p1, send to p2 */
+       
+       /* Setup rxcore if necessary on outgoing channel */
+       if (!p1->rxcore.tv_sec && !p1->rxcore.tv_usec)
+               gettimeofday(&p1->rxcore, NULL);
+
+       /* Setup txcore if necessary on outgoing channel */
+       if (!p2->offset.tv_sec && !p2->offset.tv_usec)
+               gettimeofday(&p2->offset, NULL);
+       
+       /* Now, ts is the timestamp of the original packet in the orignal context.
+          Adding rxcore to it gives us when we would want the packet to be delivered normally.
+          Subtracting txcore of the outgoing channel gives us what we'd expect */
+       
+       ms = (p1->rxcore.tv_sec - p2->offset.tv_sec) * 1000 + (p1->rxcore.tv_usec - p1->offset.tv_usec) / 1000;
+       fakets += ms;
+       if (fakets <= p2->lastsent)
+               fakets = p2->lastsent + 1;
+       p2->lastsent = fakets;
+       return fakets;
+}
+#endif
+
 static unsigned int calc_rxstamp(struct chan_iax_pvt *p)
 {
        /* Returns where in "receive time" we are */
        struct timeval tv;
        unsigned int ms;
+       /* Setup rxcore if necessary */
        if (!p->rxcore.tv_sec && !p->rxcore.tv_usec)
                gettimeofday(&p->rxcore, NULL);
+
        gettimeofday(&tv, NULL);
        ms = (tv.tv_sec - p->rxcore.tv_sec) * 1000 + (tv.tv_usec - p->rxcore.tv_usec) / 1000;
        return ms;
@@ -2061,6 +2131,8 @@ static struct ast_cli_entry  cli_no_debug =
 static int iax_write(struct ast_channel *c, struct ast_frame *f)
 {
        struct chan_iax_pvt *i = c->pvt->pvt;
+       if (!i)
+               return -1;
        /* If there's an outstanding error, return failure now */
        if (i->error) {
                ast_log(LOG_DEBUG, "Write error: %s\n", strerror(errno));
@@ -2099,6 +2171,13 @@ static int send_command(struct chan_iax_pvt *i, char type, int command, unsigned
        return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
 }
 
+#ifdef BRIDGE_OPTIMIZATION
+static int forward_command(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
+{
+       return __send_command(iaxs[i->bridgecallno], type, command, ts, data, datalen, seqno, 0, 0, 0);
+}
+#endif
+
 static int send_command_final(struct chan_iax_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno)
 {
        iax_predestroy(i);
@@ -2125,20 +2204,6 @@ static int apply_context(struct iax_context *con, char *context)
        return 0;
 }
 
-static int apply_ha(struct iax_ha *ha, struct sockaddr_in *sin)
-{
-       /* Start optimistic */
-       int res = IAX_SENSE_ALLOW;
-       while(ha) {
-               /* For each rule, if this address and the netmask = the net address
-                  apply the current rule */
-               if ((sin->sin_addr.s_addr & ha->netmask.s_addr) == (ha->netaddr.s_addr))
-                       res = ha->sense;
-               ha = ha->next;
-       }
-       return res;
-}
-
 static int iax_getformats(int callno, char *orequest)
 {
        char *var, *value;
@@ -2183,6 +2248,8 @@ static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int
                                strncpy(iaxs[callno]->exten, value, sizeof(iaxs[callno]->exten)-1);
                        else if (!strcmp(var, "callerid"))
                                strncpy(iaxs[callno]->callerid, value, sizeof(iaxs[callno]->callerid)-1);
+                       else if (!strcmp(var, "ani"))
+                               strncpy(iaxs[callno]->ani, value, sizeof(iaxs[callno]->ani) - 1);
                        else if (!strcmp(var, "dnid"))
                                strncpy(iaxs[callno]->dnid, value, sizeof(iaxs[callno]->dnid)-1);
                        else if (!strcmp(var, "context"))
@@ -2218,7 +2285,7 @@ static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int
        while(user) {
                if ((!strlen(iaxs[callno]->username) ||                         /* No username specified */
                        !strcmp(iaxs[callno]->username, user->name))    /* Or this username specified */
-                       && (apply_ha(user->ha, sin) == IAX_SENSE_ALLOW) /* Access is permitted from this IP */
+                       && ast_apply_ha(user->ha, sin)  /* Access is permitted from this IP */
                        && (!strlen(iaxs[callno]->context) ||                   /* No context specified */
                             apply_context(user->contexts, iaxs[callno]->context))) {                   /* Context is permitted */
                        /* We found our match (use the first) */
@@ -2239,11 +2306,11 @@ static int check_access(int callno, struct sockaddr_in *sin, char *orequest, int
                        strncpy(iaxs[callno]->inkeys, user->inkeys, sizeof(iaxs[callno]->inkeys));
                        /* And the permitted authentication methods */
                        strncpy(iaxs[callno]->methods, user->methods, sizeof(iaxs[callno]->methods)-1);
-                       /* If they have callerid, override the given caller id.  Always store the hidden */
+                       /* If they have callerid, override the given caller id.  Always store the ANI */
                        if (strlen(iaxs[callno]->callerid)) {
                                if (user->hascallerid)
                                        strncpy(iaxs[callno]->callerid, user->callerid, sizeof(iaxs[callno]->callerid)-1);
-                               strncpy(iaxs[callno]->hidden_callerid, user->callerid, sizeof(iaxs[callno]->hidden_callerid)-1);
+                               strncpy(iaxs[callno]->ani, user->callerid, sizeof(iaxs[callno]->ani)-1);
                        }
                        if (strlen(user->accountcode))
                                strncpy(iaxs[callno]->accountcode, user->accountcode, sizeof(iaxs[callno]->accountcode)-1);
@@ -2332,7 +2399,7 @@ static int authenticate_verify(struct chan_iax_pvt *p, char *orequest)
                                res = 0;
                                break;
                        } else if (!key)
-                               ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n");
+                               ast_log(LOG_WARNING, "requested inkey '%s' for RSA authentication does not exist\n", keyn);
                        keyn = strtok(NULL, ":");
                }
        } else if (strstr(p->methods, "md5")) {
@@ -2416,7 +2483,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, char *orequest)
                return -1;
        }
 
-       if (apply_ha(p->ha, sin) != IAX_SENSE_ALLOW) {
+       if (!ast_apply_ha(p->ha, sin)) {
                ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", inet_ntoa(sin->sin_addr), p->name);
                return -1;
        }
@@ -3055,6 +3122,27 @@ static void iax_dprequest(struct iax_dpcache *dp, int callno)
        dp->flags |= CACHE_FLAG_TRANSMITTED;
 }
 
+static int iax_vnak(int callno)
+{
+       return send_command_immediate(iaxs[callno], AST_FRAME_IAX, AST_IAX_COMMAND_VNAK, 0, NULL, 0, iaxs[callno]->iseqno);
+}
+
+static void vnak_retransmit(int callno, int last)
+{
+       struct ast_iax_frame *f;
+       ast_pthread_mutex_lock(&iaxq.lock);
+       f = iaxq.head;
+       while(f) {
+               /* Send a copy immediately */
+               if ((f->callno == callno) && iaxs[f->callno] &&
+                       (f->seqno >= last)) {
+                       send_packet(f);
+               }
+               f = f->next;
+       }
+       ast_pthread_mutex_unlock(&iaxq.lock);
+}
+
 static int socket_read(int *id, int fd, short events, void *cbdata)
 {
        struct sockaddr_in sin;
@@ -3071,6 +3159,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        struct ast_channel *c;
        struct iax_dpcache *dp;
        int format;
+       int exists;
        char rel0[256];
        char rel1[255];
        char empty[32]="";              /* Safety measure */
@@ -3085,10 +3174,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, sizeof(struct ast_iax_mini_hdr));
                return 1;
        }
-#ifdef DEBUG_SUPPORT   
+#ifdef DEBUG_SUPPORT
        if (iaxdebug)
-               showframe(NULL, fh, 1);
-#endif 
+               showframe(NULL, fh, 1, &sin);
+#endif
        if (ntohs(mh->callno) & AST_FLAG_FULL) {
                /* Get the destination call number */
                dcallno = ntohs(fh->dcallno);
@@ -3101,6 +3190,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
 #endif
                if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == AST_IAX_COMMAND_NEW) || (f.subclass == AST_IAX_COMMAND_REGREQ)))
                        new = NEW_ALLOW;
+       } else {
+               /* Don't knwo anything about it yet */
+               f.frametype = AST_FRAME_NULL;
+               f.subclass = 0;
        }
        ast_pthread_mutex_lock(&iaxs_lock);
        fr.callno = find_callno(ntohs(mh->callno) & ~AST_FLAG_FULL, dcallno, &sin, new);
@@ -3111,7 +3204,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        /* We can only raw hangup control frames */
                        if (((f.subclass != AST_IAX_COMMAND_INVAL) &&
                                 (f.subclass != AST_IAX_COMMAND_TXCNT) &&
-                                (f.subclass != AST_IAX_COMMAND_TXACC))|| 
+                                (f.subclass != AST_IAX_COMMAND_TXACC))||
                            (f.frametype != AST_FRAME_IAX))
                                raw_hangup(&sin, ntohs(fh->dcallno), ntohs(mh->callno) & ~AST_FLAG_FULL
                                );
@@ -3119,24 +3212,25 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                ast_pthread_mutex_unlock(&iaxs_lock);
                return 1;
        }
-       if (((f.subclass != AST_IAX_COMMAND_TXCNT) && 
+       if (((f.subclass != AST_IAX_COMMAND_TXCNT) &&
             (f.subclass != AST_IAX_COMMAND_TXACC)) || (f.frametype != AST_FRAME_IAX))
-               iaxs[fr.callno]->peercallno = ntohs(mh->callno) & ~AST_FLAG_FULL;
+               iaxs[fr.callno]->peercallno = (short)(ntohs(mh->callno) & ~AST_FLAG_FULL);
        if (ntohs(mh->callno) & AST_FLAG_FULL) {
                if (option_debug)
                        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);
                if ((iaxs[fr.callno]->iseqno != fr.seqno) &&
-                       (iaxs[fr.callno]->iseqno || 
+                       (iaxs[fr.callno]->iseqno ||
                                ((f.subclass != AST_IAX_COMMAND_TXCNT) &&
                                (f.subclass != AST_IAX_COMMAND_TXACC)) ||
                                (f.subclass != AST_FRAME_IAX))) {
                        if (
-                        ((f.subclass != AST_IAX_COMMAND_ACK) && 
+                        ((f.subclass != AST_IAX_COMMAND_ACK) &&
                          (f.subclass != AST_IAX_COMMAND_INVAL) &&
                          (f.subclass != AST_IAX_COMMAND_TXCNT) &&
-                         (f.subclass != AST_IAX_COMMAND_TXACC)) ||
+                         (f.subclass != AST_IAX_COMMAND_TXACC) &&
+                         (f.subclass != AST_IAX_COMMAND_VNAK)) ||
                          (f.frametype != AST_FRAME_IAX)) {
                                /* If it's not an ACK packet, it's out of order. */
                                if (option_debug)
@@ -3150,16 +3244,20 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                                        ast_log(LOG_DEBUG, "Acking anyway\n");
                                                send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.seqno);
                                        }
+                               } else {
+                                       /* Send a VNAK requesting retransmission */
+                                       iax_vnak(fr.callno);
                                }
                                ast_pthread_mutex_unlock(&iaxs_lock);
                                return 1;
                        }
                } else {
-                       /* Increment unless it's an ACK */
+                       /* Increment unless it's an ACK or VNAK */
                        if (((f.subclass != AST_IAX_COMMAND_ACK) &&
                            (f.subclass != AST_IAX_COMMAND_INVAL) &&
                            (f.subclass != AST_IAX_COMMAND_TXCNT) &&
-                           (f.subclass != AST_IAX_COMMAND_TXACC)) ||
+                           (f.subclass != AST_IAX_COMMAND_TXACC) &&
+                               (f.subclass != AST_IAX_COMMAND_VNAK)) ||
                            (f.frametype != AST_FRAME_IAX))
                                iaxs[fr.callno]->iseqno++;
                }
@@ -3180,10 +3278,25 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                         ((f.subclass != AST_IAX_COMMAND_ACK) && 
                          (f.subclass != AST_IAX_COMMAND_TXCNT) && 
                          (f.subclass != AST_IAX_COMMAND_TXACC) && 
-                         (f.subclass != AST_IAX_COMMAND_INVAL))) 
+                         (f.subclass != AST_IAX_COMMAND_INVAL) &&
+                         (f.subclass != AST_IAX_COMMAND_VNAK))) 
                        send_command_immediate(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_ACK, fr.ts, NULL, 0,fr.seqno);
-               if (f.frametype == AST_FRAME_VOICE)
-                       iaxs[fr.callno]->voiceformat = f.subclass;
+               if (f.frametype == AST_FRAME_VOICE) {
+                       if (f.subclass != iaxs[fr.callno]->voiceformat) {
+                                       iaxs[fr.callno]->voiceformat = f.subclass;
+                                       ast_log(LOG_DEBUG, "Ooh, voice format changed to %d\n", f.subclass);
+                                       if (iaxs[fr.callno]->owner) {
+                                               int orignative;
+                                               ast_pthread_mutex_lock(&iaxs[fr.callno]->owner->lock);
+                                               orignative = iaxs[fr.callno]->owner->nativeformats;
+                                               iaxs[fr.callno]->owner->nativeformats = f.subclass;
+                                               if (iaxs[fr.callno]->owner->readformat)
+                                                       ast_set_read_format(iaxs[fr.callno]->owner, iaxs[fr.callno]->owner->readformat);
+                                               iaxs[fr.callno]->owner->nativeformats = orignative;
+                                               ast_pthread_mutex_unlock(&iaxs[fr.callno]->owner->lock);
+                                       }
+                       }
+               }
                if (f.frametype == AST_FRAME_IAX) {
                        /* Handle the IAX pseudo frame itself */
                        if (option_debug)
@@ -3238,11 +3351,15 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                if (check_access(fr.callno, &sin, f.data, f.datalen)) {
                                        /* They're not allowed on */
                                        send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No authority found", strlen("No authority found"), -1);
-                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s'\n", inet_ntoa(sin.sin_addr), f.data);
+                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s'\n", inet_ntoa(sin.sin_addr), (char *)f.data);
                                        break;
                                }
+                               ast_pthread_mutex_unlock(&iaxs_lock);
+                               /* This might re-enter the IAX code and need the lock */
+                               exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid);
+                               ast_pthread_mutex_lock(&iaxs_lock);
                                if (!strlen(iaxs[fr.callno]->secret) && !strlen(iaxs[fr.callno]->inkeys)) {
-                                       if (strcmp(iaxs[fr.callno]->exten, "TBD") && !ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid)) {
+                                       if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
                                                send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No such context/extension", strlen("No such context/extension"), -1);
                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", inet_ntoa(sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
                                        } else {
@@ -3317,7 +3434,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                if (f.data)
                                        ((char *)f.data)[f.datalen] = '\0';
                                if (iaxs[fr.callno]->owner)
-                                       ast_log(LOG_WARNING, "Call rejected by %s: %s\n", inet_ntoa(iaxs[fr.callno]->addr.sin_addr), f.data);
+                                       ast_log(LOG_WARNING, "Call rejected by %s: %s\n", inet_ntoa(iaxs[fr.callno]->addr.sin_addr), (char *)f.data);
                                iaxs[fr.callno]->error = EPERM;
                                iax_destroy(fr.callno);
                                break;
@@ -3364,24 +3481,53 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                ast_pthread_mutex_unlock(&dpcache_lock);
                                break;
                        case AST_IAX_COMMAND_PING:
+#ifdef BRIDGE_OPTIMIZATION
+                               if (iaxs[fr.callno]->bridgecallno > -1) {
+                                       /* If we're in a bridged call, just forward this */
+                                       forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PING, fr.ts, NULL, 0, -1);
+                               } else {
+                                       /* Send back a pong packet with the original timestamp */
+                                       send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
+                               }
+#else                          
                                /* Send back a pong packet with the original timestamp */
                                send_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
+#endif                         
                                break;
                        case AST_IAX_COMMAND_PONG:
+#ifdef BRIDGE_OPTIMIZATION
+                               if (iaxs[fr.callno]->bridgecallno > -1) {
+                                       /* Forward to the other side of the bridge */
+                                       forward_command(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
+                               } else {
+                                       /* Calculate ping time */
+                                       iaxs[fr.callno]->pingtime =  calc_timestamp(iaxs[fr.callno], 0) - fr.ts;
+                               }
+#else
+                               /* Calculate ping time */
                                iaxs[fr.callno]->pingtime =  calc_timestamp(iaxs[fr.callno], 0) - fr.ts;
+#endif                                 
                                break;
                        case AST_IAX_COMMAND_LAGRQ:
                        case AST_IAX_COMMAND_LAGRP:
-                               /* A little strange -- We have to actually go through the motions of
-                                  delivering the packet.  In the very last step, it will be properly
-                                  handled by do_deliver */
-                               snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno);
-                               f.src = src;
-                               f.mallocd = 0;
-                               f.offset = 0;
-                               fr.f = &f;
-                               f.timelen = 0;
-                               schedule_delivery(iaxfrdup2(&fr, 0), 1);
+#ifdef BRIDGE_OPTIMIZATION
+                               if (iaxs[fr.callno]->bridgecallno > -1) {
+                                       forward_command(iaxs[fr.callno], AST_FRAME_IAX, f.subclass, fr.ts, NULL, 0, -1);
+                               } else {
+#endif                         
+                                       /* A little strange -- We have to actually go through the motions of
+                                          delivering the packet.  In the very last step, it will be properly
+                                          handled by do_deliver */
+                                       snprintf(src, sizeof(src), "LAGRQ-IAX/%s/%d", inet_ntoa(sin.sin_addr),fr.callno);
+                                       f.src = src;
+                                       f.mallocd = 0;
+                                       f.offset = 0;
+                                       fr.f = &f;
+                                       f.timelen = 0;
+                                       schedule_delivery(iaxfrdup2(&fr, 0), 1);
+#ifdef BRIDGE_OPTIMIZATION
+                               }
+#endif                         
                                break;
                        case AST_IAX_COMMAND_AUTHREQ:
                                if (iaxs[fr.callno]->state & (IAX_STATE_STARTED | IAX_STATE_TBD)) {
@@ -3392,7 +3538,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                if (authenticate_reply(iaxs[fr.callno], &iaxs[fr.callno]->addr, (char *)f.data, iaxs[fr.callno]->secret, iaxs[fr.callno]->outkey)) {
                                        ast_log(LOG_WARNING, 
                                                "I don't know how to authenticate %s to %s\n", 
-                                               f.data, inet_ntoa(iaxs[fr.callno]->addr.sin_addr));
+                                               (char *)f.data, inet_ntoa(iaxs[fr.callno]->addr.sin_addr));
                                }
                                break;
                        case AST_IAX_COMMAND_AUTHREP:
@@ -3407,7 +3553,11 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                        send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No authority found", strlen("No authority found"), -1);
                                        break;
                                }
-                               if (strcmp(iaxs[fr.callno]->exten, "TBD") && !ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid)) {
+                               ast_pthread_mutex_unlock(&iaxs_lock);
+                               /* This might re-enter the IAX code and need the lock */
+                               exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->callerid);
+                               ast_pthread_mutex_lock(&iaxs_lock);
+                               if (strcmp(iaxs[fr.callno]->exten, "TBD") && !exists) {
                                        send_command_final(iaxs[fr.callno], AST_FRAME_IAX, AST_IAX_COMMAND_REJECT, 0, "No such context/extension", strlen("No such context/extension"), -1);
                                        ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", inet_ntoa(sin.sin_addr), iaxs[fr.callno]->exten, iaxs[fr.callno]->context);
                                } else {
@@ -3477,8 +3627,9 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                        ast_log(LOG_DEBUG, "Destroying call %d\n", fr.callno);
                                break;
                        case AST_IAX_COMMAND_VNAK:
+                               ast_log(LOG_DEBUG, "Sending VNAK\n");
                                /* Force retransmission */
-                               ast_log(LOG_NOTICE, "Need to implement VNAK\n");
+                               vnak_retransmit(fr.callno, fr.seqno);
                                break;
                        case AST_IAX_COMMAND_REGREQ:
                                if (f.data) 
@@ -3505,7 +3656,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                                if (f.data)
                                        ((char *)f.data)[f.datalen] = '\0';
                                if (iaxs[fr.callno]->reg) {
-                                       ast_log(LOG_NOTICE, "Registration of '%s' rejected: %s\n", iaxs[fr.callno]->reg->username, f.data);
+                                       ast_log(LOG_NOTICE, "Registration of '%s' rejected: %s\n", iaxs[fr.callno]->reg->username, (char *)f.data);
                                        iaxs[fr.callno]->reg->regstate = REG_STATE_REJECTED;
                                }
                                iax_destroy(fr.callno);
@@ -3593,6 +3744,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        f.subclass = iaxs[fr.callno]->voiceformat;
                else {
                        ast_log(LOG_WARNING, "Received mini frame before first full voice frame\n ");
+                       iax_vnak(fr.callno);
                        ast_pthread_mutex_unlock(&iaxs_lock);
                        return 1;
                }
@@ -3632,7 +3784,15 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        ast_log(LOG_DEBUG, "Received out of order packet... (type=%d, subclass %d, ts = %d, last = %d)\n", f.frametype, f.subclass, fr.ts, iaxs[fr.callno]->last);
                fr.outoforder = -1;
        }
+#ifdef BRIDGE_OPTIMIZATION
+       if (iaxs[fr.callno]->bridgecallno > -1) {
+               forward_delivery(&fr);
+       } else {
+               schedule_delivery(iaxfrdup2(&fr, 0), 1);
+       }
+#else
        schedule_delivery(iaxfrdup2(&fr, 0), 1);
+#endif
        /* Always run again */
        ast_pthread_mutex_unlock(&iaxs_lock);
        return 1;
@@ -3666,16 +3826,6 @@ static int iax_do_register(struct iax_registry *reg)
        return 0;
 }
 
-static void free_ha(struct iax_ha *ha)
-{
-       struct iax_ha *hal;
-       while(ha) {
-               hal = ha;
-               ha = ha->next;
-               free(hal);
-       }
-}
-
 static void free_context(struct iax_context *con)
 {
        struct iax_context *conl;
@@ -3690,6 +3840,7 @@ static struct ast_channel *iax_request(char *type, int format, void *data)
 {
        int callno;
        int res;
+       int sendani;
        int fmt, native;
        struct sockaddr_in sin;
        char s[256];
@@ -3703,7 +3854,7 @@ static struct ast_channel *iax_request(char *type, int format, void *data)
        if (!st)
                st = s;
        /* Populate our address from the given */
-       if (create_addr(&sin, &capability, st)) {
+       if (create_addr(&sin, &capability, &sendani, st, NULL)) {
                return NULL;
        }
        ast_pthread_mutex_lock(&iaxs_lock);
@@ -3712,6 +3863,8 @@ static struct ast_channel *iax_request(char *type, int format, void *data)
                ast_log(LOG_WARNING, "Unable to create call\n");
                return NULL;
        }
+       /* Keep track of sendani flag */
+       iaxs[callno]->sendani = sendani;
        c = ast_iax_new(iaxs[callno], AST_STATE_DOWN, capability);
        if (c) {
                /* Choose a format we can live with */
@@ -3791,6 +3944,7 @@ static void *network_thread(void *ignore)
                        ast_sched_runq(sched);
                }
        }
+       return NULL;
 }
 
 static int start_network_thread()
@@ -3808,54 +3962,10 @@ static struct iax_context *build_context(char *context)
        return con;
 }
 
-static struct iax_ha *build_ha(char *sense, char *stuff)
-{
-       struct iax_ha *ha = malloc(sizeof(struct iax_ha));
-       char *nm;
-       if (ha) {
-               strtok(stuff, "/");
-               nm = strtok(NULL, "/");
-               if (!nm)
-                       nm = "255.255.255.255";
-               if (!inet_aton(stuff, &ha->netaddr)) {
-                       ast_log(LOG_WARNING, "%s not a valid IP\n", stuff);
-                       free(ha);
-                       return NULL;
-               }
-               if (!inet_aton(nm, &ha->netmask)) {
-                       ast_log(LOG_WARNING, "%s not a valid netmask\n", nm);
-                       free(ha);
-                       return NULL;
-               }
-               ha->netaddr.s_addr &= ha->netmask.s_addr;
-               if (!strncasecmp(sense, "p", 1)) {
-                       ha->sense = IAX_SENSE_ALLOW;
-               } else {
-                       ha->sense = IAX_SENSE_DENY;
-               }
-               ha->next = NULL;
-       }
-       return ha;
-}
-
-static int get_ip(struct sockaddr_in *sin, char *value)
-{
-       struct hostent *hp;
-       hp = gethostbyname(value);
-       if (hp) {
-               memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
-       } else {
-               ast_log(LOG_WARNING, "Unable to lookup '%s'\n", value);
-               return -1;
-       }
-       return 0;
-}
-
 static struct iax_peer *build_peer(char *name, struct ast_variable *v)
 {
        struct iax_peer *peer;
        struct iax_peer *prev;
-       struct iax_ha *ha, *hal = NULL;
        int maskfound=0;
        int format;
        int found=0;
@@ -3916,7 +4026,7 @@ static struct iax_peer *build_peer(char *name, struct ast_variable *v)
                                                ast_sched_del(sched, peer->expire);
                                        peer->expire = -1;
                                        peer->dynamic = 0;
-                                       if (get_ip(&peer->addr, v->value)) {
+                                       if (ast_get_ip(&peer->addr, v->value)) {
                                                free(peer);
                                                return NULL;
                                        }
@@ -3924,23 +4034,19 @@ static struct iax_peer *build_peer(char *name, struct ast_variable *v)
                                if (!maskfound)
                                        inet_aton("255.255.255.255", &peer->mask);
                        } else if (!strcasecmp(v->name, "defaultip")) {
-                               if (get_ip(&peer->defaddr, v->value)) {
+                               if (ast_get_ip(&peer->defaddr, v->value)) {
                                        free(peer);
                                        return NULL;
                                }
                        } else if (!strcasecmp(v->name, "permit") ||
                                           !strcasecmp(v->name, "deny")) {
-                               ha = build_ha(v->name, v->value);
-                               if (ha) {
-                                       if (hal)
-                                               hal->next = ha;
-                                       else
-                                               peer->ha = ha;
-                                       hal = ha;
-                               }
+                               peer->ha = ast_append_ha(v->name, v->value, peer->ha);
                        } else if (!strcasecmp(v->name, "mask")) {
                                maskfound++;
                                inet_aton(v->value, &peer->mask);
+                       } else if (!strcasecmp(v->name, "context")) {
+                               if (!strlen(peer->context))
+                                       strncpy(peer->context, v->value, sizeof(peer->context) - 1);
                        } else if (!strcasecmp(v->name, "port")) {
                                if (peer->dynamic)
                                        peer->defaddr.sin_port = htons(atoi(v->value));
@@ -3963,6 +4069,8 @@ static struct iax_peer *build_peer(char *name, struct ast_variable *v)
                        } else if (!strcasecmp(v->name, "callerid")) {
                                strncpy(peer->callerid, v->value, sizeof(peer->callerid)-1);
                                peer->hascallerid=1;
+                       } else if (!strcasecmp(v->name, "sendani")) {
+                               peer->sendani = ast_true(v->value);
                        } else if (!strcasecmp(v->name, "inkeys")) {
                                strncpy(peer->inkeys, v->value, sizeof(peer->inkeys));
                        } else if (!strcasecmp(v->name, "outkey")) {
@@ -3982,7 +4090,6 @@ static struct iax_user *build_user(char *name, struct ast_variable *v)
 {
        struct iax_user *user;
        struct iax_context *con, *conl = NULL;
-       struct iax_ha *ha, *hal = NULL;
        int format;
        user = (struct iax_user *)malloc(sizeof(struct iax_user));
        if (user) {
@@ -4000,14 +4107,7 @@ static struct iax_user *build_user(char *name, struct ast_variable *v)
                                }
                        } else if (!strcasecmp(v->name, "permit") ||
                                           !strcasecmp(v->name, "deny")) {
-                               ha = build_ha(v->name, v->value);
-                               if (ha) {
-                                       if (hal)
-                                               hal->next = ha;
-                                       else
-                                               user->ha = ha;
-                                       hal = ha;
-                               }
+                               user->ha = ast_append_ha(v->name, v->value, user->ha);
                        } else if (!strcasecmp(v->name, "auth")) {
                                strncpy(user->methods, v->value, sizeof(user->methods)-1);
                        } else if (!strcasecmp(v->name, "secret")) {
@@ -4052,7 +4152,7 @@ void delete_users(void){
        /* Delete all users */
        ast_pthread_mutex_lock(&userl.lock);
        for (user=userl.users;user;) {
-               free_ha(user->ha);
+               ast_free_ha(user->ha);
                free_context(user->contexts);
                userlast = user;
                user=user->next;
@@ -4293,7 +4393,7 @@ static int cache_get_callno(char *data)
                host = st;
        }
        /* Populate our address from the given */
-       if (create_addr(&sin, NULL, host)) {
+       if (create_addr(&sin, NULL, NULL, host, NULL)) {
                return -1;
        }
        ast_log(LOG_DEBUG, "host: %s, user: %s, password: %s, context: %s\n", host, username, password, context);
@@ -4593,8 +4693,8 @@ int load_module(void)
                return -1;
        }
 
-       pthread_mutex_init(&iaxq.lock, NULL);
-       pthread_mutex_init(&userl.lock, NULL);
+       ast_pthread_mutex_init(&iaxq.lock);
+       ast_pthread_mutex_init(&userl.lock);
 
        ast_cli_register(&cli_show_users);
        ast_cli_register(&cli_show_channels);