res_pjsip: Add option to force G.726 to be treated as AAL2 packed.
[asterisk/asterisk.git] / channels / chan_iax2.c
index 0f5c8fc..da6bec7 100644 (file)
@@ -27,7 +27,7 @@
  * \arg \ref Config_iax
  *
  * \ingroup channel_drivers
- * 
+ *
  * \todo Implement musicclass settings for IAX2 devices
  */
 
  * \verbinclude iax.conf.sample
  */
 
+/*!
+ * \todo XXX The IAX2 channel driver needs its native bridge
+ * code converted to the new bridge technology scheme.
+ *
+ * \note The chan_dahdi native bridge code can be used as an
+ * example.  It also appears that chan_iax2 also has a native
+ * transfer check like chan_dahdi to eliminate tromboned calls.
+ *
+ * \note The existing native bridge code is marked with the
+ * IAX2_NATIVE_BRIDGING conditional.
+ */
+
 /*** MODULEINFO
        <use type="external">crypto</use>
        <support_level>core</support_level>
@@ -46,7 +58,7 @@
 
 #include "asterisk.h"
 
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+ASTERISK_REGISTER_FILE()
 
 #include <sys/mman.h>
 #include <dirent.h>
@@ -67,7 +79,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/paths.h"
 
 #include "asterisk/lock.h"
-#include "asterisk/frame.h" 
+#include "asterisk/frame.h"
 #include "asterisk/channel.h"
 #include "asterisk/module.h"
 #include "asterisk/pbx.h"
@@ -93,21 +105,28 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/netsock.h"
 #include "asterisk/stringfields.h"
 #include "asterisk/linkedlists.h"
-#include "asterisk/event.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/timing.h"
 #include "asterisk/taskprocessor.h"
 #include "asterisk/test.h"
 #include "asterisk/data.h"
-#include "asterisk/netsock2.h"
 #include "asterisk/security_events.h"
 #include "asterisk/stasis_endpoints.h"
-#include "asterisk/bridging.h"
+#include "asterisk/bridge.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_system.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/format_cache.h"
+#include "asterisk/format_compatibility.h"
+#include "asterisk/format_cap.h"
 
 #include "iax2/include/iax2.h"
 #include "iax2/include/firmware.h"
 #include "iax2/include/parser.h"
 #include "iax2/include/provision.h"
+#include "iax2/include/codec_pref.h"
+#include "iax2/include/format_compatibility.h"
+
 #include "jitterbuf.h"
 
 /*** DOCUMENTATION
@@ -266,7 +285,7 @@ static int nochecksums = 0;
 /* Sample over last 100 units to determine historic jitter */
 #define GAMMA (0.01)
 
-static struct ast_codec_pref prefs;
+static struct iax2_codec_pref prefs_global;
 
 static const char tdesc[] = "Inter Asterisk eXchange Driver (Ver 2)";
 
@@ -334,22 +353,22 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 #define IAX_CAPABILITY_FULLBANDWIDTH   0xFFFF
 /* T1, maybe ISDN */
 #define IAX_CAPABILITY_MEDBANDWIDTH (IAX_CAPABILITY_FULLBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR) &      \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SLINEAR16) &    \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN7) &       \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_SIREN14) &      \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G719) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ULAW) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ALAW) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G722))
+                     ~AST_FORMAT_SLIN &      \
+                     ~AST_FORMAT_SLIN16 &    \
+                     ~AST_FORMAT_SIREN7 &       \
+                     ~AST_FORMAT_SIREN14 &      \
+                     ~AST_FORMAT_G719 &         \
+                     ~AST_FORMAT_ULAW &         \
+                     ~AST_FORMAT_ALAW &         \
+                     ~AST_FORMAT_G722)
 /* A modem */
 #define IAX_CAPABILITY_LOWBANDWIDTH (IAX_CAPABILITY_MEDBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726) &         \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G726_AAL2) &    \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_ADPCM))
+                     ~AST_FORMAT_G726 &         \
+                     ~AST_FORMAT_G726_AAL2 &    \
+                     ~AST_FORMAT_ADPCM)
 
 #define IAX_CAPABILITY_LOWFREE      (IAX_CAPABILITY_LOWBANDWIDTH & \
-                     ~ast_format_id_to_old_bitfield(AST_FORMAT_G723_1))
+                     ~AST_FORMAT_G723)
 
 
 #define DEFAULT_MAXMS          2000            /* Must be faster than 2 seconds by default */
@@ -368,7 +387,7 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
                        break; \
                \
                for (idx = 0; idx < 16; idx++) \
-                       sprintf(digest + (idx << 1), "%2.2x", (unsigned char) key[idx]); \
+                       sprintf(digest + (idx << 1), "%02hhx", (unsigned char) key[idx]); \
                \
                ast_log(LOG_NOTICE, msg " IAX_COMMAND_RTKEY to rotate key to '%s'\n", digest); \
        } while(0)
@@ -376,8 +395,6 @@ static int (*iax2_regfunk)(const char *username, int onoff) = NULL;
 static struct io_context *io;
 static struct ast_sched_context *sched;
 
-#define DONT_RESCHEDULE -2
-
 static iax2_format iax2_capability = IAX_CAPABILITY_FULLBANDWIDTH;
 
 static int iaxdebug = 0;
@@ -416,38 +433,37 @@ struct iax2_context {
 };
 
 
-#define        IAX_HASCALLERID         (uint64_t)(1 << 0)    /*!< CallerID has been specified */
-#define IAX_DELME               (uint64_t)(1 << 1)    /*!< Needs to be deleted */
-#define IAX_TEMPONLY            (uint64_t)(1 << 2)    /*!< Temporary (realtime) */
-#define IAX_TRUNK               (uint64_t)(1 << 3)    /*!< Treat as a trunk */
-#define IAX_NOTRANSFER          (uint64_t)(1 << 4)    /*!< Don't native bridge */
-#define IAX_USEJITTERBUF        (uint64_t)(1 << 5)    /*!< Use jitter buffer */
-#define IAX_DYNAMIC             (uint64_t)(1 << 6)    /*!< dynamic peer */
-#define IAX_SENDANI             (uint64_t)(1 << 7)    /*!< Send ANI along with CallerID */
-#define IAX_RTSAVE_SYSNAME      (uint64_t)(1 << 8)    /*!< Save Systname on Realtime Updates */
-#define IAX_ALREADYGONE         (uint64_t)(1 << 9)    /*!< Already disconnected */
-#define IAX_PROVISION           (uint64_t)(1 << 10)   /*!< This is a provisioning request */
-#define IAX_QUELCH              (uint64_t)(1 << 11)   /*!< Whether or not we quelch audio */
-#define IAX_ENCRYPTED           (uint64_t)(1 << 12)   /*!< Whether we should assume encrypted tx/rx */
-#define IAX_KEYPOPULATED        (uint64_t)(1 << 13)   /*!< Whether we have a key populated */
-#define IAX_CODEC_USER_FIRST    (uint64_t)(1 << 14)   /*!< are we willing to let the other guy choose the codec? */
-#define IAX_CODEC_NOPREFS       (uint64_t)(1 << 15)   /*!< Force old behaviour by turning off prefs */
-#define IAX_CODEC_NOCAP         (uint64_t)(1 << 16)   /*!< only consider requested format and ignore capabilities*/
-#define IAX_RTCACHEFRIENDS      (uint64_t)(1 << 17)   /*!< let realtime stay till your reload */
-#define IAX_RTUPDATE            (uint64_t)(1 << 18)   /*!< Send a realtime update */
-#define IAX_RTAUTOCLEAR         (uint64_t)(1 << 19)   /*!< erase me on expire */
-#define IAX_FORCEJITTERBUF      (uint64_t)(1 << 20)   /*!< Force jitterbuffer, even when bridged to a channel that can take jitter */
-#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1 << 21)   /*!< When using realtime, ignore registration expiration */
-#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1 << 22)   /*!< Send trunk timestamps */
-#define IAX_TRANSFERMEDIA       (uint64_t)(1 << 23)   /*!< When doing IAX2 transfers, transfer media only */
-#define IAX_MAXAUTHREQ          (uint64_t)(1 << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
-#define IAX_DELAYPBXSTART       (uint64_t)(1 << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
-#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1 << 26)   /*!< Allow the FWDOWNL command? */
-#define IAX_IMMEDIATE           (uint64_t)(1 << 27)   /*!< Allow immediate off-hook to extension s */
-#define IAX_SENDCONNECTEDLINE   (uint64_t)(1 << 28)   /*!< Allow sending of connected line updates */
-#define IAX_RECVCONNECTEDLINE   (uint64_t)(1 << 29)   /*!< Allow receiving of connected line updates */
-#define IAX_FORCE_ENCRYPT       (uint64_t)(1 << 30)   /*!< Forces call encryption, if encryption not possible hangup */
-#define IAX_SHRINKCALLERID      (uint64_t)(1 << 31)   /*!< Turn on and off caller id shrinking */
+#define IAX_HASCALLERID         (uint64_t)(1LLU << 0)    /*!< CallerID has been specified */
+#define IAX_DELME               (uint64_t)(1LLU << 1)    /*!< Needs to be deleted */
+#define IAX_TEMPONLY            (uint64_t)(1LLU << 2)    /*!< Temporary (realtime) */
+#define IAX_TRUNK               (uint64_t)(1LLU << 3)    /*!< Treat as a trunk */
+#define IAX_NOTRANSFER          (uint64_t)(1LLU << 4)    /*!< Don't native bridge */
+#define IAX_USEJITTERBUF        (uint64_t)(1LLU << 5)    /*!< Use jitter buffer */
+#define IAX_DYNAMIC             (uint64_t)(1LLU << 6)    /*!< dynamic peer */
+#define IAX_SENDANI             (uint64_t)(1LLU << 7)    /*!< Send ANI along with CallerID */
+#define IAX_RTSAVE_SYSNAME      (uint64_t)(1LLU << 8)    /*!< Save Systname on Realtime Updates */
+#define IAX_ALREADYGONE         (uint64_t)(1LLU << 9)    /*!< Already disconnected */
+#define IAX_PROVISION           (uint64_t)(1LLU << 10)   /*!< This is a provisioning request */
+#define IAX_QUELCH              (uint64_t)(1LLU << 11)   /*!< Whether or not we quelch audio */
+#define IAX_ENCRYPTED           (uint64_t)(1LLU << 12)   /*!< Whether we should assume encrypted tx/rx */
+#define IAX_KEYPOPULATED        (uint64_t)(1LLU << 13)   /*!< Whether we have a key populated */
+#define IAX_CODEC_USER_FIRST    (uint64_t)(1LLU << 14)   /*!< are we willing to let the other guy choose the codec? */
+#define IAX_CODEC_NOPREFS       (uint64_t)(1LLU << 15)   /*!< Force old behaviour by turning off prefs */
+#define IAX_CODEC_NOCAP         (uint64_t)(1LLU << 16)   /*!< only consider requested format and ignore capabilities*/
+#define IAX_RTCACHEFRIENDS      (uint64_t)(1LLU << 17)   /*!< let realtime stay till your reload */
+#define IAX_RTUPDATE            (uint64_t)(1LLU << 18)   /*!< Send a realtime update */
+#define IAX_RTAUTOCLEAR         (uint64_t)(1LLU << 19)   /*!< erase me on expire */
+#define IAX_RTIGNOREREGEXPIRE   (uint64_t)(1LLU << 21)   /*!< When using realtime, ignore registration expiration */
+#define IAX_TRUNKTIMESTAMPS     (uint64_t)(1LLU << 22)   /*!< Send trunk timestamps */
+#define IAX_TRANSFERMEDIA       (uint64_t)(1LLU << 23)   /*!< When doing IAX2 transfers, transfer media only */
+#define IAX_MAXAUTHREQ          (uint64_t)(1LLU << 24)   /*!< Maximum outstanding AUTHREQ restriction is in place */
+#define IAX_DELAYPBXSTART       (uint64_t)(1LLU << 25)   /*!< Don't start a PBX on the channel until the peer sends us a response, so that we've achieved a three-way handshake with them before sending voice or anything else */
+#define IAX_ALLOWFWDOWNLOAD     (uint64_t)(1LLU << 26)   /*!< Allow the FWDOWNL command? */
+#define IAX_IMMEDIATE           (uint64_t)(1LLU << 27)   /*!< Allow immediate off-hook to extension s */
+#define IAX_SENDCONNECTEDLINE   (uint64_t)(1LLU << 28)   /*!< Allow sending of connected line updates */
+#define IAX_RECVCONNECTEDLINE   (uint64_t)(1LLU << 29)   /*!< Allow receiving of connected line updates */
+#define IAX_FORCE_ENCRYPT       (uint64_t)(1LLU << 30)   /*!< Forces call encryption, if encryption not possible hangup */
+#define IAX_SHRINKCALLERID      (uint64_t)(1LLU << 31)   /*!< Turn on and off caller id shrinking */
 static int global_rtautoclear = 120;
 
 static int reload_config(int forced_reload);
@@ -490,7 +506,7 @@ struct iax2_user {
        iax2_format capability;
        int maxauthreq; /*!< Maximum allowed outstanding AUTHREQs */
        int curauthreq; /*!< Current number of outstanding AUTHREQs */
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        struct ast_acl_list *acl;
        struct iax2_context *contexts;
        struct ast_variable *vars;
@@ -519,17 +535,17 @@ struct iax2_peer {
                AST_STRING_FIELD(zonetag);              /*!< Time Zone */
                AST_STRING_FIELD(parkinglot);   /*!< Default parkinglot for device */
        );
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        struct ast_dnsmgr_entry *dnsmgr;                /*!< DNS refresh manager */
        struct ast_sockaddr addr;
        int formats;
        int sockfd;                                     /*!< Socket to use for transmission */
-       struct in_addr mask;
+       struct ast_sockaddr mask;
        int adsi;
        uint64_t flags;
 
        /* Dynamic Registration fields */
-       struct sockaddr_in defaddr;                     /*!< Default address if there is one */
+       struct ast_sockaddr defaddr;                    /*!< Default address if there is one */
        int authmethods;                                /*!< Authentication methods (IAX_AUTH_*) */
        int encmethods;                                 /*!< Encryption methods (IAX_ENCRYPT_*) */
 
@@ -562,7 +578,7 @@ struct iax2_peer {
 struct iax2_trunk_peer {
        ast_mutex_t lock;
        int sockfd;
-       struct sockaddr_in addr;
+       struct ast_sockaddr addr;
        struct timeval txtrunktime;             /*!< Transmit trunktime */
        struct timeval rxtrunktime;             /*!< Receive trunktime */
        struct timeval lasttxtime;              /*!< Last transmitted trunktime */
@@ -613,9 +629,11 @@ struct iax2_registry {
        enum iax_reg_state regstate;
        int messages;                           /*!< Message count, low 8 bits = new, high 8 bits = old */
        int callno;                             /*!< Associated call number if applicable */
-       struct sockaddr_in us;                  /*!< Who the server thinks we are */
+       struct ast_sockaddr us;                 /*!< Who the server thinks we are */
        struct ast_dnsmgr_entry *dnsmgr;        /*!< DNS refresh manager */
        AST_LIST_ENTRY(iax2_registry) entry;
+       int port;
+       char hostname[];
 };
 
 static AST_LIST_HEAD_STATIC(registrations, iax2_registry);
@@ -663,7 +681,7 @@ struct chan_iax2_pvt {
        /*! Socket to send/receive on for this call */
        int sockfd;
        /*! ast_callid bound to dialog */
-       struct ast_callid *callid;
+       ast_callid callid;
        /*! Last received voice format */
        iax2_format voiceformat;
        /*! Last received video format */
@@ -693,11 +711,11 @@ struct chan_iax2_pvt {
        /*! Max time for initial response */
        int maxtime;
        /*! Peer Address */
-       struct sockaddr_in addr;
+       struct ast_sockaddr addr;
        /*! Actual used codec preferences */
-       struct ast_codec_pref prefs;
+       struct iax2_codec_pref prefs;
        /*! Requested codec preferences */
-       struct ast_codec_pref rprefs;
+       struct iax2_codec_pref rprefs;
        /*! Our call number */
        unsigned short callno;
        /*! Our callno_entry entry */
@@ -791,7 +809,7 @@ struct chan_iax2_pvt {
        ast_aes_decrypt_key mydcx;
        /*! Decryption AES-128 Key used to decrypt peer frames */
        ast_aes_decrypt_key dcx;
-       /*! scheduler id associated with iax_key_rotate 
+       /*! scheduler id associated with iax_key_rotate
         * for encrypted calls*/
        int keyrotateid;
        /*! 32 bytes of semi-random data */
@@ -809,7 +827,7 @@ struct chan_iax2_pvt {
        /*! Transfer identifier */
        int transferid;
        /*! Who we are IAX transferring to */
-       struct sockaddr_in transfer;
+       struct ast_sockaddr transfer;
        /*! What's the new call number for the transfer */
        unsigned short transfercallno;
        /*! Transfer encrypt AES-128 Key */
@@ -818,7 +836,7 @@ struct chan_iax2_pvt {
        /*! Status of knowledge of peer ADSI capability */
        int peeradsicpe;
 
-       /*! Who we are bridged to */
+       /*! Callno of native bridge peer. (Valid if nonzero) */
        unsigned short bridgecallno;
 
        int pingid;                     /*!< Transmit PING request */
@@ -844,6 +862,8 @@ struct chan_iax2_pvt {
        int frames_dropped;
        /*! received frame count: (just for stats) */
        int frames_received;
+       /*! Destroying this call initiated. */
+       int destroy_initiated;
        /*! num bytes used for calltoken ie, even an empty ie should contain 2 */
        unsigned char calltoken_ie_len;
        /*! hold all signaling frames from the pbx thread until we have a destination callno */
@@ -898,7 +918,7 @@ static struct ast_taskprocessor *transmit_processor;
 
 static int randomcalltokendata;
 
-static const time_t MAX_CALLTOKEN_DELAY = 10;
+static time_t max_calltoken_delay = 10;
 
 /*!
  * This module will get much higher performance when doing a lot of
@@ -941,7 +961,7 @@ static uint16_t total_nonval_callno_used = 0;
  *  consumed by a single ip address */
 struct peercnt {
        /*! ip address consuming call numbers */
-       unsigned long addr;
+       struct ast_sockaddr addr;
        /*! Number of call numbers currently used by this ip address */
        uint16_t cur;
        /*! Max call numbers allowed for this ip address */
@@ -995,8 +1015,8 @@ struct iax2_dpcache {
 static AST_LIST_HEAD_STATIC(dpcache, iax2_dpcache);
 
 static void reg_source_db(struct iax2_peer *p);
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin);
-static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin);
+static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr);
+static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr);
 
 static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt);
 static char *complete_iax2_peers(const char *line, const char *word, int pos, int state, uint64_t flags);
@@ -1030,12 +1050,12 @@ struct iax2_thread {
 #endif
 #ifdef DEBUG_SCHED_MULTITHREAD
        char curfunc[80];
-#endif 
+#endif
        int actions;
        pthread_t threadid;
        int threadnum;
-       struct sockaddr_in iosin;
-       unsigned char readbuf[4096]; 
+       struct ast_sockaddr ioaddr;
+       unsigned char readbuf[4096];
        unsigned char *buf;
        ssize_t buf_len;
        size_t buf_size;
@@ -1051,7 +1071,7 @@ struct iax2_thread {
          frames for that callno to other threads */
        struct {
                unsigned short callno;
-               struct sockaddr_in sin;
+               struct ast_sockaddr addr;
                unsigned char type;
                unsigned char csub;
        } ffinfo;
@@ -1087,30 +1107,22 @@ static void signal_condition(ast_mutex_t *lock, ast_cond_t *cond)
  */
 static struct chan_iax2_pvt *iaxs[IAX_MAX_CALLS];
 
-static struct ast_callid *iax_pvt_callid_get(int callno)
+static ast_callid iax_pvt_callid_get(int callno)
 {
-       if (iaxs[callno]->callid) {
-               return ast_callid_ref(iaxs[callno]->callid);
-       }
-       return NULL;
+       return iaxs[callno]->callid;
 }
 
-static void iax_pvt_callid_set(int callno, struct ast_callid *callid)
+static void iax_pvt_callid_set(int callno, ast_callid callid)
 {
-       if (iaxs[callno]->callid) {
-               ast_callid_unref(iaxs[callno]->callid);
-       }
-       ast_callid_ref(callid);
        iaxs[callno]->callid = callid;
 }
 
 static void iax_pvt_callid_new(int callno)
 {
-       struct ast_callid *callid = ast_create_callid();
+       ast_callid callid = ast_create_callid();
        char buffer[AST_CALLID_BUFFER_LENGTH];
        ast_callid_strnprint(buffer, sizeof(buffer), callid);
        iax_pvt_callid_set(callno, callid);
-       ast_callid_unref(callid);
 }
 
 /*!
@@ -1135,8 +1147,8 @@ static ast_mutex_t iaxsl[ARRAY_LEN(iaxs)];
 
 /*!
  *  * \brief Another container of iax2_pvt structures
- *  
- *  Active IAX2 pvt stucts used during transfering a call are stored here.  
+ *
+ *  Active IAX2 pvt stucts used during transfering a call are stored here.
  */
 static struct ao2_container *iax_transfercallno_pvts;
 
@@ -1145,20 +1157,21 @@ static struct ao2_container *iax_transfercallno_pvts;
 #define TRUNK_CALL_START       (IAX_MAX_CALLS / 2)
 
 /* Debug routines... */
-static struct sockaddr_in debugaddr;
+static struct ast_sockaddr debugaddr;
 
-static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct sockaddr_in *sin, int datalen)
+static void iax_outputframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, struct ast_sockaddr *addr, int datalen)
 {
        if (iaxdebug ||
-           (sin && debugaddr.sin_addr.s_addr && 
-            (!ntohs(debugaddr.sin_port) ||
-             debugaddr.sin_port == sin->sin_port) &&
-            debugaddr.sin_addr.s_addr == sin->sin_addr.s_addr)) {
+           (addr && !ast_sockaddr_isnull(&debugaddr) &&
+               (!ast_sockaddr_port(&debugaddr) ||
+                 ast_sockaddr_port(&debugaddr) == ast_sockaddr_port(addr)) &&
+                 !ast_sockaddr_cmp_addr(&debugaddr, addr))) {
+
                if (iaxdebug) {
-                       iax_showframe(f, fhi, rx, sin, datalen);
+                       iax_showframe(f, fhi, rx, addr, datalen);
                } else {
                        iaxdebug = 1;
-                       iax_showframe(f, fhi, rx, sin, datalen);
+                       iax_showframe(f, fhi, rx, addr, datalen);
                        iaxdebug = 0;
                }
        }
@@ -1211,7 +1224,6 @@ static void __attribute__((format(printf, 1, 2))) jb_debug_output(const char *fm
        ast_verbose("%s", buf);
 }
 
-static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
 static int expire_registry(const void *data);
 static int iax2_answer(struct ast_channel *c);
 static int iax2_call(struct ast_channel *c, const char *dest, int timeout);
@@ -1223,7 +1235,7 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
 static int iax2_hangup(struct ast_channel *c);
 static int iax2_indicate(struct ast_channel *c, int condition, const void *data, size_t datalen);
 static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-static int iax2_provision(struct sockaddr_in *end, int sockfd, const char *dest, const char *template, int force);
+static int iax2_provision(struct ast_sockaddr *end, int sockfd, const char *dest, const char *template, int force);
 static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
 static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen);
 static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img);
@@ -1240,7 +1252,7 @@ static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, c
 static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_locked(unsigned short callno, char, int, unsigned int, const unsigned char *, int, int);
 static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const unsigned char *, int);
-static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
+static struct ast_channel *iax2_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
 static struct ast_frame *iax2_read(struct ast_channel *c);
 static struct iax2_peer *build_peer(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
 static struct iax2_user *build_user(const char *name, struct ast_variable *v, struct ast_variable *alt, int temponly);
@@ -1257,11 +1269,10 @@ static void build_ecx_key(const unsigned char *digest, struct chan_iax2_pvt *pvt
 static void build_rand_pad(unsigned char *buf, ssize_t len);
 static int get_unused_callno(enum callno_type type, int validated, callno_entry *entry);
 static int replace_callno(const void *obj);
-static void sched_delay_remove(struct sockaddr_in *sin, callno_entry entry);
-static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message);
-static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *message);
+static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry);
+static void network_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
+static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message);
 
-/* BUGBUG The IAX2 channel driver needs its own native bridge technology. */
 static struct ast_channel_tech iax2_tech = {
        .type = "IAX2",
        .description = tdesc,
@@ -1282,7 +1293,6 @@ static struct ast_channel_tech iax2_tech = {
        .indicate = iax2_indicate,
        .setoption = iax2_setoption,
        .queryoption = iax2_queryoption,
-       .bridge = iax2_bridge,
        .transfer = iax2_transfer,
        .fixup = iax2_fixup,
        .func_channel_read = acf_channel_read,
@@ -1321,11 +1331,103 @@ static void iax2_lock_owner(int callno)
        }
 }
 
-static void mwi_event_cb(void *userdata, struct stasis_subscription *sub, struct stasis_topic *topic, struct stasis_message *msg)
+/*!
+ * \internal
+ * \brief Check if a control subtype is allowed on the wire.
+ *
+ * \param subtype Control frame subtype to check if allowed to/from the wire.
+ *
+ * \retval non-zero if allowed.
+ */
+static int iax2_is_control_frame_allowed(int subtype)
 {
-       /* The MWI subscriptions exist just so the core knows we care about those
-        * mailboxes.  However, we just grab the events out of the cache when it
-        * is time to send MWI, since it is only sent with a REGACK. */
+       enum ast_control_frame_type control = subtype;
+       int is_allowed;
+
+       /*
+        * Note: If we compare the enumeration type, which does not have any
+        * negative constants, the compiler may optimize this code away.
+        * Therefore, we must perform an integer comparison here.
+        */
+       if (subtype == -1) {
+               return -1;
+       }
+
+       /* Default to not allowing control frames to pass. */
+       is_allowed = 0;
+
+       /*
+        * The switch default is not present in order to take advantage
+        * of the compiler complaining of a missing enum case.
+        */
+       switch (control) {
+       /*
+        * These control frames make sense to send/receive across the link.
+        */
+       case AST_CONTROL_HANGUP:
+       case AST_CONTROL_RING:
+       case AST_CONTROL_RINGING:
+       case AST_CONTROL_ANSWER:
+       case AST_CONTROL_BUSY:
+       case AST_CONTROL_TAKEOFFHOOK:
+       case AST_CONTROL_OFFHOOK:
+       case AST_CONTROL_CONGESTION:
+       case AST_CONTROL_FLASH:
+       case AST_CONTROL_WINK:
+       case AST_CONTROL_OPTION:
+       case AST_CONTROL_RADIO_KEY:
+       case AST_CONTROL_RADIO_UNKEY:
+       case AST_CONTROL_PROGRESS:
+       case AST_CONTROL_PROCEEDING:
+       case AST_CONTROL_HOLD:
+       case AST_CONTROL_UNHOLD:
+       case AST_CONTROL_VIDUPDATE:
+       case AST_CONTROL_CONNECTED_LINE:
+       case AST_CONTROL_REDIRECTING:
+       case AST_CONTROL_T38_PARAMETERS:
+       case AST_CONTROL_AOC:
+       case AST_CONTROL_INCOMPLETE:
+       case AST_CONTROL_MCID:
+               is_allowed = -1;
+               break;
+
+       /*
+        * These control frames do not make sense to send/receive across the link.
+        */
+       case _XXX_AST_CONTROL_T38:
+               /* The control value is deprecated in favor of AST_CONTROL_T38_PARAMETERS. */
+       case AST_CONTROL_SRCUPDATE:
+               /* Across an IAX link the source is still the same. */
+       case AST_CONTROL_TRANSFER:
+               /* A success/fail status report from calling ast_transfer() on this machine. */
+       case AST_CONTROL_CC:
+               /* The payload contains pointers that are valid for the sending machine only. */
+       case AST_CONTROL_SRCCHANGE:
+               /* Across an IAX link the source is still the same. */
+       case AST_CONTROL_READ_ACTION:
+               /* The action can only be done by the sending machine. */
+       case AST_CONTROL_END_OF_Q:
+               /* This frame would cause the call to unexpectedly hangup. */
+       case AST_CONTROL_UPDATE_RTP_PEER:
+               /* Only meaningful across a bridge on this machine for direct-media exchange. */
+       case AST_CONTROL_PVT_CAUSE_CODE:
+               /* Intended only for the sending machine's local channel structure. */
+       case AST_CONTROL_MASQUERADE_NOTIFY:
+               /* Intended only for masquerades when calling ast_indicate_data(). */
+       case AST_CONTROL_STREAM_STOP:
+       case AST_CONTROL_STREAM_SUSPEND:
+       case AST_CONTROL_STREAM_RESTART:
+       case AST_CONTROL_STREAM_REVERSE:
+       case AST_CONTROL_STREAM_FORWARD:
+               /* None of these playback stream control frames should go across the link. */
+       case AST_CONTROL_RECORD_CANCEL:
+       case AST_CONTROL_RECORD_STOP:
+       case AST_CONTROL_RECORD_SUSPEND:
+       case AST_CONTROL_RECORD_MUTE:
+               /* None of these media recording control frames should go across the link. */
+               break;
+       }
+       return is_allowed;
 }
 
 static void network_change_stasis_subscribe(void)
@@ -1368,7 +1470,7 @@ static int network_change_sched_cb(const void *data)
 }
 
 static void network_change_stasis_cb(void *data, struct stasis_subscription *sub,
-       struct stasis_topic *topic, struct stasis_message *message)
+       struct stasis_message *message)
 {
        /* This callback is only concerned with network change messages from the system topic. */
        if (stasis_message_type(message) != ast_network_change_type()) {
@@ -1382,7 +1484,7 @@ static void network_change_stasis_cb(void *data, struct stasis_subscription *sub
 }
 
 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
-       struct stasis_topic *topic, struct stasis_message *message)
+       struct stasis_message *message)
 {
        if (stasis_message_type(message) != ast_named_acl_change_type()) {
                return;
@@ -1392,17 +1494,6 @@ static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
        reload_config(1);
 }
 
-
-/*! \brief Send manager event at call setup to link between Asterisk channel name
-       and IAX2 call identifiers */
-static void iax2_ami_channelupdate(struct chan_iax2_pvt *pvt)
-{
-       manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
-               "Channel: %s\r\nChanneltype: IAX2\r\nIAX2-callno-local: %d\r\nIAX2-callno-remote: %d\r\nIAX2-peer: %s\r\n",
-               pvt->owner ? ast_channel_name(pvt->owner) : "",
-               pvt->callno, pvt->peercallno, pvt->peer ? pvt->peer : "");
-}
-
 static const struct ast_datastore_info iax2_variable_datastore_info = {
        .type = "IAX2_VARIABLE",
        .duplicate = iax2_dup_variable_datastore,
@@ -1535,12 +1626,11 @@ static struct iax2_thread *find_idle_thread(void)
 #ifdef SCHED_MULTITHREADED
 static int __schedule_action(void (*func)(const void *data), const void *data, const char *funcname)
 {
-       struct iax2_thread *thread = NULL;
+       struct iax2_thread *thread;
        static time_t lasterror;
-       static time_t t;
+       time_t t;
 
        thread = find_idle_thread();
-
        if (thread != NULL) {
                thread->schedfunc = func;
                thread->scheddata = data;
@@ -1552,9 +1642,10 @@ static int __schedule_action(void (*func)(const void *data), const void *data, c
                return 0;
        }
        time(&t);
-       if (t != lasterror)
-               ast_debug(1, "Out of idle IAX2 threads for scheduling!\n");
-       lasterror = t;
+       if (t != lasterror) {
+               lasterror = t;
+               ast_debug(1, "Out of idle IAX2 threads for scheduling! (%s)\n", funcname);
+       }
 
        return -1;
 }
@@ -1573,23 +1664,48 @@ static int iax2_sched_add(struct ast_sched_context *con, int when,
        return ast_sched_add(con, when, callback, data);
 }
 
+/*
+ * \brief Acquire the iaxsl[callno] if call exists and not having ongoing hangup.
+ * \param callno Call number to lock.
+ * \return 0 If call disappeared or has ongoing hangup procedure. 1 If call found and mutex is locked.
+ */
+static int iax2_lock_callno_unless_destroyed(int callno)
+{
+       ast_mutex_lock(&iaxsl[callno]);
+
+       /* We acquired the lock; but the call was already destroyed (we came after full hang up procedures)
+        * or destroy initiated (in middle of hang up procedure. */
+       if (!iaxs[callno] || iaxs[callno]->destroy_initiated) {
+               ast_debug(3, "I wanted to lock callno %d, but it is dead or going to die.\n", callno);
+               ast_mutex_unlock(&iaxsl[callno]);
+               return 0;
+       }
+
+       /* Lock acquired, and callno is alive and kicking. */
+       return 1;
+}
+
 static int send_ping(const void *data);
 
 static void __send_ping(const void *data)
 {
-       int callno = (long) data;
+       int callno = PTR_TO_CALLNO(data);
 
-       ast_mutex_lock(&iaxsl[callno]);
+       if (iax2_lock_callno_unless_destroyed(callno) == 0) {
+               ast_debug(3, "Hangup initiated on call %d, aborting __send_ping\n", callno);
+               return;
+       }
 
-       if (iaxs[callno]) {
-               if (iaxs[callno]->peercallno) {
-                       send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
-                       if (iaxs[callno]->pingid != DONT_RESCHEDULE) {
-                               iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
-                       }
-               }
-       } else {
-               ast_debug(1, "I was supposed to send a PING with callno %d, but no such call exists.\n", callno);
+       /* Mark pingid as invalid scheduler id. */
+       iaxs[callno]->pingid = -1;
+
+       /* callno is now locked. */
+       if (iaxs[callno]->peercallno) {
+               /* Send PING packet. */
+               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_PING, 0, NULL, 0, -1);
+
+               /* Schedule sending next ping. */
+               iaxs[callno]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, data);
        }
 
        ast_mutex_unlock(&iaxsl[callno]);
@@ -1597,13 +1713,6 @@ static void __send_ping(const void *data)
 
 static int send_ping(const void *data)
 {
-       int callno = (long) data;
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno] && iaxs[callno]->pingid != DONT_RESCHEDULE) {
-               iaxs[callno]->pingid = -1;
-       }
-       ast_mutex_unlock(&iaxsl[callno]);
-
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__send_ping, data))
 #endif
@@ -1644,19 +1753,23 @@ static int send_lagrq(const void *data);
 
 static void __send_lagrq(const void *data)
 {
-       int callno = (long) data;
+       int callno = PTR_TO_CALLNO(data);
 
-       ast_mutex_lock(&iaxsl[callno]);
+       if (iax2_lock_callno_unless_destroyed(callno) == 0) {
+               ast_debug(3, "Hangup initiated on call %d, aborting __send_lagrq\n", callno);
+               return;
+       }
 
-       if (iaxs[callno]) {
-               if (iaxs[callno]->peercallno) {
-                       send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
-                       if (iaxs[callno]->lagid != DONT_RESCHEDULE) {
-                               iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
-                       }
-               }
-       } else {
-               ast_debug(1, "I was supposed to send a LAGRQ with callno %d, but no such call exists.\n", callno);
+       /* Mark lagid as invalid scheduler id. */
+       iaxs[callno]->lagid = -1;
+
+       /* callno is now locked. */
+       if (iaxs[callno]->peercallno) {
+               /* Send LAGRQ packet. */
+               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_LAGRQ, 0, NULL, 0, -1);
+
+               /* Schedule sending next lagrq. */
+               iaxs[callno]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, data);
        }
 
        ast_mutex_unlock(&iaxsl[callno]);
@@ -1664,13 +1777,6 @@ static void __send_lagrq(const void *data)
 
 static int send_lagrq(const void *data)
 {
-       int callno = (long) data;
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno] && iaxs[callno]->lagid != DONT_RESCHEDULE) {
-               iaxs[callno]->lagid = -1;
-       }
-       ast_mutex_unlock(&iaxsl[callno]);
-
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__send_lagrq, data))
 #endif
@@ -1712,73 +1818,114 @@ static iax2_format uncompress_subclass(unsigned char csub)
                return csub;
 }
 
-static iax2_format iax2_codec_choose(struct ast_codec_pref *pref, iax2_format formats, int find_best)
+static struct ast_format *codec_choose_from_prefs(struct iax2_codec_pref *pref, struct ast_format_cap *cap)
 {
-       struct ast_format_cap *cap;
-       struct ast_format tmpfmt;
-       iax2_format format = 0;
-       if ((cap = ast_format_cap_alloc_nolock())) {
-               ast_format_clear(&tmpfmt);
-               ast_format_cap_from_old_bitfield(cap, formats);
-               ast_codec_choose(pref, cap, find_best, &tmpfmt);
-               format = ast_format_to_old_bitfield(&tmpfmt);
-               cap = ast_format_cap_destroy(cap);
+       int x;
+       struct ast_format *found_format = NULL;
+
+       for (x = 0; x < ARRAY_LEN(pref->order); ++x) {
+               struct ast_format *pref_format;
+               uint64_t pref_bitfield;
+
+               pref_bitfield = iax2_codec_pref_order_value_to_format_bitfield(pref->order[x]);
+               if (!pref_bitfield) {
+                       break;
+               }
+
+               pref_format = ast_format_compatibility_bitfield2format(pref_bitfield);
+               if (!pref_format) {
+                       /* The bitfield is not associated with any format. */
+                       continue;
+               }
+               found_format = ast_format_cap_get_compatible_format(cap, pref_format);
+               if (found_format) {
+                       break;
+               }
        }
 
-       return format;
+       if (found_format && (ast_format_get_type(found_format) == AST_MEDIA_TYPE_AUDIO)) {
+               return found_format;
+       }
+
+       ast_debug(4, "Could not find preferred codec - Returning zero codec.\n");
+       ao2_cleanup(found_format);
+       return NULL;
 }
 
-static iax2_format iax2_best_codec(iax2_format formats)
+static iax2_format iax2_codec_choose(struct iax2_codec_pref *pref, iax2_format formats)
 {
-       struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
-       struct ast_format tmpfmt;
-       if (!cap) {
-               return 0;
+       struct ast_format_cap *cap;
+       struct ast_format *tmpfmt;
+       iax2_format format = 0;
+
+       if ((cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+               iax2_format_compatibility_bitfield2cap(formats, cap);
+               tmpfmt = codec_choose_from_prefs(pref, cap);
+               if (!tmpfmt) {
+                       ao2_ref(cap, -1);
+                       return 0;
+               }
+
+               format = ast_format_compatibility_format2bitfield(tmpfmt);
+               ao2_ref(tmpfmt, -1);
+               ao2_ref(cap, -1);
        }
 
-       ast_format_clear(&tmpfmt);
-       ast_format_cap_from_old_bitfield(cap, formats);
-       ast_best_codec(cap, &tmpfmt);
-       cap = ast_format_cap_destroy(cap);
-       return ast_format_to_old_bitfield(&tmpfmt);
+       return format;
 }
 
 const char *iax2_getformatname(iax2_format format)
 {
-       struct ast_format tmpfmt;
-       if (!(ast_format_from_old_bitfield(&tmpfmt, format))) {
+       struct ast_format *tmpfmt;
+
+       tmpfmt = ast_format_compatibility_bitfield2format(format);
+       if (!tmpfmt) {
                return "Unknown";
        }
 
-       return ast_getformatname(&tmpfmt);
+       return ast_format_get_name(tmpfmt);
 }
 
-static char *iax2_getformatname_multiple(char *codec_buf, size_t len, iax2_format format)
+static const char *iax2_getformatname_multiple(iax2_format format, struct ast_str **codec_buf)
 {
-       struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
 
        if (!cap) {
                return "(Nothing)";
        }
-       ast_format_cap_from_old_bitfield(cap, format);
-       ast_getformatname_multiple(codec_buf, len, cap);
-       cap = ast_format_cap_destroy(cap);
+       iax2_format_compatibility_bitfield2cap(format, cap);
+       ast_format_cap_get_names(cap, codec_buf);
+       ao2_ref(cap, -1);
 
-       return codec_buf;
+       return ast_str_buffer(*codec_buf);
 }
 
-static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
+static int iax2_parse_allow_disallow(struct iax2_codec_pref *pref, iax2_format *formats, const char *list, int allowing)
 {
-       int res;
-       struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
-       if (!cap) {
+       int res, i;
+       struct ast_format_cap *cap;
+
+       /* We want to add the formats to the cap in the preferred order */
+       cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!cap || iax2_codec_pref_to_cap(pref, cap)) {
+               ao2_cleanup(cap);
                return 1;
        }
 
-       ast_format_cap_from_old_bitfield(cap, *formats);
-       res = ast_parse_allow_disallow(pref, cap, list, allowing);
-       *formats = ast_format_cap_to_old_bitfield(cap);
-       cap = ast_format_cap_destroy(cap);
+       res = ast_format_cap_update_by_allow_disallow(cap, list, allowing);
+
+       /* Adjust formats bitfield and pref list to match. */
+       *formats = iax2_format_compatibility_cap2bitfield(cap);
+       iax2_codec_pref_remove_missing(pref, *formats);
+
+       for (i = 0; i < ast_format_cap_count(cap); i++) {
+               struct ast_format *fmt = ast_format_cap_get_format(cap, i);
+
+               iax2_codec_pref_append(pref, fmt, ast_format_cap_get_format_framing(cap, fmt));
+               ao2_ref(fmt, -1);
+       }
+
+       ao2_ref(cap, -1);
 
        return res;
 }
@@ -1786,13 +1933,13 @@ static int iax2_parse_allow_disallow(struct ast_codec_pref *pref, iax2_format *f
 static int iax2_data_add_codecs(struct ast_data *root, const char *node_name, iax2_format formats)
 {
        int res;
-       struct ast_format_cap *cap = ast_format_cap_alloc_nolock();
+       struct ast_format_cap *cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
        if (!cap) {
                return -1;
        }
-       ast_format_cap_from_old_bitfield(cap, formats);
+       iax2_format_compatibility_bitfield2cap(formats, cap);
        res = ast_data_add_codecs(root, node_name, cap);
-       cap = ast_format_cap_destroy(cap);
+       ao2_ref(cap, -1);
        return res;
 }
 
@@ -1846,16 +1993,16 @@ static int user_cmp_cb(void *obj, void *arg, int flags)
  * \note This funtion calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call it with a pvt lock held.
  */
-static struct iax2_peer *find_peer(const char *name, int realtime) 
+static struct iax2_peer *find_peer(const char *name, int realtime)
 {
        struct iax2_peer *peer = NULL;
 
        peer = ao2_find(peers, name, OBJ_KEY);
 
        /* Now go for realtime if applicable */
-       if(!peer && realtime)
+       if (!peer && realtime) {
                peer = realtime_peer(name, NULL);
-
+       }
        return peer;
 }
 
@@ -1875,11 +2022,6 @@ static struct iax2_user *find_user(const char *name)
 {
        return ao2_find(users, name, OBJ_KEY);
 }
-static inline struct iax2_user *user_ref(struct iax2_user *user)
-{
-       ao2_ref(user, +1);
-       return user;
-}
 
 static inline struct iax2_user *user_unref(struct iax2_user *user)
 {
@@ -1887,7 +2029,7 @@ static inline struct iax2_user *user_unref(struct iax2_user *user)
        return NULL;
 }
 
-static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
+static int iax2_getpeername(struct ast_sockaddr addr, char *host, int len)
 {
        struct iax2_peer *peer = NULL;
        int res = 0;
@@ -1895,12 +2037,8 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 
        i = ao2_iterator_init(peers, 0);
        while ((peer = ao2_iterator_next(&i))) {
-               struct sockaddr_in peer_addr;
-
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-               if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
-                   (peer_addr.sin_port == sin.sin_port)) {
+               if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
                        ast_copy_string(host, peer->name, len);
                        peer_unref(peer);
                        res = 1;
@@ -1911,7 +2049,7 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
        ao2_iterator_destroy(&i);
 
        if (!peer) {
-               peer = realtime_peer(NULL, &sin);
+               peer = realtime_peer(NULL, &addr);
                if (peer) {
                        ast_copy_string(host, peer->name, len);
                        peer_unref(peer);
@@ -1922,6 +2060,16 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
        return res;
 }
 
+/* Call AST_SCHED_DEL on a scheduled task if it is found in scheduler. */
+static int iax2_delete_from_sched(const void* data)
+{
+       int sched_id = (int)(long)data;
+
+       AST_SCHED_DEL(sched, sched_id);
+
+       return 0;
+}
+
 /*!\note Assumes the lock on the pvt is already held, when
  * iax2_destroy_helper() is called. */
 static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
@@ -1938,11 +2086,27 @@ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
 
                ast_clear_flag64(pvt, IAX_MAXAUTHREQ);
        }
-       /* No more pings or lagrq's */
-       AST_SCHED_DEL_SPINLOCK(sched, pvt->pingid, &iaxsl[pvt->callno]);
-       pvt->pingid = DONT_RESCHEDULE;
-       AST_SCHED_DEL_SPINLOCK(sched, pvt->lagid, &iaxsl[pvt->callno]);
-       pvt->lagid = DONT_RESCHEDULE;
+
+
+       /* Mark call destroy initiated flag. */
+       pvt->destroy_initiated = 1;
+
+       /*
+        * Schedule deleting the scheduled (but didn't run yet) PINGs or LAGRQs.
+        * Already running tasks will be terminated because of destroy_initiated.
+        *
+        * Don't call AST_SCHED_DEL from this thread for pingid and lagid because
+        * it leads to a deadlock between the scheduler thread callback locking
+        * the callno mutex and this thread which holds the callno mutex one or
+        * more times.  It is better to have another thread delete the scheduled
+        * callbacks which doesn't lock the callno mutex.
+        */
+       iax2_sched_add(sched, 0, iax2_delete_from_sched, (void*)(long)pvt->pingid);
+       iax2_sched_add(sched, 0, iax2_delete_from_sched, (void*)(long)pvt->lagid);
+
+       pvt->pingid = -1;
+       pvt->lagid = -1;
+
        AST_SCHED_DEL(sched, pvt->autoid);
        AST_SCHED_DEL(sched, pvt->authid);
        AST_SCHED_DEL(sched, pvt->initid);
@@ -2061,14 +2225,9 @@ static void pvt_destructor(void *obj)
                jb_destroy(pvt->jb);
                ast_string_field_free_memory(pvt);
        }
-
-       if (pvt->callid) {
-               ast_callid_unref(pvt->callid);
-       }
-
 }
 
-static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
+static struct chan_iax2_pvt *new_iax(struct ast_sockaddr *addr, const char *host)
 {
        struct chan_iax2_pvt *tmp;
        jb_conf jbconf;
@@ -2082,8 +2241,8 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
                tmp = NULL;
                return NULL;
        }
-               
-       tmp->prefs = prefs;
+
+       tmp->prefs = prefs_global;
        tmp->pingid = -1;
        tmp->lagid = -1;
        tmp->autoid = -1;
@@ -2139,10 +2298,9 @@ enum {
        NEW_ALLOW_CALLTOKEN_VALIDATED = 3,
 };
 
-static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
+static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
 {
-       if ((cur->addr.sin_addr.s_addr == sin->sin_addr.s_addr) &&
-               (cur->addr.sin_port == sin->sin_port)) {
+       if (!ast_sockaddr_cmp(&cur->addr, addr)) {
                /* This is the main host */
                if ( (cur->peercallno == 0 || cur->peercallno == callno) &&
                         (check_dcallno ? dcallno == cur->callno : 1) ) {
@@ -2150,8 +2308,7 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short
                        return 1;
                }
        }
-       if ((cur->transfer.sin_addr.s_addr == sin->sin_addr.s_addr) &&
-           (cur->transfer.sin_port == sin->sin_port) && (cur->transferring)) {
+       if (!ast_sockaddr_cmp(&cur->transfer, addr) && cur->transferring) {
                /* We're transferring */
                if ((dcallno == cur->callno) || (cur->transferring == TRANSFER_MEDIAPASS && cur->transfercallno == callno))
                        return 1;
@@ -2208,9 +2365,9 @@ static int make_trunk(unsigned short callno, int locked)
 
        iaxs[callno] = NULL;
        /* Update the two timers that should have been started */
-       iaxs[x]->pingid = iax2_sched_add(sched, 
+       iaxs[x]->pingid = iax2_sched_add(sched,
                ping_time * 1000, send_ping, (void *)(long)x);
-       iaxs[x]->lagid = iax2_sched_add(sched, 
+       iaxs[x]->lagid = iax2_sched_add(sched,
                lagrq_time * 1000, send_lagrq, (void *)(long)x);
 
        if (locked)
@@ -2274,9 +2431,7 @@ static int addr_range_delme_cb(void *obj, void *arg, int flags)
 static int addr_range_hash_cb(const void *obj, const int flags)
 {
        const struct addr_range *lim = obj;
-       struct sockaddr_in sin;
-       ast_sockaddr_to_sin(&lim->ha.addr, &sin);
-       return abs((int) sin.sin_addr.s_addr);
+       return abs(ast_sockaddr_hash(&lim->ha.addr));
 }
 
 static int addr_range_cmp_cb(void *obj, void *arg, int flags)
@@ -2290,37 +2445,39 @@ static int addr_range_cmp_cb(void *obj, void *arg, int flags)
 static int peercnt_hash_cb(const void *obj, const int flags)
 {
        const struct peercnt *peercnt = obj;
-       return abs((int) peercnt->addr);
+
+       if (ast_sockaddr_isnull(&peercnt->addr)) {
+               return 0;
+       }
+       return ast_sockaddr_hash(&peercnt->addr);
 }
 
 static int peercnt_cmp_cb(void *obj, void *arg, int flags)
 {
        struct peercnt *peercnt1 = obj, *peercnt2 = arg;
-       return (peercnt1->addr == peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
+       return !ast_sockaddr_cmp_addr(&peercnt1->addr, &peercnt2->addr) ? CMP_MATCH | CMP_STOP : 0;
 }
 
 static int addr_range_match_address_cb(void *obj, void *arg, int flags)
 {
        struct addr_range *addr_range = obj;
-       struct sockaddr_in *sin = arg;
-       struct sockaddr_in ha_netmask_sin;
-       struct sockaddr_in ha_addr_sin;
+       struct ast_sockaddr *addr = arg;
+       struct ast_sockaddr tmp_addr;
 
-       ast_sockaddr_to_sin(&addr_range->ha.netmask, &ha_netmask_sin);
-       ast_sockaddr_to_sin(&addr_range->ha.addr, &ha_addr_sin);
+       ast_sockaddr_apply_netmask(addr, &addr_range->ha.netmask, &tmp_addr);
 
-       if ((sin->sin_addr.s_addr & ha_netmask_sin.sin_addr.s_addr) == ha_addr_sin.sin_addr.s_addr) {
+       if (!ast_sockaddr_cmp_addr(&tmp_addr, &addr_range->ha.addr)) {
                return CMP_MATCH | CMP_STOP;
        }
        return 0;
 }
 
-/*! 
+/*!
  * \internal
  *
- * \brief compares sin to calltoken_ignores table to determine if validation is required.
+ * \brief compares addr to calltoken_ignores table to determine if validation is required.
  */
-static int calltoken_required(struct sockaddr_in *sin, const char *name, int subclass)
+static int calltoken_required(struct ast_sockaddr *addr, const char *name, int subclass)
 {
        struct addr_range *addr_range;
        struct iax2_peer *peer = NULL;
@@ -2337,7 +2494,7 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
         */
 
        /* ----- Case 1 ----- */
-       if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, sin))) {
+       if ((addr_range = ao2_callback(calltoken_ignores, 0, addr_range_match_address_cb, addr))) {
                ao2_ref(addr_range, -1);
                optional = 1;
        }
@@ -2345,11 +2502,11 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
        /* ----- Case 2 ----- */
        if ((subclass == IAX_COMMAND_NEW) && (user = find_user(find))) {
                calltoken_required = user->calltoken_required;
-       } else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, sin))) {
+       } else if ((subclass == IAX_COMMAND_NEW) && (user = realtime_user(find, addr))) {
                calltoken_required = user->calltoken_required;
        } else if ((subclass != IAX_COMMAND_NEW) && (peer = find_peer(find, 0))) {
                calltoken_required = peer->calltoken_required;
-       } else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, sin))) {
+       } else if ((subclass != IAX_COMMAND_NEW) && (peer = realtime_peer(find, addr))) {
                calltoken_required = peer->calltoken_required;
        }
 
@@ -2360,7 +2517,7 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
                user_unref(user);
        }
 
-       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %d \n", ast_inet_ntoa(sin->sin_addr), name, optional, calltoken_required);
+       ast_debug(1, "Determining if address %s with username %s requires calltoken validation.  Optional = %d  calltoken_required = %u \n", ast_sockaddr_stringify_addr(addr), name, optional, calltoken_required);
        if (((calltoken_required == CALLTOKEN_NO) || (calltoken_required == CALLTOKEN_AUTO)) ||
                (optional && (calltoken_required == CALLTOKEN_DEFAULT))) {
                res = 0;
@@ -2369,12 +2526,12 @@ static int calltoken_required(struct sockaddr_in *sin, const char *name, int sub
        return res;
 }
 
-/*! 
+/*!
  * \internal
  *
  * \brief set peercnt callno limit.
  *
- * \details 
+ * \details
  * First looks in custom definitions. If not found, global limit
  * is used.  Entries marked as reg already have
  * a custom limit set by a registration and are not modified.
@@ -2383,25 +2540,24 @@ static void set_peercnt_limit(struct peercnt *peercnt)
 {
        uint16_t limit = global_maxcallno;
        struct addr_range *addr_range;
-       struct sockaddr_in sin = {
-               .sin_addr.s_addr = peercnt->addr,
-       };
+       struct ast_sockaddr addr;
 
+       ast_sockaddr_copy(&addr, &peercnt->addr);
 
        if (peercnt->reg && peercnt->limit) {
                return; /* this peercnt has a custom limit set by a registration */
        }
 
-       if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &sin))) {
+       if ((addr_range = ao2_callback(callno_limits, 0, addr_range_match_address_cb, &addr))) {
                limit = addr_range->limit;
-               ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_inet_ntoa(sin.sin_addr));
+               ast_debug(1, "custom addr_range %d found for %s\n", limit, ast_sockaddr_stringify(&addr));
                ao2_ref(addr_range, -1);
        }
 
        peercnt->limit = limit;
 }
 
-/*! 
+/*!
  * \internal
  * \brief sets limits for all peercnts in table. done on reload to reflect changes in conf.
  */
@@ -2415,9 +2571,9 @@ static int set_peercnt_limit_all_cb(void *obj, void *arg, int flags)
        return 0;
 }
 
-/*! 
+/*!
  * \internal
- * \brief returns match if delme is set. 
+ * \brief returns match if delme is set.
  */
 static int prune_addr_range_cb(void *obj, void *arg, int flags)
 {
@@ -2426,7 +2582,7 @@ static int prune_addr_range_cb(void *obj, void *arg, int flags)
        return addr_range->delme ? CMP_MATCH : 0;
 }
 
-/*! 
+/*!
  * \internal
  * \brief modifies peercnt entry in peercnts table. Used to set custom limit or mark a registered ip
  */
@@ -2434,14 +2590,9 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
 {
        /* this function turns off and on custom callno limits set by peer registration */
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = 0,
-       };
-       struct sockaddr_in sin;
+       struct peercnt tmp;
 
-       ast_sockaddr_to_sin(sockaddr, &sin);
-
-       tmp.addr = sin.sin_addr.s_addr;
+       ast_sockaddr_copy(&tmp.addr, sockaddr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                peercnt->reg = reg;
@@ -2450,12 +2601,12 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
                } else {
                        set_peercnt_limit(peercnt);
                }
-               ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_inet_ntoa(sin.sin_addr), peercnt->limit, peercnt->reg);
+               ast_debug(1, "peercnt entry %s modified limit:%d registered:%d", ast_sockaddr_stringify_addr(sockaddr), peercnt->limit, peercnt->reg);
                ao2_ref(peercnt, -1); /* decrement ref from find */
        }
 }
 
-/*! 
+/*!
  * \internal
  * \brief adds an ip to the peercnts table, increments connection count if it already exists
  *
@@ -2463,14 +2614,13 @@ static void peercnt_modify(unsigned char reg, uint16_t limit, struct ast_sockadd
  * the current count is incremented.  If not found a new peercnt is allocated
  * and linked into the peercnts table with a call number count of 1.
  */
-static int peercnt_add(struct sockaddr_in *sin)
+static int peercnt_add(struct ast_sockaddr *addr)
 {
        struct peercnt *peercnt;
-       unsigned long addr = sin->sin_addr.s_addr;
        int res = 0;
-       struct peercnt tmp = {
-               .addr = addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        /* Reasoning for peercnts container lock:  Two identical ip addresses
         * could be added by different threads at the "same time". Without the container
@@ -2484,7 +2634,7 @@ static int peercnt_add(struct sockaddr_in *sin)
        } else if ((peercnt = ao2_alloc(sizeof(*peercnt), NULL))) {
                ao2_lock(peercnt);
                /* create and set defaults */
-               peercnt->addr = addr;
+               ast_sockaddr_copy(&peercnt->addr, addr);
                set_peercnt_limit(peercnt);
                /* guarantees it does not go away after unlocking table
                 * ao2_find automatically adds this */
@@ -2497,9 +2647,9 @@ static int peercnt_add(struct sockaddr_in *sin)
        /* check to see if the address has hit its callno limit.  If not increment cur. */
        if (peercnt->limit > peercnt->cur) {
                peercnt->cur++;
-               ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin->sin_addr));
+               ast_debug(1, "ip callno count incremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(addr));
        } else { /* max num call numbers for this peer has been reached! */
-               ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_inet_ntoa(sin->sin_addr));
+               ast_log(LOG_ERROR, "maxcallnumber limit of %d for %s has been reached!\n", peercnt->limit, ast_sockaddr_stringify_addr(addr));
                res = -1;
        }
 
@@ -2511,15 +2661,15 @@ static int peercnt_add(struct sockaddr_in *sin)
        return res;
 }
 
-/*! 
+/*!
  * \internal
  * \brief decrements a peercnts table entry
  */
 static void peercnt_remove(struct peercnt *peercnt)
 {
-       struct sockaddr_in sin = {
-               .sin_addr.s_addr = peercnt->addr,
-       };
+       struct ast_sockaddr addr;
+
+       ast_sockaddr_copy(&addr, &peercnt->addr);
 
        /*
         * Container locked here since peercnt may be unlinked from
@@ -2529,7 +2679,7 @@ static void peercnt_remove(struct peercnt *peercnt)
         */
        ao2_lock(peercnts);
        peercnt->cur--;
-       ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_inet_ntoa(sin.sin_addr));
+       ast_debug(1, "ip callno count decremented to %d for %s\n", peercnt->cur, ast_sockaddr_stringify_addr(&addr));
        /* if this was the last connection from the peer remove it from table */
        if (peercnt->cur == 0) {
                ao2_unlink(peercnts, peercnt);/* decrements ref from table, last ref is left to scheduler */
@@ -2537,7 +2687,7 @@ static void peercnt_remove(struct peercnt *peercnt)
        ao2_unlock(peercnts);
 }
 
-/*! 
+/*!
  * \internal
  * \brief called by scheduler to decrement object
  */
@@ -2551,16 +2701,16 @@ static int peercnt_remove_cb(const void *obj)
        return 0;
 }
 
-/*! 
+/*!
  * \internal
  * \brief decrements peercnts connection count, finds by addr
  */
-static int peercnt_remove_by_addr(struct sockaddr_in *sin)
+static int peercnt_remove_by_addr(struct ast_sockaddr *addr)
 {
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = sin->sin_addr.s_addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                peercnt_remove(peercnt);
@@ -2569,7 +2719,7 @@ static int peercnt_remove_by_addr(struct sockaddr_in *sin)
        return 0;
 }
 
-/*! 
+/*!
  * \internal
  * \brief Create callno_limit entry based on configuration
  */
@@ -2624,7 +2774,7 @@ static void build_callno_limits(struct ast_variable *v)
        }
 }
 
-/*! 
+/*!
  * \internal
  * \brief Create calltoken_ignores entry based on configuration
  */
@@ -2673,7 +2823,7 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
 {
        struct ao2_iterator i;
        struct peercnt *peercnt;
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int found = 0;
 
        switch (cmd) {
@@ -2690,22 +2840,23 @@ static char *handle_cli_iax2_show_callno_limits(struct ast_cli_entry *e, int cmd
                        return CLI_SHOWUSAGE;
 
                if (a->argc == 4) {
-                       ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+                       ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
                }
 
                i = ao2_iterator_init(peercnts, 0);
                while ((peercnt = ao2_iterator_next(&i))) {
-                       sin.sin_addr.s_addr = peercnt->addr;
+                       ast_sockaddr_copy(&addr, &peercnt->addr);
+
                        if (a->argc == 5) {
-                               if (!strcasecmp(a->argv[4], ast_inet_ntoa(sin.sin_addr))) {
-                                       ast_cli(a->fd, "%-15s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
-                                       ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
+                               if (!strcasecmp(a->argv[4], ast_sockaddr_stringify(&addr))) {
+                                       ast_cli(a->fd, "%-45s %-12s %-12s\n", "Address", "Callno Usage", "Callno Limit");
+                                       ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
                                        ao2_ref(peercnt, -1);
                                        found = 1;
                                        break;
                                }
                        } else {
-                               ast_cli(a->fd, "%-15s %-12d %-12d\n", ast_inet_ntoa(sin.sin_addr), peercnt->cur, peercnt->limit);
+                               ast_cli(a->fd, "%-45s %-12d %-12d\n", ast_sockaddr_stringify(&addr), peercnt->cur, peercnt->limit);
                        }
                        ao2_ref(peercnt, -1);
                }
@@ -2883,20 +3034,20 @@ static int create_callno_pools(void)
  * \brief Schedules delayed removal of iax2_pvt call number data
  *
  * \note After MIN_REUSE_TIME has passed for a destroyed iax2_pvt, the callno is
- * avaliable again, and the address from the previous connection must be decremented
+ * available again, and the address from the previous connection must be decremented
  * from the peercnts table.  This function schedules these operations to take place.
  */
-static void sched_delay_remove(struct sockaddr_in *sin, callno_entry entry)
+static void sched_delay_remove(struct ast_sockaddr *addr, callno_entry entry)
 {
        int i;
        struct peercnt *peercnt;
-       struct peercnt tmp = {
-               .addr = sin->sin_addr.s_addr,
-       };
+       struct peercnt tmp;
+
+       ast_sockaddr_copy(&tmp.addr, addr);
 
        if ((peercnt = ao2_find(peercnts, &tmp, OBJ_POINTER))) {
                /* refcount is incremented with ao2_find.  keep that ref for the scheduler */
-               ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_inet_ntoa(sin->sin_addr), MIN_REUSE_TIME);
+               ast_debug(1, "schedule decrement of callno used for %s in %d seconds\n", ast_sockaddr_stringify_addr(addr), MIN_REUSE_TIME);
                i = iax2_sched_add(sched, MIN_REUSE_TIME * 1000, peercnt_remove_cb, peercnt);
                if (i == -1) {
                        ao2_ref(peercnt, -1);
@@ -2910,9 +3061,9 @@ static void sched_delay_remove(struct sockaddr_in *sin, callno_entry entry)
                CALLNO_ENTRY_TO_PTR(entry));
 }
 
-/*! 
+/*!
  * \internal
- * \brief returns whether or not a frame is capable of starting a new IAX2 dialog. 
+ * \brief returns whether or not a frame is capable of starting a new IAX2 dialog.
  *
  * \note For this implementation, inbound pokes should _NOT_ be capable of allocating
  * a new callno.
@@ -2940,7 +3091,7 @@ static inline int attribute_pure iax2_allow_new(int frametype, int subclass, int
 /*
  * \note Calling this function while holding another pvt lock can cause a deadlock.
  */
-static int __find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int return_locked, int check_dcallno)
+static int __find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int return_locked, int check_dcallno)
 {
        int res = 0;
        int x;
@@ -2960,8 +3111,8 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                                .frames_received = check_dcallno,
                        };
 
-                       memcpy(&tmp_pvt.addr, sin, sizeof(tmp_pvt.addr));
-                       /* this works for finding normal call numbers not involving transfering */ 
+                       ast_sockaddr_copy(&tmp_pvt.addr, addr);
+                       /* this works for finding normal call numbers not involving transfering */
                        if ((pvt = ao2_find(iax_peercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
                                if (return_locked) {
                                        ast_mutex_lock(&iaxsl[pvt->callno]);
@@ -2973,7 +3124,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                        }
                        /* this searches for transfer call numbers that might not get caught otherwise */
                        memset(&tmp_pvt.addr, 0, sizeof(tmp_pvt.addr));
-                       memcpy(&tmp_pvt.transfer, sin, sizeof(tmp_pvt.transfer));
+                       ast_sockaddr_copy(&tmp_pvt.transfer, addr);
                        if ((pvt = ao2_find(iax_transfercallno_pvts, &tmp_pvt, OBJ_POINTER))) {
                                if (return_locked) {
                                        ast_mutex_lock(&iaxsl[pvt->callno]);
@@ -2989,7 +3140,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                if (dcallno) {
                        ast_mutex_lock(&iaxsl[dcallno]);
                }
-               if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(sin, callno, dcallno, iaxs[dcallno], check_dcallno)) {
+               if (callno && dcallno && iaxs[dcallno] && !iaxs[dcallno]->peercallno && match(addr, callno, dcallno, iaxs[dcallno], check_dcallno)) {
                        iaxs[dcallno]->peercallno = callno;
                        res = dcallno;
                        store_by_peercallno(iaxs[dcallno]);
@@ -3004,16 +3155,17 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
        }
        if (!res && (new >= NEW_ALLOW)) {
                callno_entry entry;
+
                /* It may seem odd that we look through the peer list for a name for
                 * this *incoming* call.  Well, it is weird.  However, users don't
                 * have an IP address/port number that we can match against.  So,
                 * this is just checking for a peer that has that IP/port and
                 * assuming that we have a user of the same name.  This isn't always
                 * correct, but it will be changed if needed after authentication. */
-               if (!iax2_getpeername(*sin, host, sizeof(host)))
-                       snprintf(host, sizeof(host), "%s:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               if (!iax2_getpeername(*addr, host, sizeof(host)))
+                       snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(addr));
 
-               if (peercnt_add(sin)) {
+               if (peercnt_add(addr)) {
                        /* This address has hit its callnumber limit.  When the limit
                         * is reached, the connection is not added to the peercnts table.*/
                        return 0;
@@ -3022,22 +3174,20 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                if (get_unused_callno(CALLNO_TYPE_NORMAL, validated, &entry)) {
                        /* since we ran out of space, remove the peercnt
                         * entry we added earlier */
-                       peercnt_remove_by_addr(sin);
+                       peercnt_remove_by_addr(addr);
                        ast_log(LOG_WARNING, "No more space\n");
                        return 0;
                }
                x = CALLNO_ENTRY_GET_CALLNO(entry);
                ast_mutex_lock(&iaxsl[x]);
 
-               iaxs[x] = new_iax(sin, host);
+               iaxs[x] = new_iax(addr, host);
                if (iaxs[x]) {
                        if (iaxdebug)
                                ast_debug(1, "Creating new call structure %d\n", x);
                        iaxs[x]->callno_entry = entry;
                        iaxs[x]->sockfd = sockfd;
-                       iaxs[x]->addr.sin_port = sin->sin_port;
-                       iaxs[x]->addr.sin_family = sin->sin_family;
-                       iaxs[x]->addr.sin_addr.s_addr = sin->sin_addr.s_addr;
+                       ast_sockaddr_copy(&iaxs[x]->addr, addr);
                        iaxs[x]->peercallno = callno;
                        iaxs[x]->callno = x;
                        iaxs[x]->pingtime = DEFAULT_RETRY_TIME;
@@ -3045,7 +3195,7 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
                        iaxs[x]->pingid = iax2_sched_add(sched, ping_time * 1000, send_ping, (void *)(long)x);
                        iaxs[x]->lagid = iax2_sched_add(sched, lagrq_time * 1000, send_lagrq, (void *)(long)x);
                        iaxs[x]->amaflags = amaflags;
-                       ast_copy_flags64(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+                       ast_copy_flags64(iaxs[x], &globalflags, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
                        ast_string_field_set(iaxs[x], accountcode, accountcode);
                        ast_string_field_set(iaxs[x], mohinterpret, mohinterpret);
                        ast_string_field_set(iaxs[x], mohsuggest, mohsuggest);
@@ -3067,13 +3217,13 @@ static int __find_callno(unsigned short callno, unsigned short dcallno, struct s
        return res;
 }
 
-static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) { 
-       return __find_callno(callno, dcallno, sin, new, sockfd, 0, full_frame);
+static int find_callno(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
+       return __find_callno(callno, dcallno, addr, new, sockfd, 0, full_frame);
 }
 
-static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new, int sockfd, int full_frame) {
+static int find_callno_locked(unsigned short callno, unsigned short dcallno, struct ast_sockaddr *addr, int new, int sockfd, int full_frame) {
 
-       return __find_callno(callno, dcallno, sin, new, sockfd, 1, full_frame);
+       return __find_callno(callno, dcallno, addr, new, sockfd, 1, full_frame);
 }
 
 /*!
@@ -3170,7 +3320,7 @@ static int iax2_queue_hangup(int callno)
  *
  * \note IMPORTANT NOTE!!! Any time this function is used, even if iaxs[callno]
  * was valid before calling it, it may no longer be valid after calling it.
- * This function calls iax2_queue_frame(), which may unlock and lock the mutex 
+ * This function calls iax2_queue_frame(), which may unlock and lock the mutex
  * associated with this callno, meaning that another thread may grab it and destroy the call.
  */
 static int __do_deliver(void *data)
@@ -3210,7 +3360,7 @@ static int handle_error(void)
        else {
                if (m.msg_controllen) {
                        sin = (struct sockaddr_in *)SO_EE_OFFENDER(&e);
-                       if (sin) 
+                       if (sin)
                                ast_log(LOG_WARNING, "Receive error from %s\n", ast_inet_ntoa(sin->sin_addr));
                        else
                                ast_log(LOG_WARNING, "No address detected??\n");
@@ -3222,11 +3372,11 @@ static int handle_error(void)
        return 0;
 }
 
-static int transmit_trunk(struct iax_frame *f, struct sockaddr_in *sin, int sockfd)
+static int transmit_trunk(struct iax_frame *f, struct ast_sockaddr *addr, int sockfd)
 {
        int res;
-       res = sendto(sockfd, f->data, f->datalen, 0,(struct sockaddr *)sin,
-                                       sizeof(*sin));
+       res = ast_sendto(sockfd, f->data, f->datalen, 0, addr);
+
        if (res < 0) {
                ast_debug(1, "Received error: %s\n", strerror(errno));
                handle_error();
@@ -3245,15 +3395,15 @@ static int send_packet(struct iax_frame *f)
            return -1;
 
        /* Called with iaxsl held */
-       if (iaxdebug)
-               ast_debug(3, "Sending %d on %d/%d to %s:%d\n", f->ts, callno, iaxs[callno]->peercallno, ast_inet_ntoa(iaxs[callno]->addr.sin_addr), ntohs(iaxs[callno]->addr.sin_port));
-
+       if (iaxdebug) {
+               ast_debug(3, "Sending %u on %d/%d to %s\n", f->ts, callno, iaxs[callno]->peercallno, ast_sockaddr_stringify(&iaxs[callno]->addr));
+       }
        if (f->transfer) {
                iax_outputframe(f, NULL, 0, &iaxs[callno]->transfer, f->datalen - sizeof(struct ast_iax2_full_hdr));
-               res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->transfer, sizeof(iaxs[callno]->transfer));
+               res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->transfer);
        } else {
                iax_outputframe(f, NULL, 0, &iaxs[callno]->addr, f->datalen - sizeof(struct ast_iax2_full_hdr));
-               res = sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0,(struct sockaddr *)&iaxs[callno]->addr, sizeof(iaxs[callno]->addr));
+               res = ast_sendto(iaxs[callno]->sockfd, f->data, f->datalen, 0, &iaxs[callno]->addr);
        }
        if (res < 0) {
                if (iaxdebug)
@@ -3388,42 +3538,49 @@ static void __attempt_transmit(const void *data)
        struct iax_frame *f = (struct iax_frame *)data;
        int freeme = 0;
        int callno = f->callno;
+
        /* Make sure this call is still active */
-       if (callno) 
+       if (callno)
                ast_mutex_lock(&iaxsl[callno]);
        if (callno && iaxs[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 */
-                               if (f->retries >= max_retries) {
-                                       if (f->transfer) {
-                                               /* Transfer timeout */
-                                               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
-                                       } else if (f->final) {
-                                               iax2_destroy(callno);
-                                       } else {
-                                               if (iaxs[callno]->owner)
-                                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %d, subclass = %u, ts=%d, seqno=%d)\n", ast_inet_ntoa(iaxs[f->callno]->addr.sin_addr),ast_channel_name(iaxs[f->callno]->owner), f->af.frametype, f->af.subclass.integer, f->ts, f->oseqno);
-                                               iaxs[callno]->error = ETIMEDOUT;
-                                               if (iaxs[callno]->owner) {
-                                                       struct ast_frame fr = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
-                                                       /* Hangup the fd */
-                                                       iax2_queue_frame(callno, &fr); /* XXX */
-                                                       /* Remember, owner could disappear */
-                                                       if (iaxs[callno] && iaxs[callno]->owner)
-                                                               ast_channel_hangupcause_set(iaxs[callno]->owner, AST_CAUSE_DESTINATION_OUT_OF_ORDER);
-                                               } else {
-                                                       if (iaxs[callno]->reg) {
-                                                               memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
-                                                               iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
-                                                               iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
-                                                       }
-                                                       iax2_destroy(callno);
-                                               }
+               if (f->retries < 0) {
+                       /* Already ACK'd */
+                       freeme = 1;
+               } else if (f->retries >= max_retries) {
+                       /* Too many attempts.  Record an error. */
+                       if (f->transfer) {
+                               /* Transfer timeout */
+                               send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_TXREJ, 0, NULL, 0, -1);
+                       } else if (f->final) {
+                               iax2_destroy(callno);
+                       } else {
+                               if (iaxs[callno]->owner) {
+                                       ast_log(LOG_WARNING, "Max retries exceeded to host %s on %s (type = %u, subclass = %d, ts=%u, seqno=%d)\n",
+                                               ast_sockaddr_stringify_addr(&iaxs[f->callno]->addr),
+                                               ast_channel_name(iaxs[f->callno]->owner),
+                                               f->af.frametype,
+                                               f->af.subclass.integer,
+                                               f->ts,
+                                               f->oseqno);
+                               }
+                               iaxs[callno]->error = ETIMEDOUT;
+                               if (iaxs[callno]->owner) {
+                                       struct ast_frame fr = { AST_FRAME_CONTROL, { AST_CONTROL_HANGUP }, .data.uint32 = AST_CAUSE_DESTINATION_OUT_OF_ORDER };
+                                       /* Hangup the fd */
+                                       iax2_queue_frame(callno, &fr); /* XXX */
+                                       /* Remember, owner could disappear */
+                                       if (iaxs[callno] && iaxs[callno]->owner)
+                                               ast_channel_hangupcause_set(iaxs[callno]->owner, AST_CAUSE_DESTINATION_OUT_OF_ORDER);
+                               } else {
+                                       if (iaxs[callno]->reg) {
+                                               memset(&iaxs[callno]->reg->us, 0, sizeof(iaxs[callno]->reg->us));
+                                               iaxs[callno]->reg->regstate = REG_STATE_TIMEOUT;
+                                               iaxs[callno]->reg->refresh = IAX_DEFAULT_REG_EXPIRE;
                                        }
-
+                                       iax2_destroy(callno);
                                }
-                               freeme = 1;
+                       }
+                       freeme = 1;
                } else {
                        /* Update it if it needs it */
                        update_packet(f);
@@ -3461,7 +3618,7 @@ static int attempt_transmit(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__attempt_transmit, data))
-#endif         
+#endif
                __attempt_transmit(data);
        return 0;
 }
@@ -3633,7 +3790,7 @@ static int peer_status(struct iax2_peer *peer, char *status, int statuslen)
                } else {
                        ast_copy_string(status, "UNKNOWN", statuslen);
                }
-       } else { 
+       } else {
                ast_copy_string(status, "Unmonitored", statuslen);
                res = -1;
        }
@@ -3646,9 +3803,9 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
        char status[30];
        char cbuf[256];
        struct iax2_peer *peer;
-       char codec_buf[512];
+       struct ast_str *codec_buf = ast_str_alloca(256);
        struct ast_str *encmethods = ast_str_alloca(256);
-       int x = 0, load_realtime = 0;
+       int load_realtime = 0;
 
        switch (cmd) {
        case CLI_INIT:
@@ -3670,9 +3827,13 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
 
        peer = find_peer(a->argv[3], load_realtime);
        if (peer) {
-               struct sockaddr_in peer_addr;
+               char *str_addr, *str_defaddr;
+               char *str_port, *str_defport;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+               str_addr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
+               str_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
+               str_defaddr = ast_strdupa(ast_sockaddr_stringify_addr(&peer->defaddr));
+               str_defport = ast_strdupa(ast_sockaddr_stringify_port(&peer->defaddr));
 
                encmethods_to_str(peer->encmethods, &encmethods);
                ast_cli(a->fd, "\n\n");
@@ -3690,30 +3851,18 @@ static char *handle_cli_iax2_show_peer(struct ast_cli_entry *e, int cmd, struct
                ast_cli(a->fd, "  Callerid     : %s\n", ast_callerid_merge(cbuf, sizeof(cbuf), peer->cid_name, peer->cid_num, "<unspecified>"));
                ast_cli(a->fd, "  Expire       : %d\n", peer->expire);
                ast_cli(a->fd, "  ACL          : %s\n", (ast_acl_list_is_empty(peer->acl) ? "No" : "Yes"));
-               ast_cli(a->fd, "  Addr->IP     : %s Port %d\n",  peer_addr.sin_addr.s_addr ? ast_inet_ntoa(peer_addr.sin_addr) : "(Unspecified)", ntohs(peer_addr.sin_port));
-               ast_cli(a->fd, "  Defaddr->IP  : %s Port %d\n", ast_inet_ntoa(peer->defaddr.sin_addr), ntohs(peer->defaddr.sin_port));
+               ast_cli(a->fd, "  Addr->IP     : %s Port %s\n",  str_addr ? str_addr : "(Unspecified)", str_port);
+               ast_cli(a->fd, "  Defaddr->IP  : %s Port %s\n", str_defaddr, str_defport);
                ast_cli(a->fd, "  Username     : %s\n", peer->username);
-               ast_cli(a->fd, "  Codecs       : ");
-               iax2_getformatname_multiple(codec_buf, sizeof(codec_buf) -1, peer->capability);
-               ast_cli(a->fd, "%s\n", codec_buf);
-
-               ast_cli(a->fd, "  Codec Order  : (");
-               for(x = 0; x < AST_CODEC_PREF_SIZE; x++) {
-                       struct ast_format tmpfmt;
-                       if(!(ast_codec_pref_index(&peer->prefs, x, &tmpfmt)))
-                               break;
-                       ast_cli(a->fd, "%s", ast_getformatname(&tmpfmt));
-                       if(x < 31 && ast_codec_pref_index(&peer->prefs, x+1, &tmpfmt))
-                               ast_cli(a->fd, "|");
-               }
+               ast_cli(a->fd, "  Codecs       : %s\n", iax2_getformatname_multiple(peer->capability, &codec_buf));
 
-               if (!x)
-                       ast_cli(a->fd, "none");
-               ast_cli(a->fd, ")\n");
+               if (iax2_codec_pref_string(&peer->prefs, cbuf, sizeof(cbuf)) < 0) {
+                       strcpy(cbuf, "Error"); /* Safe */
+               }
+               ast_cli(a->fd, "  Codec Order  : %s\n", cbuf);
 
-               ast_cli(a->fd, "  Status       : ");
-               peer_status(peer, status, sizeof(status));      
-               ast_cli(a->fd, "%s\n",status);
+               peer_status(peer, status, sizeof(status));
+               ast_cli(a->fd, "  Status       : %s\n", status);
                ast_cli(a->fd, "  Qualify      : every %dms when OK, every %dms when UNREACHABLE (sample smoothing %s)\n", peer->pokefreqok, peer->pokefreqnotok, peer->smoothing ? "On" : "Off");
                ast_cli(a->fd, "\n");
                peer_unref(peer);
@@ -3815,23 +3964,23 @@ static char *handle_cli_iax2_set_mtu(struct ast_cli_entry *e, int cmd, struct as
        }
 
        if (a->argc != 4)
-               return CLI_SHOWUSAGE; 
+               return CLI_SHOWUSAGE;
        if (strncasecmp(a->argv[3], "default", strlen(a->argv[3])) == 0)
                mtuv = MAX_TRUNK_MTU;
        else
                mtuv = atoi(a->argv[3]);
 
        if (mtuv == 0) {
-               ast_cli(a->fd, "Trunk MTU control disabled (mtu was %d)\n", global_max_trunk_mtu); 
-               global_max_trunk_mtu = 0; 
-               return CLI_SUCCESS; 
+               ast_cli(a->fd, "Trunk MTU control disabled (mtu was %d)\n", global_max_trunk_mtu);
+               global_max_trunk_mtu = 0;
+               return CLI_SUCCESS;
        }
        if (mtuv < 172 || mtuv > 4000) {
-               ast_cli(a->fd, "Trunk MTU must be between 172 and 4000\n"); 
-               return CLI_SHOWUSAGE; 
+               ast_cli(a->fd, "Trunk MTU must be between 172 and 4000\n");
+               return CLI_SHOWUSAGE;
        }
-       ast_cli(a->fd, "Trunk MTU changed from %d to %d\n", global_max_trunk_mtu, mtuv); 
-       global_max_trunk_mtu = mtuv; 
+       ast_cli(a->fd, "Trunk MTU changed from %d to %d\n", global_max_trunk_mtu, mtuv);
+       global_max_trunk_mtu = mtuv;
        return CLI_SUCCESS;
 }
 
@@ -3969,7 +4118,7 @@ static void __get_from_jb(const void *p)
        long ms;
        long next;
        struct timeval now = ast_tvnow();
-       
+
        /* Make sure we have a valid private structure before going on */
        ast_mutex_lock(&iaxsl[callno]);
        pvt = iaxs[callno];
@@ -3980,18 +4129,18 @@ static void __get_from_jb(const void *p)
        }
 
        pvt->jbid = -1;
-       
+
        /* round up a millisecond since ast_sched_runq does; */
        /* prevents us from spinning while waiting for our now */
        /* to catch up with runq's now */
        now.tv_usec += 1000;
-       
+
        ms = ast_tvdiff_ms(now, pvt->rxcore);
-       
+
        if(ms >= (next = jb_next(pvt->jb))) {
-               struct ast_format voicefmt;
-               ast_format_from_old_bitfield(&voicefmt, pvt->voiceformat);
-               ret = jb_get(pvt->jb, &frame, ms, ast_codec_interp_len(&voicefmt));
+               struct ast_format *voicefmt;
+               voicefmt = ast_format_compatibility_bitfield2format(pvt->voiceformat);
+               ret = jb_get(pvt->jb, &frame, ms, voicefmt ? ast_format_get_default_ms(voicefmt) : 20);
                switch(ret) {
                case JB_OK:
                        fr = frame.data;
@@ -4002,15 +4151,15 @@ static void __get_from_jb(const void *p)
                case JB_INTERP:
                {
                        struct ast_frame af = { 0, };
-                       
+
                        /* create an interpolation frame */
                        af.frametype = AST_FRAME_VOICE;
-                       ast_format_copy(&af.subclass.format, &voicefmt);
-                       af.samples  = frame.ms * (ast_format_rate(&voicefmt) / 1000);
+                       af.subclass.format = voicefmt;
+                       af.samples  = frame.ms * (ast_format_get_sample_rate(voicefmt) / 1000);
                        af.src  = "IAX2 JB interpolation";
                        af.delivery = ast_tvadd(pvt->rxcore, ast_samp2tv(next, 1000));
                        af.offset = AST_FRIENDLY_OFFSET;
-                       
+
                        /* queue the frame:  For consistency, we would call __do_deliver here, but __do_deliver wants an iax_frame,
                         * which we'd need to malloc, and then it would free it.  That seems like a drag */
                        if (!ast_test_flag64(iaxs[callno], IAX_ALREADYGONE)) {
@@ -4041,7 +4190,7 @@ static int get_from_jb(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__get_from_jb, data))
-#endif         
+#endif
                __get_from_jb(data);
        return 0;
 }
@@ -4057,8 +4206,6 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
        int type, len;
        int ret;
        int needfree = 0;
-       struct ast_channel *owner = NULL;
-       struct ast_channel *bridge = NULL;
 
        /*
         * Clear fr->af.data if there is no data in the buffer.  Things
@@ -4087,7 +4234,7 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
 
        if(fr->af.frametype == AST_FRAME_VOICE) {
                type = JB_TYPE_VOICE;
-               len = ast_codec_get_samples(&fr->af) / (ast_format_rate(&fr->af.subclass.format) / 1000);
+               len = ast_codec_samples_count(&fr->af) / (ast_format_get_sample_rate(fr->af.subclass.format) / 1000);
        } else if(fr->af.frametype == AST_FRAME_CNG) {
                type = JB_TYPE_SILENCE;
        }
@@ -4099,44 +4246,6 @@ static int schedule_delivery(struct iax_frame *fr, int updatehistory, int fromtr
                return -1;
        }
 
-       iax2_lock_owner(fr->callno);
-       if (!iaxs[fr->callno]) {
-               /* The call dissappeared so discard this frame that we could not send. */
-               iax2_frame_free(fr);
-               return -1;
-       }
-       if ((owner = iaxs[fr->callno]->owner))
-               bridge = ast_bridged_channel(owner);
-
-       /* if the user hasn't requested we force the use of the jitterbuffer, and we're bridged to
-        * a channel that can accept jitter, then flush and suspend the jb, and send this frame straight through */
-       if ( (!ast_test_flag64(iaxs[fr->callno], IAX_FORCEJITTERBUF)) && owner && bridge && (ast_channel_tech(bridge)->properties & AST_CHAN_TP_WANTSJITTER) ) {
-               jb_frame frame;
-
-               ast_channel_unlock(owner);
-
-               /* deliver any frames in the jb */
-               while (jb_getall(iaxs[fr->callno]->jb, &frame) == JB_OK) {
-                       __do_deliver(frame.data);
-                       /* __do_deliver() can make the call disappear */
-                       if (!iaxs[fr->callno])
-                               return -1;
-               }
-
-               jb_reset(iaxs[fr->callno]->jb);
-
-               AST_SCHED_DEL(sched, iaxs[fr->callno]->jbid);
-
-               /* deliver this frame now */
-               if (tsout)
-                       *tsout = fr->ts;
-               __do_deliver(fr);
-               return -1;
-       }
-       if (owner) {
-               ast_channel_unlock(owner);
-       }
-
        /* insert into jitterbuffer */
        /* TODO: Perhaps we could act immediately if it's not droppable and late */
        ret = jb_put(iaxs[fr->callno]->jb, fr, type, len, fr->ts,
@@ -4202,7 +4311,7 @@ static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int durati
 
 static int iax2_sendtext(struct ast_channel *c, const char *text)
 {
-       
+
        return send_command_locked(PTR_TO_CALLNO(ast_channel_tech_pvt(c)), AST_FRAME_TEXT,
                0, 0, (unsigned char *)text, strlen(text) + 1, -1);
 }
@@ -4233,22 +4342,25 @@ static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newcha
  * \note This function calls reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this with a pvt lock held.
  */
-static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in *sin)
+static struct iax2_peer *realtime_peer(const char *peername, struct ast_sockaddr *addr)
 {
        struct ast_variable *var = NULL;
        struct ast_variable *tmp;
        struct iax2_peer *peer=NULL;
        time_t regseconds = 0, nowtime;
        int dynamic=0;
+       char *str_addr, *str_port;
+
+       str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+       str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
        if (peername) {
                var = ast_load_realtime("iaxpeers", "name", peername, "host", "dynamic", SENTINEL);
-               if (!var && sin)
-                       var = ast_load_realtime("iaxpeers", "name", peername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
-       } else if (sin) {
-               char porta[25];
-               sprintf(porta, "%d", ntohs(sin->sin_port));
-               var = ast_load_realtime("iaxpeers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+               if (!var && !ast_sockaddr_isnull(addr)) {
+                       var = ast_load_realtime("iaxpeers", "name", peername, "host", str_addr, SENTINEL);
+               }
+       } else if (!ast_sockaddr_isnull(addr)) {
+               var = ast_load_realtime("iaxpeers", "ipaddr", str_addr, "port", str_port, SENTINEL);
                if (var) {
                        /* We'll need the peer name in order to build the structure! */
                        for (tmp = var; tmp; tmp = tmp->next) {
@@ -4265,16 +4377,18 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
                 * is because we only have the IP address and the host field might be
                 * set as a name (and the reverse PTR might not match).
                 */
-               if (var && sin) {
+               if (var && !ast_sockaddr_isnull(addr)) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_hostent ahp;
-                                       struct hostent *hp;
-                                       if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
+                                       struct ast_sockaddr *hostaddr = NULL;
+
+                                       if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
+                                               || ast_sockaddr_cmp_addr(hostaddr, addr)) {
                                                /* No match */
                                                ast_variables_destroy(var);
                                                var = NULL;
                                        }
+                                       ast_free(hostaddr);
                                        break;
                                }
                        }
@@ -4302,11 +4416,19 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
                } else if (!strcasecmp(tmp->name, "regseconds")) {
                        ast_get_time_t(tmp->value, &regseconds, 0, NULL);
                } else if (!strcasecmp(tmp->name, "ipaddr")) {
-                       if (!ast_sockaddr_parse(&peer->addr, tmp->value, PARSE_PORT_IGNORE)) {
+                       int setport = ast_sockaddr_port(&peer->addr);
+                       if (ast_parse_arg(tmp->value, PARSE_ADDR | PARSE_PORT_FORBID, NULL)) {
                                ast_log(LOG_WARNING, "Failed to parse sockaddr '%s' for ipaddr of realtime peer '%s'\n", tmp->value, tmp->name);
+                       } else {
+                               ast_sockaddr_parse(&peer->addr, tmp->value, 0);
                        }
+                       ast_sockaddr_set_port(&peer->addr, setport);
                } else if (!strcasecmp(tmp->name, "port")) {
-                       ast_sockaddr_set_port(&peer->addr, atoi(tmp->value));
+                       int bindport;
+                       if (ast_parse_arg(tmp->value, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
+                               bindport = IAX_DEFAULT_PORTNO;
+                       }
+                       ast_sockaddr_set_port(&peer->addr, bindport);
                } else if (!strcasecmp(tmp->name, "host")) {
                        if (!strcasecmp(tmp->value, "dynamic"))
                                dynamic = 1;
@@ -4315,9 +4437,6 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
 
        ast_variables_destroy(var);
 
-       if (!peer)
-               return NULL;
-
        if (ast_test_flag64((&globalflags), IAX_RTCACHEFRIENDS)) {
                ast_copy_flags64(peer, &globalflags, IAX_RTAUTOCLEAR|IAX_RTCACHEFRIENDS);
                if (ast_test_flag64(peer, IAX_RTAUTOCLEAR)) {
@@ -4355,21 +4474,23 @@ static struct iax2_peer *realtime_peer(const char *peername, struct sockaddr_in
        return peer;
 }
 
-static struct iax2_user *realtime_user(const char *username, struct sockaddr_in *sin)
+static struct iax2_user *realtime_user(const char *username, struct ast_sockaddr *addr)
 {
        struct ast_variable *var;
        struct ast_variable *tmp;
        struct iax2_user *user=NULL;
+       char *str_addr, *str_port;
+
+       str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
+       str_port = ast_strdupa(ast_sockaddr_stringify_port(addr));
 
        var = ast_load_realtime("iaxusers", "name", username, "host", "dynamic", SENTINEL);
        if (!var)
-               var = ast_load_realtime("iaxusers", "name", username, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL);
-       if (!var && sin) {
-               char porta[6];
-               snprintf(porta, sizeof(porta), "%d", ntohs(sin->sin_port));
-               var = ast_load_realtime("iaxusers", "name", username, "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+               var = ast_load_realtime("iaxusers", "name", username, "host", str_addr, SENTINEL);
+       if (!var && !ast_sockaddr_isnull(addr)) {
+               var = ast_load_realtime("iaxusers", "name", username, "ipaddr", str_addr, "port", str_port, SENTINEL);
                if (!var)
-                       var = ast_load_realtime("iaxusers", "ipaddr", ast_inet_ntoa(sin->sin_addr), "port", porta, SENTINEL);
+                       var = ast_load_realtime("iaxusers", "ipaddr", str_addr, "port", str_port, SENTINEL);
        }
        if (!var) { /* Last ditch effort */
                var = ast_load_realtime("iaxusers", "name", username, SENTINEL);
@@ -4382,13 +4503,15 @@ static struct iax2_user *realtime_user(const char *username, struct sockaddr_in
                if (var) {
                        for (tmp = var; tmp; tmp = tmp->next) {
                                if (!strcasecmp(tmp->name, "host")) {
-                                       struct ast_hostent ahp;
-                                       struct hostent *hp;
-                                       if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || memcmp(hp->h_addr, &sin->sin_addr, hp->h_length)) {
+                                       struct ast_sockaddr *hostaddr = NULL;
+
+                                       if (!ast_sockaddr_resolve(&hostaddr, tmp->value, PARSE_PORT_FORBID, AST_AF_UNSPEC)
+                                               || ast_sockaddr_cmp_addr(hostaddr, addr)) {
                                                /* No match */
                                                ast_variables_destroy(var);
                                                var = NULL;
                                        }
+                                       ast_free(hostaddr);
                                        break;
                                }
                        }
@@ -4404,7 +4527,7 @@ static struct iax2_user *realtime_user(const char *username, struct sockaddr_in
                        if (strcasecmp(tmp->value, "friend") &&
                            strcasecmp(tmp->value, "user")) {
                                return NULL;
-                       } 
+                       }
                }
                tmp = tmp->next;
        }
@@ -4428,10 +4551,10 @@ static struct iax2_user *realtime_user(const char *username, struct sockaddr_in
 
 static void realtime_update_peer(const char *peername, struct ast_sockaddr *sockaddr, time_t regtime)
 {
-       char port[10];
        char regseconds[20];
        const char *sysname = ast_config_AST_SYSTEM_NAME;
        char *syslabel = NULL;
+       char *port;
 
        if (ast_strlen_zero(sysname))   /* No system name, disable this */
                sysname = NULL;
@@ -4439,15 +4562,17 @@ static void realtime_update_peer(const char *peername, struct ast_sockaddr *sock
                syslabel = "regserver";
 
        snprintf(regseconds, sizeof(regseconds), "%d", (int)regtime);
-       snprintf(port, sizeof(port), "%d", ast_sockaddr_port(sockaddr));
-       ast_update_realtime("iaxpeers", "name", peername, 
-               "ipaddr", ast_sockaddr_stringify_addr(sockaddr), "port", port, 
+       port = ast_strdupa(ast_sockaddr_stringify_port(sockaddr));
+       ast_update_realtime("iaxpeers", "name", peername,
+               "ipaddr", ast_sockaddr_isnull(sockaddr) ? "" : ast_sockaddr_stringify_addr(sockaddr),
+               "port", ast_sockaddr_isnull(sockaddr) ? "" : port,
                "regseconds", regseconds, syslabel, sysname, SENTINEL); /* note syslable can be NULL */
 }
 
 struct create_addr_info {
        iax2_format capability;
        uint64_t flags;
+       struct iax2_codec_pref prefs;
        int maxtime;
        int encmethods;
        int found;
@@ -4457,7 +4582,6 @@ struct create_addr_info {
        char secret[80];
        char outkey[80];
        char timezone[80];
-       char prefs[32];
        char cid_num[80];
        char cid_name[80];
        char context[AST_MAX_CONTEXT];
@@ -4466,52 +4590,55 @@ struct create_addr_info {
        char mohsuggest[MAX_MUSICCLASS];
 };
 
-static int create_addr(const char *peername, struct ast_channel *c, struct sockaddr_in *sin, struct create_addr_info *cai)
+static int create_addr(const char *peername, struct ast_channel *c, struct ast_sockaddr *addr, struct create_addr_info *cai)
 {
        struct iax2_peer *peer;
        int res = -1;
-       struct ast_codec_pref ourprefs;
-       struct sockaddr_in peer_addr;
 
        ast_clear_flag64(cai, IAX_SENDANI | IAX_TRUNK);
        cai->sockfd = defaultsockfd;
        cai->maxtime = 0;
-       sin->sin_family = AF_INET;
 
        if (!(peer = find_peer(peername, 1))) {
-               struct ast_sockaddr sin_tmp;
+               struct ast_sockaddr peer_addr;
 
+               peer_addr.ss.ss_family = AST_AF_UNSPEC;
                cai->found = 0;
-               sin_tmp.ss.ss_family = AF_INET;
-               if (ast_get_ip_or_srv(&sin_tmp, peername, srvlookup ? "_iax._udp" : NULL)) {
+               if (ast_get_ip_or_srv(&peer_addr, peername, srvlookup ? "_iax._udp" : NULL)) {
                        ast_log(LOG_WARNING, "No such host: %s\n", peername);
                        return -1;
                }
-               ast_sockaddr_to_sin(&sin_tmp, sin);
-               if (sin->sin_port == 0) {
-                       sin->sin_port = htons(IAX_DEFAULT_PORTNO);
+
+               if (!ast_sockaddr_port(&peer_addr)) {
+                       ast_sockaddr_set_port(&peer_addr, IAX_DEFAULT_PORTNO);
                }
-               /* use global iax prefs for unknown peer/user */
-               /* But move the calling channel's native codec to the top of the preference list */
-               memcpy(&ourprefs, &prefs, sizeof(ourprefs));
+
+               ast_sockaddr_copy(addr, &peer_addr);
+               /*
+                * Use The global iax prefs for unknown peer/user.
+                * However, move the calling channel's native codec to
+                * the top of the preference list.
+                */
+               cai->prefs = prefs_global;
                if (c) {
-                       struct ast_format tmpfmt;
-                       ast_format_cap_iter_start(ast_channel_nativeformats(c));
-                       while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
-                               ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
+                       int i;
+
+                       for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
+                               struct ast_format *format = ast_format_cap_get_format(
+                                       ast_channel_nativeformats(c), i);
+                               iax2_codec_pref_prepend(&cai->prefs, format,
+                                       ast_format_cap_get_format_framing(ast_channel_nativeformats(c), format),
+                                       1);
+                               ao2_ref(format, -1);
                        }
-                       ast_format_cap_iter_end(ast_channel_nativeformats(c));
                }
-               ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
                return 0;
        }
 
        cai->found = 1;
 
-       ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
        /* if the peer has no address (current or default), return failure */
-       if (!(peer_addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr)) {
+       if (ast_sockaddr_isnull(&peer->addr) && ast_sockaddr_isnull(&peer->defaddr)) {
                goto return_unref;
        }
 
@@ -4519,24 +4646,26 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
        if (peer->maxms && ((peer->lastms > peer->maxms) || (peer->lastms < 0)))
                goto return_unref;
 
-       ast_copy_flags64(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
+       ast_copy_flags64(cai, peer, IAX_SENDANI | IAX_TRUNK | IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE | IAX_FORCE_ENCRYPT);
        cai->maxtime = peer->maxms;
        cai->capability = peer->capability;
        cai->encmethods = peer->encmethods;
        cai->sockfd = peer->sockfd;
        cai->adsi = peer->adsi;
-       memcpy(&ourprefs, &peer->prefs, sizeof(ourprefs));
+       cai->prefs = peer->prefs;
        /* Move the calling channel's native codec to the top of the preference list */
        if (c) {
-               struct ast_format tmpfmt;
-               ast_format_cap_iter_start(ast_channel_nativeformats(c));
-               while (!(ast_format_cap_iter_next(ast_channel_nativeformats(c), &tmpfmt))) {
-                       ast_debug(1, "prepending %s to prefs\n", ast_getformatname(&tmpfmt));
-                       ast_codec_pref_prepend(&ourprefs, &tmpfmt, 1);
+               int i;
+
+               for (i = 0; i < ast_format_cap_count(ast_channel_nativeformats(c)); i++) {
+                       struct ast_format *tmpfmt = ast_format_cap_get_format(
+                               ast_channel_nativeformats(c), i);
+                       iax2_codec_pref_prepend(&cai->prefs, tmpfmt,
+                               ast_format_cap_get_format_framing(ast_channel_nativeformats(c), tmpfmt),
+                               1);
+                       ao2_ref(tmpfmt, -1);
                }
-               ast_format_cap_iter_end(ast_channel_nativeformats(c));
        }
-       ast_codec_pref_convert(&ourprefs, cai->prefs, sizeof(cai->prefs), 1);
        ast_copy_string(cai->context, peer->context, sizeof(cai->context));
        ast_copy_string(cai->peercontext, peer->peercontext, sizeof(cai->peercontext));
        ast_copy_string(cai->username, peer->username, sizeof(cai->username));
@@ -4562,12 +4691,10 @@ static int create_addr(const char *peername, struct ast_channel *c, struct socka
                }
        }
 
-       if (peer_addr.sin_addr.s_addr) {
-               sin->sin_addr = peer_addr.sin_addr;
-               sin->sin_port = peer_addr.sin_port;
+       if (!ast_sockaddr_isnull(&peer->addr)) {
+               ast_sockaddr_copy(addr, &peer->addr);
        } else {
-               sin->sin_addr = peer->defaddr.sin_addr;
-               sin->sin_port = peer->defaddr.sin_port;
+               ast_sockaddr_copy(addr, &peer->defaddr);
        }
 
        res = 0;
@@ -4595,7 +4722,7 @@ static int auto_congest(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__auto_congest, data))
-#endif         
+#endif
                __auto_congest(data);
        return 0;
 }
@@ -4627,7 +4754,7 @@ struct parsed_dial_string {
 };
 
 static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
-               struct sockaddr_in *sin, int command, int ts, unsigned char seqno,
+               struct ast_sockaddr *addr, int command, int ts, unsigned char seqno,
                int sockfd, struct iax_ie_data *ied)
 {
        struct {
@@ -4649,9 +4776,9 @@ static int send_apathetic_reply(unsigned short callno, unsigned short dcallno,
        data.f.type = AST_FRAME_IAX;
        data.f.csub = compress_subclass(command);
 
-       iax_outputframe(NULL, &data.f, 0, sin, size - sizeof(struct ast_iax2_full_hdr));
+       iax_outputframe(NULL, &data.f, 0, addr, size - sizeof(struct ast_iax2_full_hdr));
 
-       return sendto(sockfd, &data, size, 0, (struct sockaddr *)sin, sizeof(*sin));
+       return ast_sendto(sockfd, &data, size, 0, addr);
 }
 
 static void add_empty_calltoken_ie(struct chan_iax2_pvt *pvt, struct iax_ie_data *ied)
@@ -4683,16 +4810,16 @@ static void resend_with_token(int callno, struct iax_frame *f, const char *newto
                return;  /* this should not be possible if called from socket_process() */
        }
 
-       /* 
+       /*
         * Check to make sure last frame sent is valid for call token resend
-        * 1. Frame should _NOT_ be encrypted since it starts the IAX dialog 
+        * 1. Frame should _NOT_ be encrypted since it starts the IAX dialog
         * 2. Frame should _NOT_ already have a destination callno
         * 3. Frame must be a valid iax_frame subclass capable of starting dialog
         * 4. Pvt must have a calltoken_ie_len which represents the number of
         *    bytes at the end of the frame used for the previous calltoken ie.
         * 5. Pvt's calltoken_ie_len must be _LESS_ than the total IE length
         * 6. Total length of f->data must be _LESS_ than size of our data struct
-        *    because f->data must be able to fit within data. 
+        *    because f->data must be able to fit within data.
         */
        if (f->encmethods || f->dcallno || !iax2_allow_new(frametype, subclass, 0)
                || !pvt->calltoken_ie_len || (pvt->calltoken_ie_len > ie_data_pos) ||
@@ -4773,9 +4900,9 @@ static void requirecalltoken_mark_auto(const char *name, int subclass)
  * \internal
  *
  * \brief handles calltoken logic for a received iax_frame.
- * 
+ *
  * \note frametype must be AST_FRAME_IAX.
- * 
+ *
  * \note
  * Three different cases are possible here.
  * Case 1. An empty calltoken is provided. This means the client supports
@@ -4787,9 +4914,9 @@ static void requirecalltoken_mark_auto(const char *name, int subclass)
  *         to decide how this should be handled (reject or permit without calltoken)
  */
 static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
-               struct sockaddr_in *sin, int fd)
+               struct ast_sockaddr *addr, int fd)
 {
-#define CALLTOKEN_HASH_FORMAT "%s%d%u%d"  /* address + port + ts + randomcalldata */
+#define CALLTOKEN_HASH_FORMAT "%s%u%d"  /* address + port + ts + randomcalldata */
 #define CALLTOKEN_IE_FORMAT   "%u?%s"     /* time + ? + (40 char hash) */
        struct ast_str *buf = ast_str_alloca(256);
        time_t t = time(NULL);
@@ -4804,12 +4931,12 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
                };
 
                /* create the hash with their address data and our timestamp */
-               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) t, randomcalltokendata);
+               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) t, randomcalltokendata);
                ast_sha1_hash(hash, ast_str_buffer(buf));
 
                ast_str_set(&buf, 0, CALLTOKEN_IE_FORMAT, (unsigned int) t, hash);
                iax_ie_append_str(&ied, IAX_IE_CALLTOKEN, ast_str_buffer(buf));
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_CALLTOKEN, ntohl(fh->ts), fh->iseqno + 1, fd, &ied);
 
                return 1;
 
@@ -4834,27 +4961,27 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
                }
 
                /* create a hash with their address and the _TOKEN'S_ timestamp */
-               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_inet_ntoa(sin->sin_addr), sin->sin_port, (unsigned int) rec_time, randomcalltokendata);
+               ast_str_set(&buf, 0, CALLTOKEN_HASH_FORMAT, ast_sockaddr_stringify(addr), (unsigned int) rec_time, randomcalltokendata);
                ast_sha1_hash(hash, ast_str_buffer(buf));
 
                /* compare hashes and then check timestamp delay */
                if (strcmp(hash, rec_hash)) {
-                       ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_WARNING, "Address %s failed CallToken hash inspection\n", ast_sockaddr_stringify(addr));
                        goto reject; /* received hash does not match ours, reject */
-               } else if ((t < rec_time) || ((t - rec_time) >= MAX_CALLTOKEN_DELAY)) {
-                       ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_inet_ntoa(sin->sin_addr));
+               } else if ((t < rec_time) || ((t - rec_time) >= max_calltoken_delay)) {
+                       ast_log(LOG_WARNING, "Too much delay in IAX2 calltoken timestamp from address %s\n", ast_sockaddr_stringify(addr));
                        goto reject; /* too much delay, reject */
                }
 
-               /* at this point the call token is valid, returning 0 
+               /* at this point the call token is valid, returning 0
                 * will allow socket_process to continue as usual */
                requirecalltoken_mark_auto(ies->username, subclass);
                return 0;
 
        /* ----- Case 3 ----- */
        } else { /* calltokens are not supported for this client, how do we respond? */
-               if (calltoken_required(sin, ies->username, subclass)) {
-                       ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_inet_ntoa(sin->sin_addr), S_OR(ies->username, "guest"));
+               if (calltoken_required(addr, ies->username, subclass)) {
+                       ast_log(LOG_ERROR, "Call rejected, CallToken Support required. If unexpected, resolve by placing address %s in the calltokenoptional list or setting user %s requirecalltoken=no\n", ast_sockaddr_stringify(addr), S_OR(ies->username, "guest"));
                        goto reject;
                }
                return 0; /* calltoken is not required for this addr, so permit it. */
@@ -4863,9 +4990,9 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 reject:
        /* received frame has failed calltoken inspection, send apathetic reject messages */
        if (subclass == IAX_COMMAND_REGREQ || subclass == IAX_COMMAND_REGREL) {
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
        } else {
-               send_apathetic_reply(1, ntohs(fh->scallno), sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+               send_apathetic_reply(1, ntohs(fh->scallno), addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
        }
 
        return 1;
@@ -4887,7 +5014,7 @@ reject:
  * password field will be set to NULL.
  *
  * \note The dial string format is:
- *       [username[:password]@]peer[:port][/exten[@@context]][/options]
+ *       [username[:password]@]peer[:port][/exten[@context]][/options]
  */
 static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 {
@@ -4920,9 +5047,10 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
        pds->peer = strsep(&data, ":");
        pds->port = data;
 
-       /* check for a key name wrapped in [] in the secret position, if found,
-          move it to the key field instead
-       */
+       /*
+        * Check for a key name wrapped in [] in the password position.
+        * If found, move it to the key field instead.
+        */
        if (pds->password && (pds->password[0] == '[')) {
                pds->key = ast_strip_quoted(pds->password, "[", "]");
                pds->password = NULL;
@@ -4931,7 +5059,7 @@ static void parse_dial_string(char *data, struct parsed_dial_string *pds)
 
 static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
 {
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        char *l=NULL, *n=NULL, *tmpstr;
        struct iax_ie_data ied;
        char *defaultrdest = "s";
@@ -4945,6 +5073,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        unsigned char osp_block_index;
        unsigned int osp_block_length;
        unsigned char osp_buffer[256];
+       char encoded_prefs[32];
        iax2_format iax2_tmpfmt;
 
        if ((ast_channel_state(c) != AST_STATE_DOWN) && (ast_channel_state(c) != AST_STATE_RESERVED)) {
@@ -4966,7 +5095,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        if (!pds.exten) {
                pds.exten = defaultrdest;
        }
-       if (create_addr(pds.peer, c, &sin, &cai)) {
+       if (create_addr(pds.peer, c, &addr, &cai)) {
                ast_log(LOG_WARNING, "No address associated with '%s'\n", pds.peer);
                return -1;
        }
@@ -4991,13 +5120,17 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        /* Keep track of the context for outgoing calls too */
        ast_channel_context_set(c, cai.context);
 
-       if (pds.port)
-               sin.sin_port = htons(atoi(pds.port));
+       if (pds.port) {
+               int bindport;
+               if (ast_parse_arg(pds.port, PARSE_UINT32 | PARSE_IN_RANGE, &bindport, 0, 65535)) {
+                       ast_sockaddr_set_port(&addr, bindport);
+               }
+       }
 
        l = ast_channel_connected(c)->id.number.valid ? ast_channel_connected(c)->id.number.str : NULL;
        n = ast_channel_connected(c)->id.name.valid ? ast_channel_connected(c)->id.name.str : NULL;
 
-       /* Now build request */ 
+       /* Now build request */
        memset(&ied, 0, sizeof(ied));
 
        /* On new call, first IE MUST be IAX version of caller */
@@ -5009,7 +5142,8 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        }
 
        /* WARNING: this breaks down at 190 bits! */
-       iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, cai.prefs);
+       iax2_codec_pref_convert(&cai.prefs, encoded_prefs, sizeof(encoded_prefs), 1);
+       iax_ie_append_str(&ied, IAX_IE_CODEC_PREFS, encoded_prefs);
 
        if (l) {
                iax_ie_append_str(&ied, IAX_IE_CALLING_NUMBER, l);
@@ -5063,7 +5197,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        iaxs[callno]->encmethods = cai.encmethods;
 
        iaxs[callno]->adsi = cai.adsi;
-       
+
        ast_string_field_set(iaxs[callno], mohinterpret, cai.mohinterpret);
        ast_string_field_set(iaxs[callno], mohsuggest, cai.mohsuggest);
 
@@ -5072,7 +5206,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
        if (pds.password)
                ast_string_field_set(iaxs[callno], secret, pds.password);
 
-       iax2_tmpfmt = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(c));
+       iax2_tmpfmt = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(c));
        iax_ie_append_int(&ied, IAX_IE_FORMAT, (int) iax2_tmpfmt);
        iax_ie_append_versioned_uint64(&ied, IAX_IE_FORMAT2, 0, iax2_tmpfmt);
 
@@ -5103,7 +5237,7 @@ static int iax2_call(struct ast_channel *c, const char *dest, int timeout)
                                osp_block_index++;
                                osp_token_ptr += osp_block_length;
                                osp_token_length -= osp_block_length;
-                       } 
+                       }
                } else
                        ast_log(LOG_WARNING, "OSP token is too long\n");
        } else if (iaxdebug)
@@ -5296,7 +5430,7 @@ static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *
        }
 }
 
-static struct ast_frame *iax2_read(struct ast_channel *c) 
+static struct ast_frame *iax2_read(struct ast_channel *c)
 {
        ast_debug(1, "I should never be called!\n");
        return &ast_null_frame;
@@ -5315,7 +5449,7 @@ static int iax2_key_rotate(const void *vpvt)
        ast_mutex_lock(&iaxsl[pvt->callno]);
        pvt->keyrotateid = ast_sched_add(sched, 120000 + (ast_random() % 180001), iax2_key_rotate, vpvt);
 
-       snprintf(key, sizeof(key), "%lX", ast_random());
+       snprintf(key, sizeof(key), "%lX", (unsigned long)ast_random());
 
        MD5Init(&md5);
        MD5Update(&md5, (unsigned char *) key, strlen(key));
@@ -5334,6 +5468,7 @@ static int iax2_key_rotate(const void *vpvt)
        return res;
 }
 
+#if defined(IAX2_NATIVE_BRIDGING)
 static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, int mediaonly)
 {
        int res;
@@ -5368,7 +5503,9 @@ static int iax2_start_transfer(unsigned short callno0, unsigned short callno1, i
        iaxs[callno1]->transferring = mediaonly ? TRANSFER_MBEGIN : TRANSFER_BEGIN;
        return 0;
 }
+#endif /* defined(IAX2_NATIVE_BRIDGING) */
 
+#if defined(IAX2_NATIVE_BRIDGING)
 static void lock_both(unsigned short callno0, unsigned short callno1)
 {
        ast_mutex_lock(&iaxsl[callno0]);
@@ -5376,13 +5513,17 @@ static void lock_both(unsigned short callno0, unsigned short callno1)
                DEADLOCK_AVOIDANCE(&iaxsl[callno0]);
        }
 }
+#endif /* defined(IAX2_NATIVE_BRIDGING) */
 
+#if defined(IAX2_NATIVE_BRIDGING)
 static void unlock_both(unsigned short callno0, unsigned short callno1)
 {
        ast_mutex_unlock(&iaxsl[callno1]);
        ast_mutex_unlock(&iaxsl[callno0]);
 }
+#endif /* defined(IAX2_NATIVE_BRIDGING) */
 
+#if defined(IAX2_NATIVE_BRIDGING)
 static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 {
        struct ast_channel *cs[3];
@@ -5435,11 +5576,13 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                        return AST_BRIDGE_FAILED_NOWARN;
                }
                if (!(ast_format_cap_identical(ast_channel_nativeformats(c0), ast_channel_nativeformats(c1)))) {
-                       char buf0[256];
-                       char buf1[256];
-                       ast_getformatname_multiple(buf0, sizeof(buf0), ast_channel_nativeformats(c0));
-                       ast_getformatname_multiple(buf1, sizeof(buf1), ast_channel_nativeformats(c1));
-                       ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n", buf0, buf1);
+                       struct ast_str *c0_buf = ast_str_alloca(64);
+                       struct ast_str *c1_buf = ast_str_alloca(64);
+
+                       ast_verb(3, "Operating with different codecs [%s] [%s] , can't native bridge...\n",
+                               ast_format_cap_get_names(ast_channel_nativeformats(c0), &c0_buf),
+                               ast_format_cap_get_names(ast_channel_nativeformats(c1), &c1_buf));
+
                        /* Remove from native mode */
                        lock_both(callno0, callno1);
                        if (iaxs[callno0])
@@ -5449,7 +5592,7 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                        unlock_both(callno0, callno1);
                        return AST_BRIDGE_FAILED_NOWARN;
                }
-               /* check if transfered and if we really want native bridging */
+               /* check if transferred and if we really want native bridging */
                if (!transferstarted && !ast_test_flag64(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag64(iaxs[callno1], IAX_NOTRANSFER)) {
                        /* Try the transfer */
                        if (iax2_start_transfer(callno0, callno1, (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) ||
@@ -5502,35 +5645,44 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
                        break;
                }
                other = (who == c0) ? c1 : c0;  /* the 'other' channel */
-               if ((f->frametype == AST_FRAME_CONTROL)) {
-                       if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+               if (f->frametype == AST_FRAME_CONTROL) {
+                       switch (f->subclass.integer) {
+                       case AST_CONTROL_VIDUPDATE:
+                       case AST_CONTROL_SRCUPDATE:
+                       case AST_CONTROL_SRCCHANGE:
+                       case AST_CONTROL_T38_PARAMETERS:
+                               ast_write(other, f);
+                               break;
+                       case AST_CONTROL_PVT_CAUSE_CODE:
                                ast_channel_hangupcause_hash_set(other, f->data.ptr, f->datalen);
-                       } else if (!(flags & AST_BRIDGE_IGNORE_SIGS)
-                               && (f->subclass.integer != AST_CONTROL_SRCUPDATE)) {
+                               break;
+                       default:
                                *fo = f;
                                *rc = who;
-                               res =  AST_BRIDGE_COMPLETE;
+                               res = AST_BRIDGE_COMPLETE;
                                break;
                        }
-               }
-               if ((f->frametype == AST_FRAME_VOICE) ||
-                       (f->frametype == AST_FRAME_TEXT) ||
-                       (f->frametype == AST_FRAME_VIDEO) || 
-                       (f->frametype == AST_FRAME_IMAGE) ||
-                       (f->frametype == AST_FRAME_DTMF) ||
-                       (f->frametype == AST_FRAME_CONTROL && f->subclass.integer != AST_CONTROL_PVT_CAUSE_CODE)) {
+                       if (res == AST_BRIDGE_COMPLETE) {
+                               break;
+                       }
+               } else if (f->frametype == AST_FRAME_VOICE
+                       || f->frametype == AST_FRAME_TEXT
+                       || f->frametype == AST_FRAME_VIDEO
+                       || f->frametype == AST_FRAME_IMAGE) {
+                       ast_write(other, f);
+               } else if (f->frametype == AST_FRAME_DTMF) {
                        /* monitored dtmf take out of the bridge.
                         * check if we monitor the specific source.
                         */
                        int monitored_source = (who == c0) ? AST_BRIDGE_DTMF_CHANNEL_0 : AST_BRIDGE_DTMF_CHANNEL_1;
-                       if (f->frametype == AST_FRAME_DTMF && (flags & monitored_source)) {
+
+                       if (flags & monitored_source) {
                                *rc = who;
                                *fo = f;
                                res = AST_BRIDGE_COMPLETE;
                                /* Remove from native mode */
                                break;
                        }
-                       /* everything else goes to the other side */
                        ast_write(other, f);
                }
                ast_frfree(f);
@@ -5547,15 +5699,12 @@ static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_cha
        unlock_both(callno0, callno1);
        return res;
 }
+#endif /* defined(IAX2_NATIVE_BRIDGING) */
 
 static int iax2_answer(struct ast_channel *c)
 {
        unsigned short callno = PTR_TO_CALLNO(ast_channel_tech_pvt(c));
        ast_debug(1, "Answering IAX2 call\n");
-       ast_mutex_lock(&iaxsl[callno]);
-       if (iaxs[callno])
-               iax2_ami_channelupdate(iaxs[callno]);
-       ast_mutex_unlock(&iaxsl[callno]);
        return send_command_locked(callno, AST_FRAME_CONTROL, AST_CONTROL_ANSWER, 0, NULL, 0, -1);
 }
 
@@ -5590,10 +5739,16 @@ static int iax2_indicate(struct ast_channel *c, int condition, const void *data,
                }
                break;
        case AST_CONTROL_CONNECTED_LINE:
-               if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE))
+       case AST_CONTROL_REDIRECTING:
+               if (!ast_test_flag64(pvt, IAX_SENDCONNECTEDLINE)) {
+                       /* We are not configured to allow sending these updates. */
+                       ast_debug(2, "Callno %d: Config blocked sending control frame %d.\n",
+                               callno, condition);
                        goto done;
+               }
                break;
        case AST_CONTROL_PVT_CAUSE_CODE:
+       case AST_CONTROL_MASQUERADE_NOTIFY:
                res = -1;
                goto done;
        }
@@ -5626,7 +5781,7 @@ static int iax2_transfer(struct ast_channel *c, const char *dest)
        return send_command_locked(callno, AST_FRAME_IAX, IAX_COMMAND_TRANSFER, 0, ied.buf, ied.pos, -1);
 }
 
-static int iax2_getpeertrunk(struct sockaddr_in sin)
+static int iax2_getpeertrunk(struct ast_sockaddr addr)
 {
        struct iax2_peer *peer;
        int res = 0;
@@ -5634,12 +5789,8 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
 
        i = ao2_iterator_init(peers, 0);
        while ((peer = ao2_iterator_next(&i))) {
-               struct sockaddr_in peer_addr;
-
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
 
-               if ((peer_addr.sin_addr.s_addr == sin.sin_addr.s_addr) &&
-                   (peer_addr.sin_port == sin.sin_port)) {
+               if (!ast_sockaddr_cmp(&peer->addr, &addr)) {
                        res = ast_test_flag64(peer, IAX_TRUNK);
                        peer_unref(peer);
                        break;
@@ -5652,50 +5803,102 @@ static int iax2_getpeertrunk(struct sockaddr_in sin)
 }
 
 /*! \brief  Create new call, interface with the PBX core */
-static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability, const char *linkedid, unsigned int cachable)
+static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capability,
+       struct iax2_codec_pref *prefs, const struct ast_assigned_ids *assignedids,
+       const struct ast_channel *requestor, unsigned int cachable)
 {
-       struct ast_channel *tmp;
+       struct ast_channel *tmp = NULL;
        struct chan_iax2_pvt *i;
+       struct iax2_peer *peer;
        struct ast_variable *v = NULL;
-       struct ast_format tmpfmt;
-       struct ast_callid *callid;
+       struct ast_format_cap *native;
+       struct ast_format *tmpfmt;
+       ast_callid callid;
+       char *peer_name = NULL;
 
        if (!(i = iaxs[callno])) {
                ast_log(LOG_WARNING, "No IAX2 pvt found for callno '%d' !\n", callno);
                return NULL;
        }
 
-       /* Don't hold call lock */
+       if (!capability) {
+               ast_log(LOG_WARNING, "No formats specified for call to: IAX2/%s-%d\n",
+                       i->host, i->callno);
+               return NULL;
+       }
+       native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+       if (!native) {
+               return NULL;
+       }
+       if (iax2_codec_pref_best_bitfield2cap(capability, prefs, native)
+               || !ast_format_cap_count(native)) {
+               ast_log(LOG_WARNING, "No requested formats available for call to: IAX2/%s-%d\n",
+                       i->host, i->callno);
+               ao2_ref(native, -1);
+               return NULL;
+       }
+
+       if (!ast_strlen_zero(i->peer)) {
+               peer_name = ast_strdupa(i->peer);
+       } else if (!ast_strlen_zero(i->host)) {
+               peer_name = ast_strdupa(i->host);
+       }
+
+       /* Don't hold call lock while making a channel or looking up a peer */
        ast_mutex_unlock(&iaxsl[callno]);
-       tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, linkedid, i->amaflags, "IAX2/%s-%d", i->host, i->callno);
+
+       if (!ast_strlen_zero(peer_name)) {
+               peer = find_peer(peer_name, 1);
+               if (peer && peer->endpoint) {
+                       tmp = ast_channel_alloc_with_endpoint(1, state, i->cid_num, i->cid_name,
+                               i->accountcode, i->exten, i->context, assignedids, requestor,
+                               i->amaflags, peer->endpoint, "IAX2/%s-%d", i->host, i->callno);
+               }
+               ao2_cleanup(peer);
+       }
+
+       if (!tmp) {
+               tmp = ast_channel_alloc(1, state, i->cid_num, i->cid_name, i->accountcode,
+                       i->exten, i->context, assignedids, requestor, i->amaflags, "IAX2/%s-%d",
+                       i->host, i->callno);
+       }
+
        ast_mutex_lock(&iaxsl[callno]);
        if (i != iaxs[callno]) {
                if (tmp) {
                        /* unlock and relock iaxsl[callno] to preserve locking order */
                        ast_mutex_unlock(&iaxsl[callno]);
+                       ast_channel_unlock(tmp);
                        tmp = ast_channel_release(tmp);
                        ast_mutex_lock(&iaxsl[callno]);
                }
+               ao2_ref(native, -1);
                return NULL;
        }
-       iax2_ami_channelupdate(i);
        if (!tmp) {
+               ao2_ref(native, -1);
                return NULL;
        }
 
+       ast_channel_stage_snapshot(tmp);
+
        if ((callid = iaxs[callno]->callid)) {
                ast_channel_callid_set(tmp, callid);
        }
 
        ast_channel_tech_set(tmp, &iax2_tech);
+
        /* We can support any format by default, until we get restricted */
-       ast_format_cap_from_old_bitfield(ast_channel_nativeformats(tmp), capability);
-       ast_best_codec(ast_channel_nativeformats(tmp), &tmpfmt);
+       ast_channel_nativeformats_set(tmp, native);
+       tmpfmt = ast_format_cap_get_format(native, 0);
 
-       ast_format_copy(ast_channel_readformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_rawreadformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_writeformat(tmp), &tmpfmt);
-       ast_format_copy(ast_channel_rawwriteformat(tmp), &tmpfmt);
+       ast_channel_set_readformat(tmp, tmpfmt);
+       ast_channel_set_rawreadformat(tmp, tmpfmt);
+       ast_channel_set_writeformat(tmp, tmpfmt);
+       ast_channel_set_rawwriteformat(tmp, tmpfmt);
+
+       ao2_ref(tmpfmt, -1);
+       ao2_ref(native, -1);
 
        ast_channel_tech_pvt_set(tmp, CALLNO_TO_PTR(i->callno));
 
@@ -5780,11 +5983,16 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
                }
        }
 
+       ast_channel_stage_snapshot_done(tmp);
+       ast_channel_unlock(tmp);
+
        if (state != AST_STATE_DOWN) {
                if (ast_pbx_start(tmp)) {
                        ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
+                       /* unlock and relock iaxsl[callno] to preserve locking order */
+                       ast_mutex_unlock(&iaxsl[callno]);
                        ast_hangup(tmp);
-                       i->owner = NULL;
+                       ast_mutex_lock(&iaxsl[callno]);
                        return NULL;
                }
        }
@@ -5807,14 +6015,14 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
        }
        /* Update last transmit time now */
        tpeer->lasttxtime = *now;
-       
+
        /* Calculate ms offset */
        ms = ast_tvdiff_ms(*now, tpeer->txtrunktime);
        /* Predict from last value */
        pred = tpeer->lastsent + sampms;
-       if (abs(ms - pred) < MAX_TIMESTAMP_SKEW)
+       if (labs(ms - pred) < MAX_TIMESTAMP_SKEW)
                ms = pred;
-       
+
        /* We never send the same timestamp twice, so fudge a little if we must */
        if (ms == tpeer->lastsent)
                ms = tpeer->lastsent + 1;
@@ -5843,7 +6051,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
        int voice = 0;
        int genuine = 0;
        int adjust;
-       int rate = ast_format_rate(&f->subclass.format) / 1000;
+       int rate = 0;
        struct timeval *delivery = NULL;
 
 
@@ -5855,6 +6063,7 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
        */
        if (f->frametype == AST_FRAME_VOICE) {
                voice = 1;
+               rate = ast_format_get_sample_rate(f->subclass.format) / 1000;
                delivery = &f->delivery;
        } else if (f->frametype == AST_FRAME_IAX) {
                genuine = 1;
@@ -5884,13 +6093,14 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                        ms = 0;
                if (voice) {
                        /* On a voice frame, use predicted values if appropriate */
-                       if (p->notsilenttx && abs(ms - p->nextpred) <= MAX_TIMESTAMP_SKEW) {
+                       adjust = (ms - p->nextpred);
+                       if (p->notsilenttx && abs(adjust) <= MAX_TIMESTAMP_SKEW) {
                                /* Adjust our txcore, keeping voice and non-voice synchronized */
                                /* AN EXPLANATION:
                                   When we send voice, we usually send "calculated" timestamps worked out
                                   on the basis of the number of samples sent. When we send other frames,
                                   we usually send timestamps worked out from the real clock.
-                                  The problem is that they can tend to drift out of step because the 
+                                  The problem is that they can tend to drift out of step because the
                                   source channel's clock and our clock may not be exactly at the same rate.
                                   We fix this by continuously "tweaking" p->offset.  p->offset is "time zero"
                                   for this call.  Moving it adjusts timestamps for non-voice frames.
@@ -5901,9 +6111,8 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                   The use of a moving average avoids offset moving too radically.
                                   Generally, "adjust" roams back and forth around 0, with offset hardly
                                   changing at all.  But if a consistent different starts to develop it
-                                  will be eliminated over the course of 10 frames (200-300msecs) 
+                                  will be eliminated over the course of 10 frames (200-300msecs)
                                */
-                               adjust = (ms - p->nextpred);
                                if (adjust < 0)
                                        p->offset = ast_tvsub(p->offset, ast_samp2tv(abs(adjust), 10000));
                                else if (adjust > 0)
@@ -5925,9 +6134,9 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                * silent periods are multiples of
                                * frame size too) */
 
-                               if (iaxdebug && abs(ms - p->nextpred) > MAX_TIMESTAMP_SKEW )
-                                       ast_debug(1, "predicted timestamp skew (%u) > max (%u), using real ts instead.\n",
-                                               abs(ms - p->nextpred), MAX_TIMESTAMP_SKEW);
+                               if (iaxdebug && abs(adjust) > MAX_TIMESTAMP_SKEW )
+                                       ast_debug(1, "predicted timestamp skew (%d) > max (%d), using real ts instead.\n",
+                                               abs(adjust), MAX_TIMESTAMP_SKEW);
 
                                if (f->samples >= rate) /* check to make sure we don't core dump */
                                {
@@ -5953,19 +6162,21 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                } else {
                        /* On a dataframe, use last value + 3 (to accomodate jitter buffer shrinking) if appropriate unless
                           it's a genuine frame */
+                       adjust = (ms - p->lastsent);
                        if (genuine) {
                                /* genuine (IAX LAGRQ etc) must keep their clock-based stamps */
                                if (ms <= p->lastsent)
                                        ms = p->lastsent + 3;
-                       } else if (abs(ms - p->lastsent) <= MAX_TIMESTAMP_SKEW) {
+                       } else if (abs(adjust) <= MAX_TIMESTAMP_SKEW) {
                                /* non-genuine frames (!?) (DTMF, CONTROL) should be pulled into the predicted stream stamps */
                                ms = p->lastsent + 3;
                        }
                }
        }
        p->lastsent = ms;
-       if (voice)
+       if (voice) {
                p->nextpred = p->nextpred + f->samples / rate;
+       }
        return ms;
 }
 
@@ -5981,7 +6192,7 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
        if (ast_tvzero(p->rxcore)) {
                p->rxcore = ast_tvnow();
                if (iaxdebug)
-                       ast_debug(1, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %dms\n",
+                       ast_debug(1, "calc_rxstamp: call=%d: rxcore set to %d.%6.6d - %ums\n",
                                        p->callno, (int)(p->rxcore.tv_sec), (int)(p->rxcore.tv_usec), offset);
                p->rxcore = ast_tvsub(p->rxcore, ast_samp2tv(offset, 1000));
 #if 1
@@ -6009,15 +6220,15 @@ static unsigned int calc_rxstamp(struct chan_iax2_pvt *p, unsigned int offset)
        return ms;
 }
 
-static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
+static struct iax2_trunk_peer *find_tpeer(struct ast_sockaddr *addr, int fd)
 {
        struct iax2_trunk_peer *tpeer = NULL;
-       
+
        /* Finds and locks trunk peer */
        AST_LIST_LOCK(&tpeers);
 
        AST_LIST_TRAVERSE(&tpeers, tpeer, list) {
-               if (!inaddrcmp(&tpeer->addr, sin)) {
+               if (!ast_sockaddr_cmp(&tpeer->addr, addr)) {
                        ast_mutex_lock(&tpeer->lock);
                        break;
                }
@@ -6027,14 +6238,15 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
                if ((tpeer = ast_calloc(1, sizeof(*tpeer)))) {
                        ast_mutex_init(&tpeer->lock);
                        tpeer->lastsent = 9999;
-                       memcpy(&tpeer->addr, sin, sizeof(tpeer->addr));
+                       ast_sockaddr_copy(&tpeer->addr, addr);
                        tpeer->trunkact = ast_tvnow();
                        ast_mutex_lock(&tpeer->lock);
                        tpeer->sockfd = fd;
+
 #ifdef SO_NO_CHECK
                        setsockopt(tpeer->sockfd, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
 #endif
-                       ast_debug(1, "Created trunk peer for '%s:%d'\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
+                       ast_debug(1, "Created trunk peer for '%s'\n", ast_sockaddr_stringify(&tpeer->addr));
                        AST_LIST_INSERT_TAIL(&tpeers, tpeer, list);
                }
        }
@@ -6056,6 +6268,7 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
        f = &fr->af;
        tpeer = find_tpeer(&pvt->addr, pvt->sockfd);
        if (tpeer) {
+
                if (tpeer->trunkdatalen + f->datalen + 4 >= tpeer->trunkdataalloc) {
                        /* Need to reallocate space */
                        if (tpeer->trunkdataalloc < trunkmaxsize) {
@@ -6066,9 +6279,9 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
 
                                tpeer->trunkdataalloc += DEFAULT_TRUNKDATA;
                                tpeer->trunkdata = tmp;
-                               ast_debug(1, "Expanded trunk '%s:%d' to %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), tpeer->trunkdataalloc);
+                               ast_debug(1, "Expanded trunk '%s' to %u bytes\n", ast_sockaddr_stringify(&tpeer->addr), tpeer->trunkdataalloc);
                        } else {
-                               ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s:%d\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port));
+                               ast_log(LOG_WARNING, "Maximum trunk data space exceeded to %s\n", ast_sockaddr_stringify(&tpeer->addr));
                                ast_mutex_unlock(&tpeer->lock);
                                return -1;
                        }
@@ -6099,14 +6312,14 @@ static int iax2_trunk_queue(struct chan_iax2_pvt *pvt, struct iax_frame *fr)
                tpeer->calls++;
 
                /* track the largest mtu we actually have sent */
-               if (tpeer->trunkdatalen + f->datalen + 4 > trunk_maxmtu) 
-                       trunk_maxmtu = tpeer->trunkdatalen + f->datalen + 4 ; 
+               if (tpeer->trunkdatalen + f->datalen + 4 > trunk_maxmtu)
+                       trunk_maxmtu = tpeer->trunkdatalen + f->datalen + 4 ;
 
                /* if we have enough for a full MTU, ship it now without waiting */
                if (global_max_trunk_mtu > 0 && tpeer->trunkdatalen + f->datalen + 4 >= global_max_trunk_mtu) {
                        now = ast_tvnow();
-                       send_trunk(tpeer, &now); 
-                       trunk_untimed ++; 
+                       send_trunk(tpeer, &now);
+                       trunk_untimed ++;
                }
 
                ast_mutex_unlock(&tpeer->lock);
@@ -6151,7 +6364,7 @@ static void memcpy_decrypt(unsigned char *dst, const unsigned char *src, int len
                ast_log(LOG_WARNING, "len should be multiple of 16, not %d!\n", len);
        for (x=0;x<len;x++)
                dst[x] = src[x] ^ 0xff;
-#else  
+#else
        unsigned char lastblock[16] = { 0 };
        int x;
        while(len > 0) {
@@ -6182,7 +6395,7 @@ static void memcpy_encrypt(unsigned char *dst, const unsigned char *src, int len
                for (x=0;x<16;x++)
                        curblock[x] ^= src[x];
                ast_aes_encrypt(curblock, dst, ecx);
-               memcpy(curblock, dst, sizeof(curblock)); 
+               memcpy(curblock, dst, sizeof(curblock));
                dst += 16;
                src += 16;
                len -= 16;
@@ -6206,7 +6419,7 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
 
                padding = 16 + (workspace[15] & 0x0f);
                if (iaxdebug)
-                       ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02x)\n", *datalen, padding, workspace[15]);
+                       ast_debug(1, "Decoding full frame with length %d (padding = %d) (15=%02hhx)\n", *datalen, padding, workspace[15]);
                if (*datalen < padding + sizeof(struct ast_iax2_full_hdr))
                        return -1;
 
@@ -6214,9 +6427,9 @@ static int decode_frame(ast_aes_decrypt_key *dcx, struct ast_iax2_full_hdr *fh,
                memcpy(efh->encdata, workspace + padding, *datalen - sizeof(struct ast_iax2_full_enc_hdr));
                f->frametype = fh->type;
                if (f->frametype == AST_FRAME_VIDEO) {
-                       ast_format_from_old_bitfield(&f->subclass.format, (uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1)));
+                       f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40) | ((fh->csub >> 6) & 0x1));
                } else if (f->frametype == AST_FRAME_VOICE) {
-                       ast_format_from_old_bitfield(&f->subclass.format, uncompress_subclass(fh->csub));
+                       f->subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
                } else {
                        f->subclass.integer = uncompress_subclass(fh->csub);
                }
@@ -6253,7 +6466,7 @@ static int encrypt_frame(ast_aes_encrypt_key *ecx, struct ast_iax2_full_hdr *fh,
                workspace[15] &= 0xf0;
                workspace[15] |= (padding & 0xf);
                if (iaxdebug)
-                       ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02x)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
+                       ast_debug(1, "Encoding full frame %d/%d with length %d + %d padding (15=%02hhx)\n", fh->type, fh->csub, *datalen, padding, workspace[15]);
                *datalen += padding;
                memcpy_encrypt(efh->encdata, workspace, *datalen - sizeof(struct ast_iax2_full_enc_hdr), ecx);
                if (*datalen >= 32 + sizeof(struct ast_iax2_full_enc_hdr))
@@ -6299,7 +6512,7 @@ static int decrypt_frame(int callno, struct ast_iax2_full_hdr *fh, struct ast_fr
                                break;
                        }
                }
-       } else 
+       } else
                res = decode_frame(&iaxs[callno]->dcx, fh, f, datalen);
        return res;
 }
@@ -6328,7 +6541,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                ast_log(LOG_WARNING, "No private structure for packet?\n");
                return -1;
        }
-       
+
        lastsent = pvt->lastsent;
 
        /* Calculate actual timestamp */
@@ -6340,7 +6553,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
        if(f->frametype == AST_FRAME_VOICE && f->datalen == 0)
                return 0;
 #if 0
-       ast_log(LOG_NOTICE, 
+       ast_log(LOG_NOTICE,
                "f->frametype %c= AST_FRAME_VOICE, %sencrypted, %srotation scheduled...\n",
                *("=!" + (f->frametype == AST_FRAME_VOICE)),
                IAX_CALLENCRYPTED(pvt) ? "" : "not ",
@@ -6351,13 +6564,14 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                iax2_key_rotate(pvt);
        }
 
-       if ((ast_test_flag64(pvt, IAX_TRUNK) || 
+       if ((ast_test_flag64(pvt, IAX_TRUNK) ||
                        (((fts & 0xFFFF0000L) == (lastsent & 0xFFFF0000L)) ||
                        ((fts & 0xFFFF0000L) == ((lastsent + 0x10000) & 0xFFFF0000L))))
                /* High two bytes are the same on timestamp, or sending on a trunk */ &&
-           (f->frametype == AST_FRAME_VOICE) 
+           (f->frametype == AST_FRAME_VOICE)
                /* is a voice frame */ &&
-               (f->subclass.format.id == ast_format_id_from_old_bitfield(pvt->svoiceformat))
+               (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svoiceformat)) ==
+                       AST_FORMAT_CMP_EQUAL)
                /* is the same type */ ) {
                        /* Force immediate rather than delayed transmission */
                        now = 1;
@@ -6371,7 +6585,8 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                 * Otherwise send a mini video frame
                 */
                if (((fts & 0xFFFF8000L) == (pvt->lastvsent & 0xFFFF8000L)) &&
-                   ((f->subclass.format.id) == ast_format_id_from_old_bitfield(pvt->svideoformat))
+               (ast_format_cmp(f->subclass.format, ast_format_compatibility_bitfield2format(pvt->svideoformat)) ==
+                       AST_FORMAT_CMP_EQUAL)
                   ) {
                        now = 1;
                        sendmini = 1;
@@ -6426,11 +6641,11 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                fh->type = fr->af.frametype & 0xFF;
 
                if (fr->af.frametype == AST_FRAME_VIDEO) {
-                       iax2_format tmpfmt = ast_format_to_old_bitfield(&fr->af.subclass.format);
-                       tmpfmt |= ast_format_get_video_mark(&fr->af.subclass.format) ? 0x1LL : 0;
+                       iax2_format tmpfmt = ast_format_compatibility_format2bitfield(fr->af.subclass.format);
+                       tmpfmt |= fr->af.subclass.frame_ending ? 0x1LL : 0;
                        fh->csub = compress_subclass(tmpfmt | ((tmpfmt & 0x1LL) << 6));
                } else if (fr->af.frametype == AST_FRAME_VOICE) {
-                       fh->csub = compress_subclass(ast_format_to_old_bitfield(&fr->af.subclass.format));
+                       fh->csub = compress_subclass(ast_format_compatibility_format2bitfield(fr->af.subclass.format));
                } else {
                        fh->csub = compress_subclass(fr->af.subclass.integer);
                }
@@ -6453,9 +6668,9 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                if ((f->frametype == AST_FRAME_IAX) && (f->subclass.integer == IAX_COMMAND_ACK))
                        fr->retries = -1;
                else if (f->frametype == AST_FRAME_VOICE)
-                       pvt->svoiceformat = ast_format_to_old_bitfield(&f->subclass.format);
+                       pvt->svoiceformat = ast_format_compatibility_format2bitfield(f->subclass.format);
                else if (f->frametype == AST_FRAME_VIDEO)
-                       pvt->svideoformat = ast_format_to_old_bitfield(&f->subclass.format);
+                       pvt->svideoformat = ast_format_compatibility_format2bitfield(f->subclass.format);
                if (ast_test_flag64(pvt, IAX_ENCRYPTED)) {
                        if (ast_test_flag64(pvt, IAX_KEYPOPULATED)) {
                                if (fr->transfer)
@@ -6486,7 +6701,7 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                        vh = (struct ast_iax2_video_hdr *)(fr->af.data.ptr - sizeof(struct ast_iax2_video_hdr));
                        vh->zeros = 0;
                        vh->callno = htons(0x8000 | fr->callno);
-                       vh->ts = htons((fr->ts & 0x7FFF) | (ast_format_get_video_mark(&fr->af.subclass.format) ? 0x8000 : 0));
+                       vh->ts = htons((fr->ts & 0x7FFF) | (fr->af.subclass.frame_ending ? 0x8000 : 0));
                        fr->datalen = fr->af.datalen + sizeof(struct ast_iax2_video_hdr);
                        fr->data = vh;
                        fr->retries = -1;
@@ -6575,7 +6790,7 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
                else
                        pstr = ast_test_flag64(user, IAX_CODEC_USER_FIRST) ? "Caller" : "Host";
 
-               ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods, 
+               ast_cli(a->fd, FORMAT2, user->name, auth, user->authmethods,
                        user->contexts ? user->contexts->context : DEFAULT_CONTEXT,
                        ast_acl_list_is_empty(user->acl) ? "No" : "Yes", pstr);
        }
@@ -6589,50 +6804,168 @@ static char *handle_cli_iax2_show_users(struct ast_cli_entry *e, int cmd, struct
 #undef FORMAT2
 }
 
+struct show_peers_context {
+       regex_t regexbuf;
+       int havepattern;
+       char idtext[256];
+       int registeredonly;
+       int peerlist;
+       int total_peers;
+       int online_peers;
+       int offline_peers;
+       int unmonitored_peers;
+};
+
+#define PEERS_FORMAT2 "%-15.15s  %-40.40s %s   %-40.40s  %-9s %s  %-11s %-32.32s\n"
+#define PEERS_FORMAT "%-15.15s  %-40.40s %s  %-40.40s  %-6s%s %s  %-11s %-32.32s\n"
+
+static void _iax2_show_peers_one(int fd, struct mansession *s, struct show_peers_context *cont, struct iax2_peer *peer)
+{
+       char name[256] = "";
+       char status[20];
+       int retstatus;
+       struct ast_str *encmethods = ast_str_alloca(256);
+
+       char *tmp_host, *tmp_mask, *tmp_port;
+
+       tmp_host = ast_strdupa(ast_sockaddr_stringify_addr(&peer->addr));
+       tmp_mask = ast_strdupa(ast_sockaddr_stringify_addr(&peer->mask));
+       tmp_port = ast_strdupa(ast_sockaddr_stringify_port(&peer->addr));
+
+       if (!ast_strlen_zero(peer->username)) {
+               snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
+       } else {
+               ast_copy_string(name, peer->name, sizeof(name));
+       }
+
+       encmethods_to_str(peer->encmethods, &encmethods);
+       retstatus = peer_status(peer, status, sizeof(status));
+       if (retstatus > 0) {
+               cont->online_peers++;
+       } else if (!retstatus) {
+               cont->offline_peers++;
+       } else {
+               cont->unmonitored_peers++;
+       }
+
+       if (s) {
+               if (cont->peerlist) { /* IAXpeerlist */
+                       astman_append(s,
+                               "Event: PeerEntry\r\n%s"
+                               "Channeltype: IAX\r\n",
+                               cont->idtext);
+                       if (!ast_strlen_zero(peer->username)) {
+                               astman_append(s,
+                                       "ObjectName: %s\r\n"
+                                       "ObjectUsername: %s\r\n",
+                                       peer->name,
+                                       peer->username);
+                       } else {
+                               astman_append(s,
+                                       "ObjectName: %s\r\n",
+                                       name);
+                       }
+               } else { /* IAXpeers */
+                       astman_append(s,
+                               "Event: PeerEntry\r\n%s"
+                               "Channeltype: IAX2\r\n"
+                               "ObjectName: %s\r\n",
+                               cont->idtext,
+                               name);
+               }
+               astman_append(s,
+                       "ChanObjectType: peer\r\n"
+                       "IPaddress: %s\r\n",
+                       tmp_host);
+               if (cont->peerlist) { /* IAXpeerlist */
+                       astman_append(s,
+                               "Mask: %s\r\n"
+                               "Port: %s\r\n",
+                               tmp_mask,
+                               tmp_port);
+               } else { /* IAXpeers */
+                       astman_append(s,
+                               "IPport: %s\r\n",
+                               tmp_port);
+               }
+               astman_append(s,
+                       "Dynamic: %s\r\n"
+                       "Trunk: %s\r\n"
+                       "Encryption: %s\r\n"
+                       "Status: %s\r\n",
+                       ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
+                       ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
+                       peer->encmethods ? ast_str_buffer(encmethods) : "no",
+                       status);
+               if (cont->peerlist) { /* IAXpeerlist */
+                       astman_append(s, "\r\n");
+               } else { /* IAXpeers */
+                       astman_append(s,
+                               "Description: %s\r\n\r\n",
+                               peer->description);
+               }
+       } else {
+               ast_cli(fd, PEERS_FORMAT,
+                       name,
+                       tmp_host,
+                       ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
+                       tmp_mask,
+                       tmp_port,
+                       ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
+                       peer->encmethods ? "(E)" : "   ",
+                       status,
+                       peer->description);
+       }
+
+       cont->total_peers++;
+}
+
 static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int argc, const char * const argv[])
 {
-       regex_t regexbuf;
-       int havepattern = 0;
-       int total_peers = 0;
-       int online_peers = 0;
-       int offline_peers = 0;
-       int unmonitored_peers = 0;
-       struct ao2_iterator i;
+       struct show_peers_context cont = {
+               .havepattern = 0,
+               .idtext = "",
+               .registeredonly = 0,
+
+               .peerlist = 0,
 
-#define FORMAT2 "%-15.15s  %-15.15s %s  %-15.15s  %-8s  %s %-11s %-32.32s\n"
-#define FORMAT "%-15.15s  %-15.15s %s  %-15.15s  %-5d%s  %s %-11s %-32.32s\n"
+               .total_peers = 0,
+               .online_peers = 0,
+               .offline_peers = 0,
+               .unmonitored_peers = 0,
+       };
+
+       struct ao2_iterator i;
 
        struct iax2_peer *peer = NULL;
-       char name[256];
-       struct ast_str *encmethods = ast_str_alloca(256);
-       int registeredonly=0;
-       char idtext[256] = "";
+
        switch (argc) {
        case 6:
                if (!strcasecmp(argv[3], "registered"))
-                       registeredonly = 1;
+                       cont.registeredonly = 1;
                else
                        return RESULT_SHOWUSAGE;
                if (!strcasecmp(argv[4], "like")) {
-                       if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
+                       if (regcomp(&cont.regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
                                return RESULT_SHOWUSAGE;
-                       havepattern = 1;
+                       cont.havepattern = 1;
                } else
                        return RESULT_SHOWUSAGE;
                break;
        case 5:
                if (!strcasecmp(argv[3], "like")) {
-                       if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
+                       if (regcomp(&cont.regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
                                return RESULT_SHOWUSAGE;
-                       havepattern = 1;
+                       cont.havepattern = 1;
                } else
                        return RESULT_SHOWUSAGE;
                break;
        case 4:
-               if (!strcasecmp(argv[3], "registered"))
-                       registeredonly = 1;
-               else
+               if (!strcasecmp(argv[3], "registered")) {
+                       cont.registeredonly = 1;
+               } else {
                        return RESULT_SHOWUSAGE;
+               }
                break;
        case 3:
                break;
@@ -6641,92 +6974,43 @@ static int __iax2_show_peers(int fd, int *total, struct mansession *s, const int
        }
 
 
-       if (!s)
-               ast_cli(fd, FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
+       if (!s) {
+               ast_cli(fd, PEERS_FORMAT2, "Name/Username", "Host", "   ", "Mask", "Port", "   ", "Status", "Description");
+       }
 
        i = ao2_iterator_init(peers, 0);
        for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-               char nm[20];
-               char status[20];
-               int retstatus;
-               struct sockaddr_in peer_addr;
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               if (registeredonly && !peer_addr.sin_addr.s_addr) {
+               if (cont.registeredonly && ast_sockaddr_isnull(&peer->addr)) {
                        continue;
                }
-               if (havepattern && regexec(&regexbuf, peer->name, 0, NULL, 0)) {
+               if (cont.havepattern && regexec(&cont.regexbuf, peer->name, 0, NULL, 0)) {
                        continue;
                }
 
-               if (!ast_strlen_zero(peer->username))
-                       snprintf(name, sizeof(name), "%s/%s", peer->name, peer->username);
-               else
-                       ast_copy_string(name, peer->name, sizeof(name));
+               _iax2_show_peers_one(fd, s, &cont, peer);
 
-               encmethods_to_str(peer->encmethods, &encmethods);
-               retstatus = peer_status(peer, status, sizeof(status));
-               if (retstatus > 0)
-                       online_peers++;
-               else if (!retstatus)
-                       offline_peers++;
-               else
-                       unmonitored_peers++;
-
-               ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
-
-               if (s) {
-                       astman_append(s,
-                               "Event: PeerEntry\r\n%s"
-                               "Channeltype: IAX2\r\n"
-                               "ObjectName: %s\r\n"
-                               "ChanObjectType: peer\r\n"
-                               "IPaddress: %s\r\n"
-                               "IPport: %d\r\n"
-                               "Dynamic: %s\r\n"
-                               "Trunk: %s\r\n"
-                               "Encryption: %s\r\n"
-                               "Status: %s\r\n"
-                               "Description: %s\r\n\r\n",
-                               idtext,
-                               name,
-                               ast_sockaddr_stringify_addr(&peer->addr),
-                               ast_sockaddr_port(&peer->addr),
-                               ast_test_flag64(peer, IAX_DYNAMIC) ? "yes" : "no",
-                               ast_test_flag64(peer, IAX_TRUNK) ? "yes" : "no",
-                               peer->encmethods ? ast_str_buffer(encmethods) : "no",
-                               status,
-                               peer->description);
-               } else {
-                       ast_cli(fd, FORMAT, name,
-                               ast_sockaddr_stringify_addr(&peer->addr),
-                               ast_test_flag64(peer, IAX_DYNAMIC) ? "(D)" : "(S)",
-                               nm,
-                               ast_sockaddr_port(&peer->addr),
-                               ast_test_flag64(peer, IAX_TRUNK) ? "(T)" : "   ",
-                               peer->encmethods ? "(E)" : "   ",
-                               status,
-                               peer->description);
-               }
-               total_peers++;
        }
        ao2_iterator_destroy(&i);
 
-       if (!s)
+       if (!s) {
                ast_cli(fd,"%d iax2 peers [%d online, %d offline, %d unmonitored]\n",
-                       total_peers, online_peers, offline_peers, unmonitored_peers);
+                       cont.total_peers, cont.online_peers, cont.offline_peers, cont.unmonitored_peers);
+       }
 
-       if (havepattern)
-               regfree(&regexbuf);
+       if (cont.havepattern) {
+               regfree(&cont.regexbuf);
+       }
 
-       if (total)
-               *total = total_peers;
+       if (total) {
+               *total = cont.total_peers;
+       }
 
        return RESULT_SUCCESS;
-#undef FORMAT
-#undef FORMAT2
+
 }
+#undef PEERS_FORMAT2
+#undef PEERS_FORMAT
 
 static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -6747,17 +7031,17 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
        }
        if (a->argc != 3)
                return CLI_SHOWUSAGE;
-               
+
        ast_cli(a->fd, "IAX2 Thread Information\n");
        time(&t);
        ast_cli(a->fd, "Idle Threads:\n");
        AST_LIST_LOCK(&idle_list);
        AST_LIST_TRAVERSE(&idle_list, thread, list) {
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n", 
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n", 
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                threadcount++;
@@ -6771,10 +7055,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
                else
                        type = 'P';
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d, func='%s'\n", 
+               ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d, func='%s'\n",
                        type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %c%d: state=%d, update=%d, actions=%d\n", 
+               ast_cli(a->fd, "Thread %c%d: state=%u, update=%d, actions=%d\n",
                        type, thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                threadcount++;
@@ -6784,10 +7068,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
        AST_LIST_LOCK(&dynamic_list);
        AST_LIST_TRAVERSE(&dynamic_list, thread, list) {
 #ifdef DEBUG_SCHED_MULTITHREAD
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d, func='%s'\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d, func='%s'\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions, thread->curfunc);
 #else
-               ast_cli(a->fd, "Thread %d: state=%d, update=%d, actions=%d\n",
+               ast_cli(a->fd, "Thread %d: state=%u, update=%d, actions=%d\n",
                        thread->threadnum, thread->iostate, (int)(t - thread->checktime), thread->actions);
 #endif
                dynamiccount++;
@@ -6849,7 +7133,7 @@ static char *complete_iax2_unregister(const char *line, const char *word, int po
        if (pos == 2) {
                struct ao2_iterator i = ao2_iterator_init(peers, 0);
                while ((p = ao2_iterator_next(&i))) {
-                       if (!strncasecmp(p->name, word, wordlen) && 
+                       if (!strncasecmp(p->name, word, wordlen) &&
                                ++which > state && p->expire > 0) {
                                res = ast_strdup(p->name);
                                peer_unref(p);
@@ -6946,60 +7230,52 @@ static int manager_iax2_show_peers(struct mansession *s, const struct message *m
                snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
 
        astman_send_listack(s, m, "Peer status list will follow", "start");
-        /* List the peers in separate manager events */
+
+       /* List the peers in separate manager events */
        __iax2_show_peers(-1, &total, s, 3, a);
-        /* Send final confirmation */
-        astman_append(s,
-        "Event: PeerlistComplete\r\n"
-        "EventList: Complete\r\n"
-        "ListItems: %d\r\n"
-        "%s"
-        "\r\n", total, idtext);
-        return 0;
+
+       /* Send final confirmation */
+       astman_send_list_complete_start(s, m, "PeerlistComplete", total);
+       astman_send_list_complete_end(s);
+       return 0;
 }
 
 /*! \brief callback to display iax peers in manager format */
 static int manager_iax2_show_peer_list(struct mansession *s, const struct message *m)
 {
+       struct show_peers_context cont = {
+               .havepattern = 0,
+               .idtext = "",
+               .registeredonly = 0,
+
+               .peerlist = 1,
+
+               .total_peers = 0,
+               .online_peers = 0,
+               .offline_peers = 0,
+               .unmonitored_peers = 0,
+       };
+
        struct iax2_peer *peer = NULL;
-       int peer_count = 0;
-       char nm[20];
-       char status[20];
-       const char *id = astman_get_header(m,"ActionID");
-       char idtext[256] = "";
-       struct ast_str *encmethods = ast_str_alloca(256);
        struct ao2_iterator i;
 
-       if (!ast_strlen_zero(id))
-               snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
+       const char *id = astman_get_header(m,"ActionID");
 
-       astman_append(s, "Response: Success\r\n%sMessage: IAX Peer status list will follow\r\n\r\n", idtext);
+       if (!ast_strlen_zero(id)) {
+               snprintf(cont.idtext, sizeof(cont.idtext), "ActionID: %s\r\n", id);
+       }
 
+       astman_send_listack(s, m, "IAX Peer status list will follow", "start");
 
        i = ao2_iterator_init(peers, 0);
        for (; (peer = ao2_iterator_next(&i)); peer_unref(peer)) {
-               encmethods_to_str(peer->encmethods, &encmethods);
-               astman_append(s, "Event: PeerEntry\r\n%sChanneltype: IAX\r\n", idtext);
-               if (!ast_strlen_zero(peer->username)) {
-                       astman_append(s, "ObjectName: %s\r\nObjectUsername: %s\r\n", peer->name, peer->username);
-               } else {
-                       astman_append(s, "ObjectName: %s\r\n", peer->name);
-               }
-               astman_append(s, "ChanObjectType: peer\r\n");
-               astman_append(s, "IPaddress: %s\r\n", ast_sockaddr_stringify_addr(&peer->addr));
-               ast_copy_string(nm, ast_inet_ntoa(peer->mask), sizeof(nm));
-               astman_append(s, "Mask: %s\r\n", nm);
-               astman_append(s, "Port: %d\r\n", ast_sockaddr_port(&peer->addr));
-               astman_append(s, "Dynamic: %s\r\n", ast_test_flag64(peer, IAX_DYNAMIC) ? "Yes" : "No");
-               astman_append(s, "Trunk: %s\r\n", ast_test_flag64(peer, IAX_TRUNK) ? "Yes" : "No");
-               astman_append(s, "Encryption: %s\r\n", peer->encmethods ? ast_str_buffer(encmethods) : "No");
-               peer_status(peer, status, sizeof(status));
-               astman_append(s, "Status: %s\r\n\r\n", status);
-               peer_count++;
+               _iax2_show_peers_one(-1, s, &cont, peer);
        }
        ao2_iterator_destroy(&i);
 
-       astman_append(s, "Event: PeerlistComplete\r\n%sListItems: %d\r\n\r\n", idtext, peer_count);
+       astman_send_list_complete_start(s, m, "PeerlistComplete", cont.total_peers);
+       astman_send_list_complete_end(s);
+
        return RESULT_SUCCESS;
 }
 
@@ -7028,8 +7304,9 @@ static char *regstate2str(int regstate)
 
 static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8.8s  %s\n"
-#define FORMAT  "%-20.20s  %-6.6s  %-10.10s  %-20.20s %8d  %s\n"
+#define FORMAT2 "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8.8s  %s\n"
+#define FORMAT  "%-45.45s  %-6.6s  %-10.10s  %-45.45s %8d  %s\n"
+
        struct iax2_registry *reg = NULL;
        char host[80];
        char perceived[80];
@@ -7051,13 +7328,12 @@ static char *handle_cli_iax2_show_registry(struct ast_cli_entry *e, int cmd, str
        AST_LIST_LOCK(&registrations);
        AST_LIST_TRAVERSE(&registrations, reg, entry) {
                snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
-               if (reg->us.sin_addr.s_addr) 
-                       snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               else
-                       ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
-               ast_cli(a->fd, FORMAT, host, 
-                                       (reg->dnsmgr) ? "Y" : "N", 
-                                       reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
+
+               snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
+
+               ast_cli(a->fd, FORMAT, host,
+                               (reg->dnsmgr) ? "Y" : "N",
+                               reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
                counter++;
        }
        AST_LIST_UNLOCK(&registrations);
@@ -7084,13 +7360,9 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
        AST_LIST_LOCK(&registrations);
        AST_LIST_TRAVERSE(&registrations, reg, entry) {
                snprintf(host, sizeof(host), "%s", ast_sockaddr_stringify(&reg->addr));
-               
-               if (reg->us.sin_addr.s_addr) {
-                       snprintf(perceived, sizeof(perceived), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               } else {
-                       ast_copy_string(perceived, "<Unregistered>", sizeof(perceived));
-               }
-               
+
+               snprintf(perceived, sizeof(perceived), "%s", ast_sockaddr_isnull(&reg->addr) ? "<Unregistered>" : ast_sockaddr_stringify(&reg->addr));
+
                astman_append(s,
                        "Event: RegistryEntry\r\n"
                        "%s"
@@ -7100,28 +7372,24 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
                        "Perceived: %s\r\n"
                        "Refresh: %d\r\n"
                        "State: %s\r\n"
-                       "\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived, 
+                       "\r\n", idtext, host, (reg->dnsmgr) ? "Y" : "N", reg->username, perceived,
                        reg->refresh, regstate2str(reg->regstate));
 
                total++;
        }
        AST_LIST_UNLOCK(&registrations);
 
-       astman_append(s,
-               "Event: RegistrationsComplete\r\n"
-               "EventList: Complete\r\n"
-               "ListItems: %d\r\n"
-               "%s"
-               "\r\n", total, idtext);
-       
+       astman_send_list_complete_start(s, m, "RegistrationsComplete", total);
+       astman_send_list_complete_end(s);
+
        return 0;
 }
 
 static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
-#define FORMAT2 "%-20.20s  %-15.15s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
-#define FORMAT  "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
-#define FORMATB "%-20.20s  %-15.15s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
+#define FORMAT2 "%-20.20s  %-40.40s  %-10.10s  %-11.11s  %-11.11s  %-7.7s  %-6.6s  %-6.6s  %s  %s  %9s\n"
+#define FORMAT  "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  %-5.5dms  %-4.4dms  %-4.4dms  %-6.6s  %s%s  %3s%s\n"
+#define FORMATB "%-20.20s  %-40.40s  %-10.10s  %5.5d/%5.5d  %5.5d/%5.5d  [Native Bridged to ID=%5.5d]\n"
        int x;
        int numchans = 0;
        char first_message[10] = { 0, };
@@ -7160,7 +7428,7 @@ static char *handle_cli_iax2_show_channels(struct ast_cli_entry *e, int cmd, str
                        lag = iaxs[x]->remote_rr.delay;
                        ast_cli(a->fd, FORMAT,
                                iaxs[x]->owner ? ast_channel_name(iaxs[x]->owner) : "(None)",
-                               ast_inet_ntoa(iaxs[x]->addr.sin_addr),
+                               ast_sockaddr_stringify_addr(&iaxs[x]->addr),
                                S_OR(iaxs[x]->username, "(None)"),
                                iaxs[x]->callno, iaxs[x]->peercallno,
                                iaxs[x]->oseqno, iaxs[x]->iseqno,
@@ -7189,8 +7457,8 @@ static int ast_cli_netstats(struct mansession *s, int fd, int limit_fmt)
        int numchans = 0;
        char first_message[10] = { 0, };
        char last_message[10] = { 0, };
-#define ACN_FORMAT1 "%-20.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
-#define ACN_FORMAT2 "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
+#define ACN_FORMAT1 "%-20.25s %4u %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d %s%s %4s%s\n"
+#define ACN_FORMAT2 "%s %u %d %d %d %d %d %d %d %d %d %d %d %d %d %d %s%s %s%s\n"
        for (x = 0; x < ARRAY_LEN(iaxs); x++) {
                ast_mutex_lock(&iaxsl[x]);
                if (iaxs[x]) {
@@ -7310,8 +7578,6 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
 
        if (!strcasecmp(a->argv[3], "peer")) {
                struct iax2_peer *peer;
-               struct sockaddr_in peer_addr;
-
 
                if (a->argc != e->args + 1)
                        return CLI_SHOWUSAGE;
@@ -7323,13 +7589,9 @@ static char *handle_cli_iax2_set_debug(struct ast_cli_entry *e, int cmd, struct
                        return CLI_FAILURE;
                }
 
-               ast_sockaddr_to_sin(&peer->addr, &peer_addr);
-
-               debugaddr.sin_addr = peer_addr.sin_addr;
-               debugaddr.sin_port = peer_addr.sin_port;
+               ast_sockaddr_copy(&debugaddr, &peer->addr);
 
-               ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s:%d\n",
-                       ast_inet_ntoa(debugaddr.sin_addr), ntohs(debugaddr.sin_port));
+               ast_cli(a->fd, "IAX2 Debugging Enabled for IP: %s\n", ast_sockaddr_stringify_port(&debugaddr));
 
                ao2_ref(peer, -1);
        } else if (!strncasecmp(a->argv[3], "on", 2)) {
@@ -7384,7 +7646,7 @@ static char *handle_cli_iax2_set_debug_jb(struct ast_cli_entry *e, int cmd, stru
 
        if (a->argc != e->args)
                return CLI_SHOWUSAGE;
-       
+
        if (!strncasecmp(a->argv[e->args -1], "on", 2)) {
                jb_setoutput(jb_error_output, jb_warning_output, jb_debug_output);
                ast_cli(a->fd, "IAX2 Jitterbuffer Debugging Enabled\n");
@@ -7445,6 +7707,12 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig
 
 static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
 {
+       if (type == AST_FRAME_CONTROL && !iax2_is_control_frame_allowed(command)) {
+               /* Control frame should not go out on the wire. */
+               ast_debug(2, "Callno %d: Blocked sending control frame %d.\n",
+                       i->callno, command);
+               return 0;
+       }
        return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0);
 }
 
@@ -7459,7 +7727,7 @@ static int send_command_locked(unsigned short callno, char type, int command, un
 
 /*!
  * \note Since this function calls iax2_predestroy() -> iax2_queue_hangup(),
- *       the pvt struct for the given call number may disappear during its 
+ *       the pvt struct for the given call number may disappear during its
  *       execution.
  */
 static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const unsigned char *data, int datalen, int seqno)
@@ -7493,7 +7761,7 @@ static int apply_context(struct iax2_context *con, const char *context)
 }
 
 
-static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
+static int check_access(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
 {
        /* Start pessimistic */
        int res = -1;
@@ -7503,14 +7771,13 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
        int gotcapability = 0;
        struct ast_variable *v = NULL, *tmpvar = NULL;
        struct ao2_iterator i;
-       struct ast_sockaddr addr;
 
        if (!iaxs[callno])
                return res;
        if (ies->called_number)
                ast_string_field_set(iaxs[callno], exten, ies->called_number);
        if (ies->calling_number) {
-               if (ast_test_flag64(&globalflags, IAX_SHRINKCALLERID)) { 
+               if (ast_test_flag64(&globalflags, IAX_SHRINKCALLERID)) {
                        ast_shrink_phone_number(ies->calling_number);
                }
                ast_string_field_set(iaxs[callno], cid_num, ies->calling_number);
@@ -7542,30 +7809,32 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
        if (ies->capability) {
                gotcapability = 1;
                iaxs[callno]->peercapability = ies->capability;
-       } 
+       }
        if (ies->version)
                version = ies->version;
 
        /* Use provided preferences until told otherwise for actual preferences */
        if (ies->codec_prefs) {
-               ast_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
-               ast_codec_pref_convert(&iaxs[callno]->prefs, ies->codec_prefs, 32, 0);
+               iax2_codec_pref_convert(&iaxs[callno]->rprefs, ies->codec_prefs, 32, 0);
+       } else {
+               memset(&iaxs[callno]->rprefs, 0, sizeof(iaxs[callno]->rprefs));
        }
+       iaxs[callno]->prefs = iaxs[callno]->rprefs;
 
-       if (!gotcapability) 
+       if (!gotcapability) {
                iaxs[callno]->peercapability = iaxs[callno]->peerformat;
+       }
        if (version > IAX_PROTO_VERSION) {
-               ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n", 
-                       ast_inet_ntoa(sin->sin_addr), version);
+               ast_log(LOG_WARNING, "Peer '%s' has too new a protocol version (%d) for me\n",
+                               ast_sockaddr_stringify_addr(addr), version);
                return res;
        }
        /* Search the userlist for a compatible entry, and fill in the rest */
-       ast_sockaddr_from_sin(&addr, sin);
        i = ao2_iterator_init(users, 0);
        while ((user = ao2_iterator_next(&i))) {
                if ((ast_strlen_zero(iaxs[callno]->username) ||                         /* No username specified */
                        !strcmp(iaxs[callno]->username, user->name))    /* Or this username specified */
-                       && (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)      /* Access is permitted from this IP */
+                       && (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_ALLOW)       /* Access is permitted from this IP */
                        && (ast_strlen_zero(iaxs[callno]->context) ||                   /* No context specified */
                             apply_context(user->contexts, iaxs[callno]->context))) {                   /* Context is permitted */
                        if (!ast_strlen_zero(iaxs[callno]->username)) {
@@ -7622,8 +7891,8 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
        ao2_iterator_destroy(&i);
        user = best;
        if (!user && !ast_strlen_zero(iaxs[callno]->username)) {
-               user = realtime_user(iaxs[callno]->username, sin);
-               if (user && (ast_apply_acl(user->acl, &addr, "IAX2 user ACL: ") == AST_SENSE_DENY               /* Access is denied from this IP */
+               user = realtime_user(iaxs[callno]->username, addr);
+               if (user && (ast_apply_acl(user->acl, addr, "IAX2 user ACL: ") == AST_SENSE_DENY                /* Access is denied from this IP */
                        || (!ast_strlen_zero(iaxs[callno]->context) &&                                  /* No context specified */
                                !apply_context(user->contexts, iaxs[callno]->context)))) {      /* Context is permitted */
                        user = user_unref(user);
@@ -7634,7 +7903,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                /* copy vars */
                for (v = user->vars ; v ; v = v->next) {
                        if((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
-                               tmpvar->next = iaxs[callno]->vars; 
+                               tmpvar->next = iaxs[callno]->vars;
                                iaxs[callno]->vars = tmpvar;
                        }
                }
@@ -7685,7 +7954,7 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                        iaxs[callno]->amaflags = user->amaflags;
                if (!ast_strlen_zero(user->language))
                        ast_string_field_set(iaxs[callno], language, user->language);
-               ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_FORCEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);       
+               ast_copy_flags64(iaxs[callno], user, IAX_NOTRANSFER | IAX_TRANSFERMEDIA | IAX_USEJITTERBUF | IAX_SENDCONNECTEDLINE | IAX_RECVCONNECTEDLINE);
                /* Keep this check last */
                if (!ast_strlen_zero(user->dbsecret)) {
                        char *family, *key=NULL;
@@ -7717,11 +7986,11 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
                        res = 0;
                }
        }
-       ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*sin), IAX_TRUNK);
+       ast_set2_flag64(iaxs[callno], iax2_getpeertrunk(*addr), IAX_TRUNK);
        return res;
 }
 
-static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned short dst, int sockfd)
+static int raw_hangup(struct ast_sockaddr *addr, unsigned short src, unsigned short dst, int sockfd)
 {
        struct ast_iax2_full_hdr fh;
        fh.scallno = htons(src | IAX_FLAG_FULL);
@@ -7731,10 +8000,10 @@ static int raw_hangup(struct sockaddr_in *sin, unsigned short src, unsigned shor
        fh.iseqno = 0;
        fh.type = AST_FRAME_IAX;
        fh.csub = compress_subclass(IAX_COMMAND_INVAL);
-       iax_outputframe(NULL, &fh, 0, sin, 0);
-       ast_debug(1, "Raw Hangup %s:%d, src=%d, dst=%d\n",
-               ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), src, dst);
-       return sendto(sockfd, &fh, sizeof(fh), 0, (struct sockaddr *)sin, sizeof(*sin));
+       iax_outputframe(NULL, &fh, 0, addr, 0);
+
+       ast_debug(1, "Raw Hangup %s, src=%d, dst=%d\n", ast_sockaddr_stringify(addr), src, dst);
+       return ast_sendto(sockfd, &fh, sizeof(fh), 0, addr);
 }
 
 static void merge_encryption(struct chan_iax2_pvt *p, unsigned int enc)
@@ -7815,13 +8084,14 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
        char md5secret[256] = "";
        char secret[256] = "";
        char rsasecret[256] = "";
-       int res = -1; 
+       int res = -1;
        int x;
        struct iax2_user *user;
 
        if (p->authrej) {
                return res;
        }
+
        user = ao2_find(users, p->username, OBJ_KEY);
        if (user) {
                if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
@@ -7831,7 +8101,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                ast_string_field_set(p, host, user->name);
                user = user_unref(user);
        }
-       if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) { 
+       if (ast_test_flag64(p, IAX_FORCE_ENCRYPT) && !p->encmethods) {
                ast_log(LOG_NOTICE, "Call Terminated, Incoming call is unencrypted while force encrypt is enabled.\n");
                return res;
        }
@@ -7868,7 +8138,6 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                struct MD5Context md5;
                unsigned char digest[16];
                char *tmppw, *stringp;
-
                tmppw = ast_strdupa(p->secret);
                stringp = tmppw;
                while((tmppw = strsep(&stringp, ";"))) {
@@ -7878,7 +8147,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
-                               sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
+                               sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
                        if (!strcasecmp(requeststr, md5secret)) {
                                res = 0;
                                break;
@@ -7892,7 +8161,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
 }
 
 /*! \brief Verify inbound registration */
-static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *ies)
+static int register_verify(int callno, struct ast_sockaddr *addr, struct iax_ies *ies)
 {
        char requeststr[256] = "";
        char peer[256] = "";
@@ -7905,7 +8174,6 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
        int x;
        int expire = 0;
        int res = -1;
-       struct ast_sockaddr addr;
 
        ast_clear_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
        /* iaxs[callno]->peer[0] = '\0'; not necc. any more-- stringfield is pre-inited to null string */
@@ -7921,7 +8189,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                expire = ies->refresh;
 
        if (ast_strlen_zero(peer)) {
-               ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_inet_ntoa(sin->sin_addr));
+               ast_log(LOG_NOTICE, "Empty registration from %s\n", ast_sockaddr_stringify_addr(addr));
                return -1;
        }
 
@@ -7938,7 +8206,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                         * 1. A challenge already exists indicating a AUTHREQ was already sent out.
                         * 2. A plaintext secret is present in ie as result of a previous AUTHREQ requesting it.
                         * 3. A plaintext secret is present in the ie and the last_authmethod used by a peer happened
-                        *    to be plaintext, indicating it is an authmethod used by other peers on the system. 
+                        *    to be plaintext, indicating it is an authmethod used by other peers on the system.
                         *
                         * If none of these cases exist, res will be returned as 0 without authentication indicating
                         * an AUTHREQ needs to be sent out. */
@@ -7950,20 +8218,19 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        }
                }
                if (authdebug && !p)
-                       ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "No registration for peer '%s' (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
                goto return_unref;
        }
 
        if (!ast_test_flag64(p, IAX_DYNAMIC)) {
                if (authdebug)
-                       ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "Peer '%s' is not dynamic (from %s)\n", peer, ast_sockaddr_stringify_addr(addr));
                goto return_unref;
        }
 
-       ast_sockaddr_from_sin(&addr, sin);
-       if (!ast_apply_acl(p->acl, &addr, "IAX2 Peer ACL: ")) {
+       if (!ast_apply_acl(p->acl, addr, "IAX2 Peer ACL: ")) {
                if (authdebug)
-                       ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
+                       ast_log(LOG_NOTICE, "Host %s denied access to register peer '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
                goto return_unref;
        }
        ast_string_field_set(iaxs[callno], secret, p->secret);
@@ -8012,7 +8279,7 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        MD5Update(&md5, (unsigned char *)tmppw, strlen(tmppw));
                        MD5Final(digest, &md5);
                        for (x=0;x<16;x++)
-                               sprintf(requeststr + (x << 1), "%2.2x", digest[x]); /* safe */
+                               sprintf(requeststr + (x << 1), "%02hhx", digest[x]); /* safe */
                        if (!strcasecmp(requeststr, md5secret))
                                break;
                }
@@ -8020,14 +8287,14 @@ static int register_verify(int callno, struct sockaddr_in *sin, struct iax_ies *
                        ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
                } else {
                        if (authdebug)
-                               ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_inet_ntoa(sin->sin_addr), p->name, requeststr, md5secret);
+                               ast_log(LOG_NOTICE, "Host %s failed MD5 authentication for '%s' (%s != %s)\n", ast_sockaddr_stringify_addr(addr), p->name, requeststr, md5secret);
                        goto return_unref;
                }
        } else if (!ast_strlen_zero(secret) && (p->authmethods & IAX_AUTH_PLAINTEXT)) {
                /* They've provided a plain text password and we support that */
                if (strcmp(secret, p->secret)) {
                        if (authdebug)
-                               ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_inet_ntoa(sin->sin_addr), p->name);
+                               ast_log(LOG_NOTICE, "Host %s did not provide proper plaintext password for '%s'\n", ast_sockaddr_stringify_addr(addr), p->name);
                        goto return_unref;
                } else
                        ast_set_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED);
@@ -8056,16 +8323,17 @@ return_unref:
        return res;
 }
 
-static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct sockaddr_in *sin, struct chan_iax2_pvt *pvt)
+static int authenticate(const char *challenge, const char *secret, const char *keyn, int authmethods, struct iax_ie_data *ied, struct ast_sockaddr *addr, struct chan_iax2_pvt *pvt)
 {
        int res = -1;
        int x;
        if (!ast_strlen_zero(keyn)) {
                if (!(authmethods & IAX_AUTH_RSA)) {
-                       if (ast_strlen_zero(secret)) 
-                               ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_inet_ntoa(sin->sin_addr));
+                       if (ast_strlen_zero(secret)) {
+                               ast_log(LOG_NOTICE, "Asked to authenticate to %s with an RSA key, but they don't allow RSA authentication\n", ast_sockaddr_stringify_addr(addr));
+                       }
                } else if (ast_strlen_zero(challenge)) {
-                       ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_inet_ntoa(sin->sin_addr));
+                       ast_log(LOG_NOTICE, "No challenge provided for RSA authentication to %s\n", ast_sockaddr_stringify_addr(addr));
                } else {
                        char sig[256];
                        struct ast_key *key;
@@ -8082,7 +8350,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
                                }
                        }
                }
-       } 
+       }
        /* Fall back */
        if (res && !ast_strlen_zero(secret)) {
                if ((authmethods & IAX_AUTH_MD5) && !ast_strlen_zero(challenge)) {
@@ -8095,7 +8363,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
                        MD5Final(digest, &md5);
                        /* If they support md5, authenticate with it.  */
                        for (x=0;x<16;x++)
-                               sprintf(digres + (x << 1),  "%2.2x", digest[x]); /* safe */
+                               sprintf(digres + (x << 1),  "%02hhx", digest[x]); /* safe */
                        if (pvt) {
                                build_encryption_keys(digest, pvt);
                        }
@@ -8105,7 +8373,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
                        iax_ie_append_str(ied, IAX_IE_PASSWORD, secret);
                        res = 0;
                } else
-                       ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_inet_ntoa(sin->sin_addr), authmethods);
+                       ast_log(LOG_NOTICE, "No way to send secret to peer '%s' (their methods: %d)\n", ast_sockaddr_stringify_addr(addr), authmethods);
        }
        return res;
 }
@@ -8114,7 +8382,7 @@ static int authenticate(const char *challenge, const char *secret, const char *k
  * \note This function calls realtime_peer -> reg_source_db -> iax2_poke_peer -> find_callno,
  *       so do not call this function with a pvt lock held.
  */
-static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin, struct iax_ies *ies, const char *override, const char *okey)
+static int authenticate_reply(struct chan_iax2_pvt *p, struct ast_sockaddr *addr, struct iax_ies *ies, const char *override, const char *okey)
 {
        struct iax2_peer *peer = NULL;
        /* Start pessimistic */
@@ -8124,7 +8392,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
        uint16_t callno = p->callno;
 
        memset(&ied, 0, sizeof(ied));
-       
+
        if (ies->username)
                ast_string_field_set(p, username, ies->username);
        if (ies->challenge)
@@ -8139,22 +8407,27 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
        /* Check for override RSA authentication first */
        if (!ast_strlen_zero(override) || !ast_strlen_zero(okey)) {
                /* Normal password authentication */
-               res = authenticate(p->challenge, override, okey, authmethods, &ied, sin, p);
+               res = authenticate(p->challenge, override, okey, authmethods, &ied, addr, p);
        } else {
                struct ao2_iterator i = ao2_iterator_init(peers, 0);
                while ((peer = ao2_iterator_next(&i))) {
-                       struct sockaddr_in peer_addr;
+                       struct ast_sockaddr peer_addr;
+                       struct ast_sockaddr tmp_sockaddr1;
+                       struct ast_sockaddr tmp_sockaddr2;
+
+                       ast_sockaddr_copy(&peer_addr, &peer->addr);
 
-                       ast_sockaddr_to_sin(&peer->addr, &peer_addr);
+                       ast_sockaddr_apply_netmask(addr, &peer->mask, &tmp_sockaddr1);
+                       ast_sockaddr_apply_netmask(&peer_addr, &peer->mask, &tmp_sockaddr2);
 
-                       if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name)) 
-                           /* No peer specified at our end, or this is the peer */
+                       if ((ast_strlen_zero(p->peer) || !strcmp(p->peer, peer->name))
+                               /* No peer specified at our end, or this is the peer */
                            && (ast_strlen_zero(peer->username) || (!strcmp(peer->username, p->username)))
                            /* No username specified in peer rule, or this is the right username */
-                           && (!peer_addr.sin_addr.s_addr || ((sin->sin_addr.s_addr & peer->mask.s_addr) == (peer_addr.sin_addr.s_addr & peer->mask.s_addr)))
+                           && (ast_sockaddr_isnull(&peer_addr) || !(ast_sockaddr_cmp_addr(&tmp_sockaddr1, &tmp_sockaddr2)))
                            /* No specified host, or this is our host */
                                ) {
-                               res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, sin, p);
+                               res = authenticate(p->challenge, peer->secret, peer->outkey, authmethods, &ied, addr, p);
                                if (!res) {
                                        peer_unref(peer);
                                        break;
@@ -8164,7 +8437,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                }
                ao2_iterator_destroy(&i);
                if (!peer) {
-                       /* We checked our list and didn't find one.  It's unlikely, but possible, 
+                       /* We checked our list and didn't find one.  It's unlikely, but possible,
                           that we're trying to authenticate *to* a realtime peer */
                        const char *peer_name = ast_strdupa(p->peer);
                        ast_mutex_unlock(&iaxsl[callno]);
@@ -8174,7 +8447,7 @@ static int authenticate_reply(struct chan_iax2_pvt *p, struct sockaddr_in *sin,
                                        peer_unref(peer);
                                        return -1;
                                }
-                               res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, sin, p);
+                               res = authenticate(p->challenge, peer->secret,peer->outkey, authmethods, &ied, addr, p);
                                peer_unref(peer);
                        }
                        if (!peer) {
@@ -8237,6 +8510,17 @@ static int iax2_do_register(struct iax2_registry *reg);
 static void __iax2_do_register_s(const void *data)
 {
        struct iax2_registry *reg = (struct iax2_registry *)data;
+
+       if (ast_sockaddr_isnull(&reg->addr)) {
+               reg->addr.ss.ss_family = AST_AF_UNSPEC;
+               ast_dnsmgr_lookup(reg->hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL);
+               if (!ast_sockaddr_port(&reg->addr)) {
+                       ast_sockaddr_set_port(&reg->addr, reg->port);
+               } else {
+                       reg->port = ast_sockaddr_port(&reg->addr);
+               }
+       }
+
        reg->expire = -1;
        iax2_do_register(reg);
 }
@@ -8245,7 +8529,7 @@ static int iax2_do_register_s(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__iax2_do_register_s, data))
-#endif         
+#endif
                __iax2_do_register_s(data);
        return 0;
 }
@@ -8253,23 +8537,22 @@ static int iax2_do_register_s(const void *data)
 static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
 {
        int newcall = 0;
-       char newip[256];
        struct iax_ie_data ied;
-       struct sockaddr_in new = { 0, };
+       struct ast_sockaddr new;
 
        memset(&ied, 0, sizeof(ied));
-       if (ies->apparent_addr)
-               memmove(&new, ies->apparent_addr, sizeof(new));
-       if (ies->callno)
+       if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
+               ast_sockaddr_copy(&new, &ies->apparent_addr);
+       }
+       if (ies->callno) {
                newcall = ies->callno;
-       if (!newcall || !new.sin_addr.s_addr || !new.sin_port) {
+       }
+       if (!newcall || ast_sockaddr_isnull(&new)) {
                ast_log(LOG_WARNING, "Invalid transfer request\n");
                return -1;
        }
        pvt->transfercallno = newcall;
-       memcpy(&pvt->transfer, &new, sizeof(pvt->transfer));
-       inet_aton(newip, &pvt->transfer.sin_addr);
-       pvt->transfer.sin_family = AF_INET;
+       ast_sockaddr_copy(&pvt->transfer, &new);
        pvt->transferid = ies->transferid;
        /* only store by transfercallno if this is a new transfer,
         * just in case we get a duplicate TXREQ */
@@ -8278,8 +8561,9 @@ static int try_transfer(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
        }
        pvt->transferring = TRANSFER_BEGIN;
 
-       if (ies->transferid)
+       if (ies->transferid) {
                iax_ie_append_int(&ied, IAX_IE_TRANSFERID, ies->transferid);
+       }
        send_command_transfer(pvt, AST_FRAME_IAX, IAX_COMMAND_TXCNT, 0, ied.buf, ied.pos);
        return 0;
 }
@@ -8289,10 +8573,10 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
        char exten[256] = "";
        int status = CACHE_FLAG_UNKNOWN, expiry = iaxdefaultdpcache, x, matchmore = 0;
        struct iax2_dpcache *dp = NULL;
-       
+
        if (ies->called_number)
                ast_copy_string(exten, ies->called_number, sizeof(exten));
-       
+
        if (ies->dpstatus & IAX_DPSTATUS_EXISTS)
                status = CACHE_FLAG_EXISTS;
        else if (ies->dpstatus & IAX_DPSTATUS_CANEXIST)
@@ -8304,7 +8588,7 @@ static int complete_dpreply(struct chan_iax2_pvt *pvt, struct iax_ies *ies)
                expiry = ies->refresh;
        if (ies->dpstatus & IAX_DPSTATUS_MATCHMORE)
                matchmore = CACHE_FLAG_MATCHMORE;
-       
+
        AST_LIST_LOCK(&dpcache);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&dpcache, dp, peer_list) {
                if (strcmp(dp->exten, exten))
@@ -8392,8 +8676,13 @@ static int complete_transfer(int callno, struct iax_ies *ies)
        return 0;
 }
 
+static void iax2_publish_registry(const char *username, const char *domain, const char *status, const char *cause)
+{
+       ast_system_publish_registry("IAX2", username, domain, status, cause);
+}
+
 /*! \brief Acknowledgment received for OUR registration */
-static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int callno)
+static int iax2_ack_registry(struct iax_ies *ies, struct ast_sockaddr *addr, int callno)
 {
        struct iax2_registry *reg;
        /* Start pessimistic */
@@ -8401,14 +8690,12 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        char msgstatus[60];
        int refresh = 60;
        char ourip[256] = "<Unspecified>";
-       struct sockaddr_in oldus;
-       struct sockaddr_in us;
+       struct ast_sockaddr oldus;
+       struct ast_sockaddr us;
        int oldmsgs;
-       struct sockaddr_in reg_addr;
 
-       memset(&us, 0, sizeof(us));
-       if (ies->apparent_addr) {
-               memmove(&us, ies->apparent_addr, sizeof(us));
+       if (!ast_sockaddr_isnull(&ies->apparent_addr)) {
+               ast_sockaddr_copy(&us, &ies->apparent_addr);
        }
        if (ies->username) {
                ast_copy_string(peer, ies->username, sizeof(peer));
@@ -8424,14 +8711,13 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
                ast_log(LOG_WARNING, "Registry acknowledge on unknown registry '%s'\n", peer);
                return -1;
        }
-       memcpy(&oldus, &reg->us, sizeof(oldus));
+       ast_sockaddr_copy(&oldus, &reg->us);
        oldmsgs = reg->messages;
-       ast_sockaddr_to_sin(&reg->addr, &reg_addr);
-       if (inaddrcmp(&reg_addr, sin)) {
-               ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_inet_ntoa(sin->sin_addr));
+       if (ast_sockaddr_cmp(&reg->addr, addr)) {
+               ast_log(LOG_WARNING, "Received unsolicited registry ack from '%s'\n", ast_sockaddr_stringify(addr));
                return -1;
        }
-       memcpy(&reg->us, &us, sizeof(reg->us));
+       ast_sockaddr_copy(&reg->us, &us);
        if (ies->msgcount >= 0) {
                reg->messages = ies->msgcount & 0xffff;         /* only low 16 bits are used in the transmission of the IE */
        }
@@ -8441,7 +8727,8 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
        reg->refresh = refresh;
        reg->expire = iax2_sched_replace(reg->expire, sched,
                (5 * reg->refresh / 6) * 1000, iax2_do_register_s, reg);
-       if (inaddrcmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
+       if (ast_sockaddr_cmp(&oldus, &reg->us) || (reg->messages != oldmsgs)) {
+
                if (reg->messages > 255) {
                        snprintf(msgstatus, sizeof(msgstatus), " with %d new and %d old messages waiting", reg->messages & 0xff, reg->messages >> 8);
                } else if (reg->messages > 1) {
@@ -8451,9 +8738,11 @@ static int iax2_ack_registry(struct iax_ies *ies, struct sockaddr_in *sin, int c
                } else {
                        ast_copy_string(msgstatus, " with no messages waiting", sizeof(msgstatus));
                }
-               snprintf(ourip, sizeof(ourip), "%s:%d", ast_inet_ntoa(reg->us.sin_addr), ntohs(reg->us.sin_port));
-               ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_inet_ntoa(sin->sin_addr), ourip, msgstatus);
-               manager_event(EVENT_FLAG_SYSTEM, "Registry", "ChannelType: IAX2\r\nDomain: %s\r\nStatus: Registered\r\n", ast_inet_ntoa(sin->sin_addr));
+
+               snprintf(ourip, sizeof(ourip), "%s", ast_sockaddr_stringify(&reg->us));
+
+               ast_verb(3, "Registered IAX2 to '%s', who sees us as %s%s\n", ast_sockaddr_stringify(addr), ourip, msgstatus);
+               iax2_publish_registry(reg->username, ast_sockaddr_stringify(addr), "Registered", NULL);
        }
        reg->regstate = REG_STATE_REGISTERED;
        return 0;
@@ -8464,28 +8753,40 @@ static int iax2_append_register(const char *hostname, const char *username,
 {
        struct iax2_registry *reg;
 
-       if (!(reg = ast_calloc(1, sizeof(*reg))))
+       if (!(reg = ast_calloc(1, sizeof(*reg) + strlen(hostname) + 1))) {
                return -1;
+       }
 
-       reg->addr.ss.ss_family = AF_INET;
+       reg->addr.ss.ss_family = AST_AF_UNSPEC;
        if (ast_dnsmgr_lookup(hostname, &reg->addr, &reg->dnsmgr, srvlookup ? "_iax._udp" : NULL) < 0) {
                ast_free(reg);
                return -1;
        }
 
        ast_copy_string(reg->username, username, sizeof(reg->username));
+       strcpy(reg->hostname, hostname); /* Note: This is safe */
 
-       if (secret)
+       if (secret) {
                ast_copy_string(reg->secret, secret, sizeof(reg->secret));
+       }
 
        reg->expire = -1;
        reg->refresh = IAX_DEFAULT_REG_EXPIRE;
-       ast_sockaddr_set_port(&reg->addr, porta ? atoi(porta) : IAX_DEFAULT_PORTNO);
+
+       reg->port = ast_sockaddr_port(&reg->addr);
+
+       if (!porta && !reg->port) {
+               reg->port = IAX_DEFAULT_PORTNO;
+       } else if (porta) {
+               sscanf(porta, "%5d", &reg->port);
+       }
+
+       ast_sockaddr_set_port(&reg->addr, reg->port);
 
        AST_LIST_LOCK(&registrations);
        AST_LIST_INSERT_HEAD(&registrations, reg, entry);
        AST_LIST_UNLOCK(&registrations);
-       
+
        return 0;
 }
 
@@ -8495,7 +8796,7 @@ static int iax2_register(const char *value, int lineno)
        char *username, *hostname, *secret;
        char *porta;
        char *stringp=NULL;
-       
+
        if (!value)
                return -1;
 
@@ -8515,7 +8816,7 @@ static int iax2_register(const char *value, int lineno)
        stringp = hostname;
        hostname = strsep(&stringp, ":");
        porta = strsep(&stringp, ":");
-       
+
        if (porta && !atoi(porta)) {
                ast_log(LOG_WARNING, "%s is not a valid port number at line %d\n", porta, lineno);
                return -1;
@@ -8586,9 +8887,9 @@ static void __expire_registry(const void *data)
                "cause", "Expired");
        ast_endpoint_blob_publish(peer->endpoint, ast_endpoint_state_type(), blob);
        /* modify entry in peercnts table as _not_ registered */
-       peercnt_modify(0, 0, &peer->addr);
+       peercnt_modify((unsigned char) 0, 0, &peer->addr);
        /* Reset the address */
-       memset(&peer->addr, 0, sizeof(peer->addr));
+       ast_sockaddr_setnull(&peer->addr);
        /* Reset expiry value */
        peer->expiry = min_reg_expire;
        if (!ast_test_flag64(peer, IAX_TEMPONLY))
@@ -8608,13 +8909,11 @@ static int expire_registry(const void *data)
 {
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__expire_registry, data))
-#endif         
+#endif
                __expire_registry(data);
        return 0;
 }
 
-static int iax2_poke_peer(struct iax2_peer *peer, int heldcall);
-
 static void reg_source_db(struct iax2_peer *p)
 {
        char data[80];
@@ -8669,8 +8968,9 @@ static void reg_source_db(struct iax2_peer *p)
  * \note Since this function calls send_command_final(), the pvt struct for
  *       the given call number may disappear while executing this function.
  */
-static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, int fd, unsigned short refresh)
+static int update_registry(struct ast_sockaddr *addr, int callno, char *devtype, int fd, unsigned short refresh)
 {
+
        /* Called from IAX thread only, with proper iaxsl lock */
        struct iax_ie_data ied = {
                .pos = 0,
@@ -8681,9 +8981,7 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
        uint16_t version;
        const char *peer_name;
        int res = -1;
-       struct ast_sockaddr sockaddr;
-
-       ast_sockaddr_from_sin(&sockaddr, sin);
+       char *str_addr;
 
        peer_name = ast_strdupa(iaxs[callno]->peer);
 
@@ -8699,16 +8997,32 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                goto return_unref;
 
        if (ast_test_flag64((&globalflags), IAX_RTUPDATE) && (ast_test_flag64(p, IAX_TEMPONLY|IAX_RTCACHEFRIENDS))) {
-               if (sin->sin_addr.s_addr) {
+               if (!ast_sockaddr_isnull(addr)) {
                        time_t nowtime;
                        time(&nowtime);
-                       realtime_update_peer(peer_name, &sockaddr, nowtime);
+                       realtime_update_peer(peer_name, addr, nowtime);
                } else {
-                       realtime_update_peer(peer_name, &sockaddr, 0);
+                       realtime_update_peer(peer_name, addr, 0);
                }
        }
 
-       if (ast_sockaddr_cmp(&p->addr, &sockaddr)) {
+       /* treat an unspecified refresh interval as the minimum */
+       if (!refresh) {
+               refresh = min_reg_expire;
+       }
+       if (refresh > max_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, max_reg_expire, refresh);
+               p->expiry = max_reg_expire;
+       } else if (refresh < min_reg_expire) {
+               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
+                       p->name, min_reg_expire, refresh);
+               p->expiry = min_reg_expire;
+       } else {
+               p->expiry = refresh;
+       }
+
+       if (ast_sockaddr_cmp(&p->addr, addr)) {
                RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
 
                if (iax2_regfunk) {
@@ -8716,25 +9030,31 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                }
 
                /* modify entry in peercnts table as _not_ registered */
-               peercnt_modify(0, 0, &p->addr);
+               peercnt_modify((unsigned char) 0, 0, &p->addr);
 
                /* Stash the IP address from which they registered */
-               ast_sockaddr_from_sin(&p->addr, sin);
+               ast_sockaddr_copy(&p->addr, addr);
+
+               str_addr = ast_strdupa(ast_sockaddr_stringify_addr(addr));
 
-               snprintf(data, sizeof(data), "%s:%d:%d", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), p->expiry);
-               if (!ast_test_flag64(p, IAX_TEMPONLY) && sin->sin_addr.s_addr) {
+               snprintf(data, sizeof(data), "%s:%d", ast_sockaddr_stringify(addr), p->expiry);
+
+               if (!ast_test_flag64(p, IAX_TEMPONLY) && !ast_sockaddr_isnull(addr)) {
                        ast_db_put("IAX/Registry", p->name, data);
-                       ast_verb(3, "Registered IAX2 '%s' (%s) at %s:%d\n", p->name,
-                                           ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+                       ast_verb(3, "Registered IAX2 '%s' (%s) at %s\n",
+                                               p->name,
+                                           ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED",
+                                           ast_sockaddr_stringify(addr));
                        ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_ONLINE);
                        blob = ast_json_pack("{s: s, s: s, s: i}",
                                "peer_status", "Registered",
-                               "address", ast_inet_ntoa(sin->sin_addr),
-                               "port", ntohs(sin->sin_port));
+                               "address", str_addr,
+                               "port", ast_sockaddr_port(addr));
                        register_peer_exten(p, 1);
                        ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "IAX2/%s", p->name); /* Activate notification */
                } else if (!ast_test_flag64(p, IAX_TEMPONLY)) {
-                       ast_verb(3, "Unregistered IAX2 '%s' (%s)\n", p->name,
+                       ast_verb(3, "Unregistered IAX2 '%s' (%s)\n",
+                                               p->name,
                                            ast_test_flag(&iaxs[callno]->state, IAX_STATE_AUTHENTICATED) ? "AUTHENTICATED" : "UNAUTHENTICATED");
                        ast_endpoint_set_state(p->endpoint, AST_ENDPOINT_OFFLINE);
                        blob = ast_json_pack("{s: s}",
@@ -8753,7 +9073,7 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
 
        /* modify entry in peercnts table as registered */
        if (p->maxcallno) {
-               peercnt_modify(1, p->maxcallno, &p->addr);
+               peercnt_modify((unsigned char) 1, p->maxcallno, &p->addr);
        }
 
        /* Make sure our call still exists, an INVAL at the right point may make it go away */
@@ -8771,49 +9091,26 @@ static int update_registry(struct sockaddr_in *sin, int callno, char *devtype, i
                        peer_unref(p);
                }
        }
-       /* treat an unspecified refresh interval as the minimum */
-       if (!refresh)
-               refresh = min_reg_expire;
-       if (refresh > max_reg_expire) {
-               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
-                       p->name, max_reg_expire, refresh);
-               p->expiry = max_reg_expire;
-       } else if (refresh < min_reg_expire) {
-               ast_log(LOG_NOTICE, "Restricting registration for peer '%s' to %d seconds (requested %d)\n",
-                       p->name, min_reg_expire, refresh);
-               p->expiry = min_reg_expire;
-       } else {
-               p->expiry = refresh;
-       }
-       if (p->expiry && sin->sin_addr.s_addr) {
+
+       if (p->expiry && !ast_sockaddr_isnull(addr)) {
                p->expire = iax2_sched_add(sched, (p->expiry + 10) * 1000, expire_registry, peer_ref(p));
                if (p->expire == -1)
                        peer_unref(p);
        }
        iax_ie_append_str(&ied, IAX_IE_USERNAME, p->name);
        iax_ie_append_int(&ied, IAX_IE_DATETIME, iax2_datetime(p->zonetag));
-       if (sin->sin_addr.s_addr) {
-               struct sockaddr_in peer_addr;
+       if (!ast_sockaddr_isnull(addr)) {
+               struct ast_sockaddr peer_addr;
 
-               ast_sockaddr_to_sin(&p->addr, &peer_addr);
+               ast_sockaddr_copy(&peer_addr, &p->addr);
 
                iax_ie_append_short(&ied, IAX_IE_REFRESH, p->expiry);
                iax_ie_append_addr(&ied, IAX_IE_APPARENT_ADDR, &peer_addr);
                if (!ast_strlen_zero(p->mailbox)) {
                        int new, old;
-                       char *mailbox, *context;
                        RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-                       struct ast_str *uniqueid = ast_str_alloca(AST_MAX_MAILBOX_UNIQUEID);
-
-                       context = mailbox = ast_strdupa(p->mailbox);
-                       strsep(&context, "@");
-                       if (ast_strlen_zero(context)) {
-                               context = "default";
-                       }
-
-                       ast_str_set(&uniqueid, 0, "%s@%s", mailbox, context);
-                       msg = stasis_cache_get(ast_mwi_topic_cached(), ast_mwi_state_type(), ast_str_buffer(uniqueid));
 
+                       msg = stasis_cache_get(ast_mwi_state_cache(), ast_mwi_state_type(), p->mailbox);
                        if (msg) {
                                struct ast_mwi_state *mwi_state = stasis_message_data(msg);
                                new = mwi_state->new_msgs;
@@ -8897,7 +9194,7 @@ return_unref:
        return iaxs[callno] ? send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGAUTH, 0, ied.buf, ied.pos, -1) : -1;
 }
 
-static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_in *sin)
+static int registry_rerequest(struct iax_ies *ies, int callno, struct ast_sockaddr *addr)
 {
        struct iax2_registry *reg;
        /* Start pessimistic */
@@ -8915,12 +9212,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
        memset(&ied, 0, sizeof(ied));
        reg = iaxs[callno]->reg;
        if (reg) {
-               struct sockaddr_in reg_addr;
 
-               ast_sockaddr_to_sin(&reg->addr, &reg_addr);
-
-               if (inaddrcmp(&reg_addr, sin)) {
-                       ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_inet_ntoa(sin->sin_addr));
+               if (ast_sockaddr_cmp(&reg->addr, addr)) {
+                       ast_log(LOG_WARNING, "Received unsolicited registry authenticate request from '%s'\n", ast_sockaddr_stringify(addr));
                        return -1;
                }
                if (ast_strlen_zero(reg->secret)) {
@@ -8934,9 +9228,9 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
                        char tmpkey[256];
                        ast_copy_string(tmpkey, reg->secret + 1, sizeof(tmpkey));
                        tmpkey[strlen(tmpkey) - 1] = '\0';
-                       res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, sin, NULL);
+                       res = authenticate(challenge, NULL, tmpkey, authmethods, &ied, addr, NULL);
                } else
-                       res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, sin, NULL);
+                       res = authenticate(challenge, reg->secret, NULL, authmethods, &ied, addr, NULL);
                if (!res) {
                        reg->regstate = REG_STATE_AUTHSENT;
                        add_empty_calltoken_ie(iaxs[callno], &ied); /* this _MUST_ be the last ie added */
@@ -8944,7 +9238,7 @@ static int registry_rerequest(struct iax_ies *ies, int callno, struct sockaddr_i
                } else
                        return -1;
                ast_log(LOG_WARNING, "Registry acknowledge on unknown registery '%s'\n", peer);
-       } else  
+       } else
                ast_log(LOG_NOTICE, "Can't reregister without a reg\n");
        return -1;
 }
@@ -8983,7 +9277,7 @@ static int auth_reject(const void *data)
        ast_mutex_unlock(&iaxsl[callno]);
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__auth_reject, data))
-#endif         
+#endif
                __auth_reject(data);
        return 0;
 }
@@ -8995,7 +9289,7 @@ static int auth_fail(int callno, int failcode)
        if (iaxs[callno]) {
                iaxs[callno]->authfail = failcode;
                if (delayreject) {
-                       iaxs[callno]->authid = iax2_sched_replace(iaxs[callno]->authid, 
+                       iaxs[callno]->authid = iax2_sched_replace(iaxs[callno]->authid,
                                sched, 1000, auth_reject, (void *)(long)callno);
                } else
                        auth_reject((void *)(long)callno);
@@ -9028,7 +9322,7 @@ static int auto_hangup(const void *data)
        ast_mutex_unlock(&iaxsl[callno]);
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__auto_hangup, data))
-#endif         
+#endif
                __auto_hangup(data);
        return 0;
 }
@@ -9037,7 +9331,7 @@ static void iax2_dprequest(struct iax2_dpcache *dp, int callno)
 {
        struct iax_ie_data ied;
        /* Auto-hangup with 30 seconds of inactivity */
-       iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid, 
+       iaxs[callno]->autoid = iax2_sched_replace(iaxs[callno]->autoid,
                sched, 30000, auto_hangup, (void *)(long)callno);
        memset(&ied, 0, sizeof(ied));
        iax_ie_append_str(&ied, IAX_IE_CALLED_NUMBER, dp->exten);
@@ -9076,7 +9370,7 @@ static int iax2_poke_peer_s(const void *data)
        peer->pokeexpire = -1;
 #ifdef SCHED_MULTITHREADED
        if (schedule_action(__iax2_poke_peer_s, data))
-#endif         
+#endif
                __iax2_poke_peer_s(data);
        return 0;
 }
@@ -9088,7 +9382,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
        struct ast_iax2_meta_hdr *meta;
        struct ast_iax2_meta_trunk_hdr *mth;
        int calls = 0;
-       
+
        /* Point to frame */
        fr = (struct iax_frame *)tpeer->trunkdata;
        /* Point to meta data */
@@ -9127,7 +9421,7 @@ static int send_trunk(struct iax2_trunk_peer *tpeer, struct timeval *now)
 static inline int iax2_trunk_expired(struct iax2_trunk_peer *tpeer, struct timeval *now)
 {
        /* Drop when trunk is about 5 seconds idle */
-       if (now->tv_sec > tpeer->trunkact.tv_sec + 5) 
+       if (now->tv_sec > tpeer->trunkact.tv_sec + 5)
                return 1;
        return 0;
 }
@@ -9138,8 +9432,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
        struct iax2_trunk_peer *tpeer = NULL, *drop = NULL;
        struct timeval now = ast_tvnow();
 
-       if (iaxtrunkdebug)
+       if (iaxtrunkdebug) {
                ast_verbose("Beginning trunk processing. Trunk queue ceiling is %d bytes per host\n", trunkmaxsize);
+       }
 
        if (timer) {
                if (ast_timer_ack(timer, 1) < 0) {
@@ -9164,8 +9459,14 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                } else {
                        res = send_trunk(tpeer, &now);
                        trunk_timed++;
-                       if (iaxtrunkdebug)
-                               ast_verbose(" - Trunk peer (%s:%d) has %d call chunk%s in transit, %d bytes backloged and has hit a high water mark of %d bytes\n", ast_inet_ntoa(tpeer->addr.sin_addr), ntohs(tpeer->addr.sin_port), res, (res != 1) ? "s" : "", tpeer->trunkdatalen, tpeer->trunkdataalloc);
+                       if (iaxtrunkdebug) {
+                               ast_verbose(" - Trunk peer (%s) has %d call chunk%s in transit, %u bytes backloged and has hit a high water mark of %u bytes\n",
+                                                       ast_sockaddr_stringify(&tpeer->addr),
+                                                       res,
+                                                       (res != 1) ? "s" : "",
+                                                       tpeer->trunkdatalen,
+                                                       tpeer->trunkdataalloc);
+                       }
                }
                totalcalls += res;
                res = 0;
@@ -9176,9 +9477,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
 
        if (drop) {
                ast_mutex_lock(&drop->lock);
-               /* Once we have this lock, we're sure nobody else is using it or could use it once we release it, 
-                  because by the time they could get tpeerlock, we've already grabbed it */
-               ast_debug(1, "Dropping unused iax2 trunk peer '%s:%d'\n", ast_inet_ntoa(drop->addr.sin_addr), ntohs(drop->addr.sin_port));
+               /*  Once we have this lock, we're sure nobody else is using it or could use it once we release it,
+                       because by the time they could get tpeerlock, we've already grabbed it */
+               ast_debug(1, "Dropping unused iax2 trunk peer '%s'\n", ast_sockaddr_stringify(&drop->addr));
                if (drop->trunkdata) {
                        ast_free(drop->trunkdata);
                        drop->trunkdata = NULL;
@@ -9188,8 +9489,9 @@ static int timing_read(int *id, int fd, short events, void *cbdata)
                ast_free(drop);
        }
 
-       if (iaxtrunkdebug)
+       if (iaxtrunkdebug) {
                ast_verbose("Ending trunk processing with %d peers and %d call chunks processed\n", processed, totalcalls);
+       }
        iaxtrunkdebug = 0;
 
        return 1;
@@ -9211,7 +9513,7 @@ static void dp_lookup(int callno, const char *context, const char *callednum, co
        memset(&ied1, 0, sizeof(ied1));
        mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
        /* Must be started */
-       if (ast_parking_ext_valid(callednum, NULL, context) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
+       if (ast_exists_extension(NULL, context, callednum, 1, callerid)) {
                dpstatus = IAX_DPSTATUS_EXISTS;
        } else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
                dpstatus = IAX_DPSTATUS_CANEXIST;
@@ -9249,7 +9551,7 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
 {
        pthread_t newthread;
        struct dpreq_data *dpr;
-       
+
        if (!(dpr = ast_calloc(1, sizeof(*dpr))))
                return;
 
@@ -9263,7 +9565,7 @@ static void spawn_dp_lookup(int callno, const char *context, const char *calledn
        }
 }
 
-static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, unsigned int ver)
+static int check_provisioning(struct ast_sockaddr *addr, int sockfd, char *si, unsigned int ver)
 {
        unsigned int ourver;
        char rsi[80];
@@ -9272,7 +9574,7 @@ static int check_provisioning(struct sockaddr_in *sin, int sockfd, char *si, uns
                return 0;
        ast_debug(1, "Service identifier '%s', we think '%08x', they think '%08x'\n", si, ourver, ver);
        if (ourver != ver)
-               iax2_provision(sin, sockfd, NULL, rsi, 1);
+               iax2_provision(addr, sockfd, NULL, rsi, 1);
        return 0;
 }
 
@@ -9292,7 +9594,7 @@ static void construct_rr(struct chan_iax2_pvt *pvt, struct iax_ie_data *iep)
        iax_ie_append_int(iep,IAX_IE_RR_OOO, stats.frames_ooo);
 }
 
-static void save_rr(struct iax_frame *fr, struct iax_ies *ies) 
+static void save_rr(struct iax_frame *fr, struct iax_ies *ies)
 {
        iaxs[fr->callno]->remote_rr.jitter = ies->rr_jitter;
        iaxs[fr->callno]->remote_rr.losspct = ies->rr_loss >> 24;
@@ -9303,7 +9605,7 @@ static void save_rr(struct iax_frame *fr, struct iax_ies *ies)
        iaxs[fr->callno]->remote_rr.ooo = ies->rr_ooo;
 }
 
-static void save_osptoken(struct iax_frame *fr, struct iax_ies *ies) 
+static void save_osptoken(struct iax_frame *fr, struct iax_ies *ies)
 {
        int i;
        unsigned int length, offset = 0;
@@ -9350,24 +9652,7 @@ static void log_jitterstats(unsigned short callno)
                        localooo = jbinfo.frames_ooo;
                        localpackets = jbinfo.frames_in;
                }
-               ast_debug(3, "JB STATS:%s ping=%d ljitterms=%d ljbdelayms=%d ltotlost=%d lrecentlosspct=%d ldropped=%d looo=%d lrecvd=%d rjitterms=%d rjbdelayms=%d rtotlost=%d rrecentlosspct=%d rdropped=%d rooo=%d rrecvd=%d\n",
-                       ast_channel_name(iaxs[callno]->owner),
-                       iaxs[callno]->pingtime,
-                       localjitter,
-                       localdelay,
-                       locallost,
-                       locallosspct,
-                       localdropped,
-                       localooo,
-                       localpackets,
-                       iaxs[callno]->remote_rr.jitter,
-                       iaxs[callno]->remote_rr.delay,
-                       iaxs[callno]->remote_rr.losscnt,
-                       iaxs[callno]->remote_rr.losspct/1000,
-                       iaxs[callno]->remote_rr.dropped,
-                       iaxs[callno]->remote_rr.ooo,
-                       iaxs[callno]->remote_rr.packets);
-               manager_event(EVENT_FLAG_REPORTING, "JitterBufStats", "Owner: %s\r\nPing: %d\r\nLocalJitter: %d\r\nLocalJBDelay: %d\r\nLocalTotalLost: %d\r\nLocalLossPercent: %d\r\nLocalDropped: %d\r\nLocalooo: %d\r\nLocalReceived: %d\r\nRemoteJitter: %d\r\nRemoteJBDelay: %d\r\nRemoteTotalLost: %d\r\nRemoteLossPercent: %d\r\nRemoteDropped: %d\r\nRemoteooo: %d\r\nRemoteReceived: %d\r\n",
+               ast_debug(3, "JB STATS:%s ping=%u ljitterms=%d ljbdelayms=%d ltotlost=%d lrecentlosspct=%d ldropped=%d looo=%d lrecvd=%d rjitterms=%d rjbdelayms=%d rtotlost=%d rrecentlosspct=%d rdropped=%d rooo=%d rrecvd=%d\n",
                        ast_channel_name(iaxs[callno]->owner),
                        iaxs[callno]->pingtime,
                        localjitter,
@@ -9405,7 +9690,7 @@ static void handle_deferred_full_frames(struct iax2_thread *thread)
                thread->buf = pkt_buf->buf;
                thread->buf_len = pkt_buf->len;
                thread->buf_size = pkt_buf->len + 1;
-               
+
                socket_process(thread);
 
                thread->buf = NULL;
@@ -9457,23 +9742,22 @@ static void defer_full_frame(struct iax2_thread *from_here, struct iax2_thread *
 static int socket_read(int *id, int fd, short events, void *cbdata)
 {
        struct iax2_thread *thread;
-       socklen_t len;
        time_t t;
        static time_t last_errtime = 0;
        struct ast_iax2_full_hdr *fh;
 
        if (!(thread = find_idle_thread())) {
                time(&t);
-               if (t != last_errtime)
+               if (t != last_errtime) {
+                       last_errtime = t;
                        ast_debug(1, "Out of idle IAX2 threads for I/O, pausing!\n");
-               last_errtime = t;
+               }
                usleep(1);
                return 1;
        }
 
-       len = sizeof(thread->iosin);
        thread->iofd = fd;
-       thread->buf_len = recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, (struct sockaddr *) &thread->iosin, &len);
+       thread->buf_len = ast_recvfrom(fd, thread->readbuf, sizeof(thread->readbuf), 0, &thread->ioaddr);
        thread->buf_size = sizeof(thread->readbuf);
        thread->buf = thread->readbuf;
        if (thread->buf_len < 0) {
@@ -9489,7 +9773,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                signal_condition(&thread->lock, &thread->cond);
                return 1;
        }
-       
+
        /* Determine if this frame is a full frame; if so, and any thread is currently
           processing a full frame for the same callno from this peer, then drop this
           frame (and the peer will retransmit it) */
@@ -9497,11 +9781,11 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        if (ntohs(fh->scallno) & IAX_FLAG_FULL) {
                struct iax2_thread *cur = NULL;
                uint16_t callno = ntohs(fh->scallno) & ~IAX_FLAG_FULL;
-               
+
                AST_LIST_LOCK(&active_list);
                AST_LIST_TRAVERSE(&active_list, cur, list) {
                        if ((cur->ffinfo.callno == callno) &&
-                           !inaddrcmp(&cur->ffinfo.sin, &thread->iosin))
+                           !ast_sockaddr_cmp_addr(&cur->ffinfo.addr, &thread->ioaddr))
                                break;
                }
                if (cur) {
@@ -9515,14 +9799,14 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                } else {
                        /* this thread is going to process this frame, so mark it */
                        thread->ffinfo.callno = callno;
-                       memcpy(&thread->ffinfo.sin, &thread->iosin, sizeof(thread->ffinfo.sin));
+                       ast_sockaddr_copy(&thread->ffinfo.addr, &thread->ioaddr);
                        thread->ffinfo.type = fh->type;
                        thread->ffinfo.csub = fh->csub;
                        AST_LIST_INSERT_HEAD(&active_list, thread, list);
                }
                AST_LIST_UNLOCK(&active_list);
        }
-       
+
        /* Mark as ready and send on its way */
        thread->iostate = IAX_IOSTATE_READY;
 #ifdef DEBUG_SCHED_MULTITHREAD
@@ -9533,7 +9817,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
        return 1;
 }
 
-static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct sockaddr_in *sin, int sockfd,
+static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, struct ast_sockaddr *addr, int sockfd,
        struct iax_frame *fr)
 {
        unsigned char metatype;
@@ -9547,8 +9831,8 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
        struct ast_frame f = { 0, };
 
        if (packet_len < sizeof(*meta)) {
-               ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a meta frame but is too short\n", 
-                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a meta frame but is too short\n",
+                               ast_sockaddr_stringify(addr));
                return 1;
        }
 
@@ -9565,10 +9849,10 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
        metatype = meta->cmddata;
        packet_len -= (sizeof(*meta) + sizeof(*mth));
        ptr = mth->data;
-       tpeer = find_tpeer(sin, sockfd);
+       tpeer = find_tpeer(addr, sockfd);
        if (!tpeer) {
-               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s:%d': No matching peer\n", 
-                       ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+               ast_log(LOG_WARNING, "Unable to accept trunked packet from '%s': No matching peer\n",
+                               ast_sockaddr_stringify(addr));
                return 1;
        }
        tpeer->trunkact = ast_tvnow();
@@ -9595,13 +9879,13 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                        callno = ntohs(mte->callno);
                        trunked_ts = 0;
                } else {
-                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s:%d': dropping\n", ast_inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
+                       ast_log(LOG_WARNING, "Unknown meta trunk cmd from '%s': dropping\n", ast_sockaddr_stringify(addr));
                        break;
                }
                /* Stop if we don't have enough data */
                if (len > packet_len)
                        break;
-               fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, sin, NEW_PREVENT, sockfd, 0);
+               fr->callno = find_callno_locked(callno & ~IAX_FLAG_FULL, 0, addr, NEW_PREVENT, sockfd, 0);
                if (!fr->callno)
                        continue;
 
@@ -9616,7 +9900,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                        ast_log(LOG_WARNING, "Received trunked frame before first full voice frame\n");
                        iax2_vnak(fr->callno);
                } else {
-                       ast_format_from_old_bitfield(&f.subclass.format, iaxs[fr->callno]->voiceformat);
+                       f.subclass.format = ast_format_compatibility_bitfield2format(iaxs[fr->callno]->voiceformat);
                        f.datalen = len;
                        if (f.datalen >= 0) {
                                if (f.datalen)
@@ -9635,8 +9919,8 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                                        f.src = "IAX2";
                                        f.mallocd = 0;
                                        f.offset = 0;
-                                       if (f.datalen && (f.frametype == AST_FRAME_VOICE)) 
-                                               f.samples = ast_codec_get_samples(&f);
+                                       if (f.datalen && (f.frametype == AST_FRAME_VOICE))
+                                               f.samples = ast_codec_samples_count(&f);
                                        else
                                                f.samples = 0;
                                        fr->outoforder = 0;
@@ -9661,10 +9945,16 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
 
 static int acf_iaxvar_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 {
-       struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
+       struct ast_datastore *variablestore;
        AST_LIST_HEAD(, ast_var_t) *varlist;
        struct ast_var_t *var;
 
+       if (!chan) {
+               ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+               return -1;
+       }
+
+       variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
        if (!variablestore) {
                *buf = '\0';
                return 0;
@@ -9684,10 +9974,16 @@ static int acf_iaxvar_read(struct ast_channel *chan, const char *cmd, char *data
 
 static int acf_iaxvar_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
 {
-       struct ast_datastore *variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
+       struct ast_datastore *variablestore;
        AST_LIST_HEAD(, ast_var_t) *varlist;
        struct ast_var_t *var;
 
+       if (!chan) {
+               ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
+               return -1;
+       }
+
+       variablestore = ast_channel_datastore_find(chan, &iax2_variable_datastore_info, NULL);
        if (!variablestore) {
                variablestore = ast_datastore_alloc(&iax2_variable_datastore_info, NULL);
                if (!variablestore) {
@@ -9755,7 +10051,7 @@ static void set_hangup_source_and_cause(int callno, unsigned char causecode)
 
 static int socket_process_helper(struct iax2_thread *thread)
 {
-       struct sockaddr_in sin;
+       struct ast_sockaddr addr;
        int res;
        int updatehistory=1;
        int new = NEW_PREVENT;
@@ -9781,7 +10077,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        struct iax_frame *duped_fr;
        char host_pref_buf[128];
        char caller_pref_buf[128];
-       struct ast_codec_pref pref;
+       struct iax2_codec_pref pref;
        char *using_prefs = "mine";
 
        /* allocate an iax_frame with 4096 bytes of data buffer */
@@ -9792,7 +10088,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        /* Copy frequently used parameters to the stack */
        res = thread->buf_len;
        fd = thread->iofd;
-       memcpy(&sin, &thread->iosin, sizeof(sin));
+       ast_sockaddr_copy(&addr, &thread->ioaddr);
 
        if (res < sizeof(*mh)) {
                ast_log(LOG_WARNING, "midget packet received (%d of %d min)\n", res, (int) sizeof(*mh));
@@ -9800,23 +10096,25 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
        if ((vh->zeros == 0) && (ntohs(vh->callno) & 0x8000)) {
                if (res < sizeof(*vh)) {
-                       ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a video frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+                       ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a video frame but is too short\n",
+                                       ast_sockaddr_stringify(&addr));
                        return 1;
                }
 
                /* This is a video frame, get call number */
-               fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &sin, new, fd, 0);
+               fr->callno = find_callno(ntohs(vh->callno) & ~0x8000, dcallno, &addr, new, fd, 0);
                minivid = 1;
        } else if ((meta->zeros == 0) && !(ntohs(meta->metacmd) & 0x8000))
-               return socket_process_meta(res, meta, &sin, fd, fr);
+               return socket_process_meta(res, meta, &addr, fd, fr);
 
 #ifdef DEBUG_SUPPORT
        if (res >= sizeof(*fh))
-               iax_outputframe(NULL, fh, 1, &sin, res - sizeof(*fh));
+               iax_outputframe(NULL, fh, 1, &addr, res - sizeof(*fh));
 #endif
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
                if (res < sizeof(*fh)) {
-                       ast_log(LOG_WARNING, "Rejecting packet from '%s.%d' that is flagged as a full frame but is too short\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
+                       ast_log(LOG_WARNING, "Rejecting packet from '%s' that is flagged as a full frame but is too short\n",
+                               ast_sockaddr_stringify(&addr));
                        return 1;
                }
 
@@ -9825,10 +10123,10 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 
                /* check to make sure this full frame isn't encrypted before we attempt
-                * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
+                * to look inside of it. If it is encrypted, decrypt it first. Its ok if the
                 * callno is not found here, that just means one hasn't been allocated for
                 * this connection yet. */
-               if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, NEW_PREVENT, fd, 1))) {
+               if ((dcallno != 1) && (fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, NEW_PREVENT, fd, 1))) {
                        ast_mutex_lock(&iaxsl[fr->callno]);
                        if (iaxs[fr->callno] && ast_test_flag64(iaxs[fr->callno], IAX_ENCRYPTED)) {
                                if (decrypt_frame(fr->callno, fh, &f, &res)) {
@@ -9844,12 +10142,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                /* Retrieve the type and subclass */
                f.frametype = fh->type;
                if (f.frametype == AST_FRAME_VIDEO) {
-                       ast_format_from_old_bitfield(&f.subclass.format, (uncompress_subclass(fh->csub & ~0x40)));
+                       f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub & ~0x40));
                        if ((fh->csub >> 6) & 0x1) {
-                               ast_format_set_video_mark(&f.subclass.format);
+                               f.subclass.frame_ending = 1;
                        }
                } else if (f.frametype == AST_FRAME_VOICE) {
-                       ast_format_from_old_bitfield(&f.subclass.format, uncompress_subclass(fh->csub));
+                       f.subclass.format = ast_format_compatibility_bitfield2format(uncompress_subclass(fh->csub));
                } else {
                        f.subclass.integer = uncompress_subclass(fh->csub);
                }
@@ -9857,7 +10155,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                /* Deal with POKE/PONG without allocating a callno */
                if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_POKE) {
                        /* Reply back with a PONG, but don't care about the result. */
-                       send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                       send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_PONG, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        return 1;
                } else if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_ACK && dcallno == 1) {
                        /* Ignore */
@@ -9868,7 +10166,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                if (f.datalen) {
                        if (f.frametype == AST_FRAME_IAX) {
                                if (iax_parse_ies(&ies, thread->buf + sizeof(struct ast_iax2_full_hdr), f.datalen)) {
-                                       ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_inet_ntoa(sin.sin_addr));
+                                       ast_log(LOG_WARNING, "Undecodable frame received from '%s'\n", ast_sockaddr_stringify(&addr));
                                        ast_variables_destroy(ies.vars);
                                        return 1;
                                }
@@ -9888,7 +10186,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
                if (!dcallno && iax2_allow_new(f.frametype, f.subclass.integer, 1)) {
                        /* only set NEW_ALLOW if calltoken checks out */
-                       if (handle_call_token(fh, &ies, &sin, fd)) {
+                       if (handle_call_token(fh, &ies, &addr, fd)) {
                                ast_variables_destroy(ies.vars);
                                return 1;
                        }
@@ -9918,18 +10216,18 @@ static int socket_process_helper(struct iax2_thread *thread)
                 * end to know the destination call number before call setup can complete.
                 *
                 * Discussed in the following thread:
-                *    http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html 
+                *    http://lists.digium.com/pipermail/asterisk-dev/2008-May/033217.html
                 */
 
                if ((ntohs(mh->callno) & IAX_FLAG_FULL) && ((f.frametype == AST_FRAME_IAX) && (f.subclass.integer == IAX_COMMAND_ACK))) {
                        check_dcallno = 1;
                }
 
-               if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &sin, new, fd, check_dcallno))) {
+               if (!(fr->callno = find_callno(ntohs(mh->callno) & ~IAX_FLAG_FULL, dcallno, &addr, new, fd, check_dcallno))) {
                        if (f.frametype == AST_FRAME_IAX && f.subclass.integer == IAX_COMMAND_NEW) {
-                               send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                               send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REJECT, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        } else if (f.frametype == AST_FRAME_IAX && (f.subclass.integer == IAX_COMMAND_REGREQ || f.subclass.integer == IAX_COMMAND_REGREL)) {
-                               send_apathetic_reply(1, ntohs(fh->scallno), &sin, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
+                               send_apathetic_reply(1, ntohs(fh->scallno), &addr, IAX_COMMAND_REGREJ, ntohl(fh->ts), fh->iseqno + 1, fd, NULL);
                        }
                        ast_variables_destroy(ies.vars);
                        return 1;
@@ -9937,12 +10235,11 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
 
        if (fr->callno > 0) {
-               struct ast_callid *mount_callid;
+               ast_callid mount_callid;
                ast_mutex_lock(&iaxsl[fr->callno]);
                if (iaxs[fr->callno] && ((mount_callid = iax_pvt_callid_get(fr->callno)))) {
                        /* Bind to thread */
                        ast_callid_threadassoc_add(mount_callid);
-                       ast_callid_unref(mount_callid);
                }
        }
 
@@ -9956,11 +10253,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                 (f.subclass.integer != IAX_COMMAND_TXACC) &&
                                 (f.subclass.integer != IAX_COMMAND_FWDOWNL))||
                            (f.frametype != AST_FRAME_IAX))
-                               raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
+                               raw_hangup(&addr, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL,
                                fd);
                }
-               if (fr->callno > 0) 
+               if (fr->callno > 0){
                        ast_mutex_unlock(&iaxsl[fr->callno]);
+               }
                ast_variables_destroy(ies.vars);
                return 1;
        }
@@ -9976,7 +10274,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
 #ifdef DEBUG_SUPPORT
        if (decrypted) {
-               iax_outputframe(NULL, fh, 3, &sin, res - sizeof(*fh));
+               iax_outputframe(NULL, fh, 3, &addr, res - sizeof(*fh));
        }
 #endif
 
@@ -10006,6 +10304,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                data_size += strlen(subclass);
 
                cause_code = ast_alloca(data_size);
+               memset(cause_code, 0, data_size);
                ast_copy_string(cause_code->chan_name, ast_channel_name(iaxs[fr->callno]->owner), AST_CHANNEL_NAME);
 
                cause_code->ast_cause = ies.causecode;
@@ -10027,7 +10326,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        /* count this frame */
        iaxs[fr->callno]->frames_received++;
 
-       if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) && !minivid &&
+       if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) && !minivid &&
                f.subclass.integer != IAX_COMMAND_TXCNT &&              /* for attended transfer */
                f.subclass.integer != IAX_COMMAND_TXACC) {              /* for attended transfer */
                unsigned short new_peercallno;
@@ -10043,7 +10342,7 @@ static int socket_process_helper(struct iax2_thread *thread)
        }
        if (ntohs(mh->callno) & IAX_FLAG_FULL) {
                if (iaxdebug)
-                       ast_debug(1, "Received packet %d, (%d, %u)\n", fh->oseqno, f.frametype, f.subclass.integer);
+                       ast_debug(1, "Received packet %d, (%u, %d)\n", fh->oseqno, f.frametype, f.subclass.integer);
                /* Check if it's out of order (and not an ACK or INVAL) */
                fr->oseqno = fh->oseqno;
                fr->iseqno = fh->iseqno;
@@ -10083,7 +10382,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                          (f.subclass.integer != IAX_COMMAND_VNAK)) ||
                          (f.frametype != AST_FRAME_IAX)) {
                                /* If it's not an ACK packet, it's out of order. */
-                               ast_debug(1, "Packet arrived out of order (expecting %d, got %d) (frametype = %d, subclass = %d)\n",
+                               ast_debug(1, "Packet arrived out of order (expecting %d, got %d) (frametype = %u, subclass = %d)\n",
                                        iaxs[fr->callno]->iseqno, fr->oseqno, f.frametype, f.subclass.integer);
                                /* Check to see if we need to request retransmission,
                                 * and take sequence number wraparound into account */
@@ -10122,9 +10421,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                thread->buf[res - 1] = '\0';
                }
 
-               /* Handle implicit ACKing unless this is an INVAL, and only if this is 
+               /* Handle implicit ACKing unless this is an INVAL, and only if this is
                   from the real peer, not the transfer peer */
-               if (!inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
+               if (!ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
                    ((f.subclass.integer != IAX_COMMAND_INVAL) ||
                     (f.frametype != AST_FRAME_IAX))) {
                        unsigned char x;
@@ -10172,7 +10471,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                ast_debug(1, "Received iseqno %d not within window %d->%d\n", fr->iseqno, iaxs[fr->callno]->rseqno, iaxs[fr->callno]->oseqno);
                        }
                }
-               if (inaddrcmp(&sin, &iaxs[fr->callno]->addr) &&
+               if (ast_sockaddr_cmp(&addr, &iaxs[fr->callno]->addr) &&
                        ((f.frametype != AST_FRAME_IAX) ||
                         ((f.subclass.integer != IAX_COMMAND_TXACC) &&
                          (f.subclass.integer != IAX_COMMAND_TXCNT)))) {
@@ -10190,8 +10489,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                    (f.frametype == AST_FRAME_IAX)) {
                        if (ast_test_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART)) {
                                ast_clear_flag64(iaxs[fr->callno], IAX_DELAYPBXSTART);
-                               if (!ast_iax2_new(fr->callno, AST_STATE_RING, iaxs[fr->callno]->chosenformat, NULL,
-                                                 ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
+                               if (!ast_iax2_new(fr->callno, AST_STATE_RING,
+                                       iaxs[fr->callno]->chosenformat, &iaxs[fr->callno]->rprefs, NULL, NULL,
+                                       ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_AUTHENTICATED))) {
                                        ast_variables_destroy(ies.vars);
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
                                        return 1;
@@ -10271,24 +10571,23 @@ static int socket_process_helper(struct iax2_thread *thread)
                }
 
                if (f.frametype == AST_FRAME_VOICE) {
-                       if (ast_format_to_old_bitfield(&f.subclass.format) != iaxs[fr->callno]->voiceformat) {
-                                       iaxs[fr->callno]->voiceformat = ast_format_to_old_bitfield(&f.subclass.format);
-                                       ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_getformatname(&f.subclass.format));
+                       if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->voiceformat) {
+                                       iaxs[fr->callno]->voiceformat = ast_format_compatibility_format2bitfield(f.subclass.format);
+                                       ast_debug(1, "Ooh, voice format changed to '%s'\n", ast_format_get_name(f.subclass.format));
                                        if (iaxs[fr->callno]->owner) {
                                                iax2_lock_owner(fr->callno);
                                                if (iaxs[fr->callno]) {
                                                        if (iaxs[fr->callno]->owner) {
-                                                               struct ast_format_cap *orignative = ast_format_cap_dup(ast_channel_nativeformats(iaxs[fr->callno]->owner));
-                                                               struct ast_format_cap *native = ast_channel_nativeformats(iaxs[fr->callno]->owner);
-                                                               if (orignative) {
-                                                                       ast_format_cap_set(native, &f.subclass.format);
-                                                                       if (ast_channel_readformat(iaxs[fr->callno]->owner)->id) {
+                                                               struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+                                                               if (native) {
+                                                                       ast_format_cap_append(native, f.subclass.format, 0);
+                                                                       ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
+                                                                       if (ast_channel_readformat(iaxs[fr->callno]->owner)) {
                                                                                ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
                                                                        }
-                                                                       ast_format_cap_copy(native, orignative);
-                                                                       ast_channel_unlock(iaxs[fr->callno]->owner);
-                                                                       orignative = ast_format_cap_destroy(orignative);
+                                                                       ao2_ref(native, -1);
                                                                }
+                                                               ast_channel_unlock(iaxs[fr->callno]->owner);
                                                        }
                                                } else {
                                                        ast_debug(1, "Neat, somebody took away the channel at a magical time but i found it!\n");
@@ -10305,16 +10604,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                        }
                }
                if (f.frametype == AST_FRAME_VIDEO) {
-                       if (f.subclass.format.id != ast_format_id_from_old_bitfield(iaxs[fr->callno]->videoformat)) {
-                               ast_debug(1, "Ooh, video format changed to %s\n", ast_getformatname(&f.subclass.format));
-                               iaxs[fr->callno]->videoformat = ast_format_to_old_bitfield(&f.subclass.format);
-                       }
-               }
-               if (f.frametype == AST_FRAME_CONTROL && iaxs[fr->callno]->owner) {
-                       if (f.subclass.integer == AST_CONTROL_BUSY) {
-                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_BUSY);
-                       } else if (f.subclass.integer == AST_CONTROL_CONGESTION) {
-                               ast_channel_hangupcause_set(iaxs[fr->callno]->owner, AST_CAUSE_CONGESTION);
+                       if (ast_format_compatibility_format2bitfield(f.subclass.format) != iaxs[fr->callno]->videoformat) {
+                               ast_debug(1, "Ooh, video format changed to %s\n", ast_format_get_name(f.subclass.format));
+                               iaxs[fr->callno]->videoformat = ast_format_compatibility_format2bitfield(f.subclass.format);
                        }
                }
                if (f.frametype == AST_FRAME_IAX) {
@@ -10330,7 +10622,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                             f.subclass.integer != IAX_COMMAND_LAGRP) {
                                iaxs[fr->callno]->last = fr->ts;
                                if (iaxdebug)
-                                       ast_debug(1, "For call=%d, set last=%d\n", fr->callno, fr->ts);
+                                       ast_debug(1, "For call=%d, set last=%u\n", fr->callno, fr->ts);
                        }
                        iaxs[fr->callno]->last_iax_message = f.subclass.integer;
                        if (!iaxs[fr->callno]->first_iax_message) {
@@ -10400,9 +10692,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                /* Ignore if it's already up */
                                if (ast_test_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED | IAX_STATE_TBD))
                                        break;
-                               if (ies.provverpres && ies.serviceident && sin.sin_addr.s_addr) {
+                               if (ies.provverpres && ies.serviceident && !(ast_sockaddr_isnull(&addr))) {
                                        ast_mutex_unlock(&iaxsl[fr->callno]);
-                                       check_provisioning(&sin, fd, ies.serviceident, ies.provver);
+                                       check_provisioning(&addr, fd, ies.serviceident, ies.provver);
                                        ast_mutex_lock(&iaxsl[fr->callno]);
                                        if (!iaxs[fr->callno]) {
                                                break;
@@ -10417,11 +10709,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                /* For security, always ack immediately */
                                if (delayreject)
                                        send_command_immediate(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_ACK, fr->ts, NULL, 0,fr->iseqno);
-                               if (check_access(fr->callno, &sin, &ies)) {
+                               if (check_access(fr->callno, &addr, &ies)) {
                                        /* They're not allowed on */
                                        auth_fail(fr->callno, IAX_COMMAND_REJECT);
-                                       if (authdebug)
-                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                       if (authdebug) {
+                                               ast_log(LOG_NOTICE, "Rejected connect attempt from %s, who was trying to reach '%s@%s'\n",
+                                                               ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                       }
                                        break;
                                }
                                if (ast_strlen_zero(iaxs[fr->callno]->secret) && ast_test_flag64(iaxs[fr->callno], IAX_FORCE_ENCRYPT)) {
@@ -10457,8 +10751,10 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                if (!iaxs[fr->callno]) {
                                                        break;
                                                }
-                                               if (authdebug)
-                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n", ast_inet_ntoa(sin.sin_addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                               if (authdebug) {
+                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, request '%s@%s' does not exist\n",
+                                                                       ast_sockaddr_stringify(&addr), iaxs[fr->callno]->exten, iaxs[fr->callno]->context);
+                                               }
                                        } else {
                                                /* Select an appropriate format */
 
@@ -10473,12 +10769,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        strcpy(caller_pref_buf, "disabled");
                                                        strcpy(host_pref_buf, "disabled");
                                                } else {
-                                                       struct ast_format tmpfmt;
+                                                       struct ast_format *tmpfmt;
                                                        using_prefs = "mine";
                                                        /* If the information elements are in here... use them */
                                                        if (ies.codec_prefs)
-                                                               ast_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
-                                                       if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                               iax2_codec_pref_convert(&iaxs[fr->callno]->rprefs, ies.codec_prefs, 32, 0);
+                                                       if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                                /* If we are codec_first_choice we let the caller have the 1st shot at picking the codec.*/
                                                                if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                        pref = iaxs[fr->callno]->rprefs;
@@ -10489,9 +10785,9 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        } else
                                                                pref = iaxs[fr->callno]->prefs;
 
-                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability, 0);
-                                                       ast_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
-                                                       ast_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
+                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->capability & iaxs[fr->callno]->peercapability);
+                                                       iax2_codec_pref_string(&iaxs[fr->callno]->rprefs, caller_pref_buf, sizeof(caller_pref_buf) - 1);
+                                                       iax2_codec_pref_string(&iaxs[fr->callno]->prefs, host_pref_buf, sizeof(host_pref_buf) - 1);
                                                }
                                                if (!format) {
                                                        if(!ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP))
@@ -10505,18 +10801,21 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        break;
                                                                }
                                                                if (authdebug) {
-                                                                       char tmp[256], tmp2[256], tmp3[256];
+                                                                       struct ast_str *peer_buf = ast_str_alloca(64);
+                                                                       struct ast_str *cap_buf = ast_str_alloca(64);
+                                                                       struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)) {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
-                                                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                                                       ast_sockaddr_stringify(&addr),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        } else {
                                                                                ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested/capability '%s'/'%s' incompatible with our capability '%s'.\n",
-                                                                                       ast_inet_ntoa(sin.sin_addr),
-                                                                                       iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peerformat),
-                                                                                       iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->peercapability),
-                                                                                       iax2_getformatname_multiple(tmp3, sizeof(tmp3), iaxs[fr->callno]->capability));
+                                                                                       ast_sockaddr_stringify(&addr),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peerformat, &peer_form_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf),
+                                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                                                        }
                                                                }
                                                        } else {
@@ -10528,13 +10827,13 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                        if(ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOPREFS)) {
                                                                                using_prefs = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ? "reqonly" : "disabled";
                                                                                memset(&pref, 0, sizeof(pref));
-                                                                               format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                               format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                                strcpy(caller_pref_buf,"disabled");
                                                                                strcpy(host_pref_buf,"disabled");
                                                                        } else {
-                                                                               struct ast_format tmpfmt;
+                                                                               struct ast_format *tmpfmt;
                                                                                using_prefs = "mine";
-                                                                               if (ast_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
+                                                                               if (iax2_codec_pref_index(&iaxs[fr->callno]->rprefs, 0, &tmpfmt)) {
                                                                                        /* Do the opposite of what we tried above. */
                                                                                        if (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                                                pref = iaxs[fr->callno]->prefs;
@@ -10542,28 +10841,31 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                                pref = iaxs[fr->callno]->rprefs;
                                                                                                using_prefs = "caller";
                                                                                        }
-                                                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, 1);
+                                                                                       format = iax2_codec_choose(&pref, iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                                } else /* if no codec_prefs IE do it the old way */
-                                                                                       format = iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                                       format = iax2_format_compatibility_best(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
                                                                        }
                                                                }
 
                                               &n