res_pjsip: Add option to force G.726 to be treated as AAL2 packed.
[asterisk/asterisk.git] / channels / chan_iax2.c
index 26ca36d..da6bec7 100644 (file)
  * \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>
@@ -93,23 +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/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
@@ -268,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)";
 
@@ -336,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 */
@@ -370,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)
@@ -378,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;
@@ -418,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);
@@ -492,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;
@@ -521,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_*) */
 
@@ -564,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 */
@@ -615,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);
@@ -665,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 */
@@ -695,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 */
@@ -811,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 */
@@ -820,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 */
@@ -846,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 */
@@ -900,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
@@ -943,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 */
@@ -997,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);
@@ -1036,7 +1054,7 @@ struct iax2_thread {
        int actions;
        pthread_t threadid;
        int threadnum;
-       struct sockaddr_in iosin;
+       struct ast_sockaddr ioaddr;
        unsigned char readbuf[4096];
        unsigned char *buf;
        ssize_t buf_len;
@@ -1053,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;
@@ -1089,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);
 }
 
 /*!
@@ -1147,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;
                }
        }
@@ -1213,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);
@@ -1225,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);
@@ -1242,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);
@@ -1259,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,
@@ -1284,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,
@@ -1323,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)
@@ -1370,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()) {
@@ -1384,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;
@@ -1526,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;
@@ -1543,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;
 }
@@ -1564,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]);
@@ -1588,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
@@ -1635,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]);
@@ -1655,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
@@ -1703,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;
 }
@@ -1777,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;
 }
 
@@ -1844,9 +2000,9 @@ static struct iax2_peer *find_peer(const char *name, int realtime)
        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;
 }
 
@@ -1866,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)
 {
@@ -1878,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;
@@ -1886,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;
@@ -1902,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);
@@ -1913,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)
@@ -1929,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);
@@ -2052,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;
@@ -2074,7 +2242,7 @@ static struct chan_iax2_pvt *new_iax(struct sockaddr_in *sin, const char *host)
                return NULL;
        }
 
-       tmp->prefs = prefs;
+       tmp->prefs = prefs_global;
        tmp->pingid = -1;
        tmp->lagid = -1;
        tmp->autoid = -1;
@@ -2130,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) ) {
@@ -2141,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;
@@ -2265,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)
@@ -2281,26 +2445,28 @@ 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;
@@ -2309,9 +2475,9 @@ static int addr_range_match_address_cb(void *obj, void *arg, int flags)
 /*!
  * \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;
@@ -2328,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;
        }
@@ -2336,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;
        }
 
@@ -2351,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;
@@ -2374,18 +2540,17 @@ 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);
        }
 
@@ -2425,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;
@@ -2441,7 +2601,7 @@ 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 */
        }
 }
@@ -2454,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
@@ -2475,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 */
@@ -2488,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;
        }
 
@@ -2508,9 +2667,9 @@ static int peercnt_add(struct sockaddr_in *sin)
  */
 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
@@ -2520,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 */
@@ -2546,12 +2705,12 @@ static int peercnt_remove_cb(const void *obj)
  * \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);
@@ -2664,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) {
@@ -2681,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);
                }
@@ -2874,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);
@@ -2931,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;
@@ -2951,7 +3111,7 @@ 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));
+                       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) {
@@ -2964,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]);
@@ -2980,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]);
@@ -2995,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;
@@ -3013,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;
@@ -3036,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);
@@ -3058,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);
 }
 
 /*!
@@ -3213,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();
@@ -3236,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)
@@ -3379,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)
                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);
@@ -3637,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:
@@ -3661,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");
@@ -3681,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);
+               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);
@@ -3980,9 +4138,9 @@ static void __get_from_jb(const void *p)
        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;
@@ -3996,8 +4154,8 @@ static void __get_from_jb(const void *p)
 
                        /* 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;
@@ -4048,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
@@ -4078,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;
        }
@@ -4090,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,
@@ -4224,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) {
@@ -4256,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;
                                }
                        }
@@ -4293,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;
@@ -4306,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)) {
@@ -4346,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);
@@ -4373,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;
                                }
                        }
@@ -4419,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;
@@ -4430,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));
+       port = ast_strdupa(ast_sockaddr_stringify_port(sockaddr));
        ast_update_realtime("iaxpeers", "name", peername,
-               "ipaddr", ast_sockaddr_stringify_addr(sockaddr), "port", port,
+               "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;
@@ -4448,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];
@@ -4457,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;
        }
 
@@ -4510,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));
@@ -4553,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;
@@ -4618,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 {
@@ -4640,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)
@@ -4778,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);
@@ -4795,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;
 
@@ -4825,15 +4961,15 @@ 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 */
                }
 
@@ -4844,8 +4980,8 @@ static int handle_call_token(struct ast_iax2_full_hdr *fh, struct iax_ies *ies,
 
        /* ----- 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. */
@@ -4854,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;
@@ -4878,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)
 {
@@ -4911,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;
@@ -4922,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";
@@ -4936,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)) {
@@ -4957,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;
        }
@@ -4982,8 +5120,12 @@ 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;
@@ -5000,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 +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);
 
@@ -5306,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));
@@ -5325,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;
@@ -5359,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]);
@@ -5367,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];
@@ -5426,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])
@@ -5440,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)) ||
@@ -5493,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);
@@ -5538,6 +5699,7 @@ 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)
 {
@@ -5577,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;
        }
@@ -5613,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;
@@ -5621,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;
@@ -5639,49 +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;
        }
        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_channel_set_readformat(tmp, tmpfmt);
+       ast_channel_set_rawreadformat(tmp, tmpfmt);
+       ast_channel_set_writeformat(tmp, tmpfmt);
+       ast_channel_set_rawwriteformat(tmp, tmpfmt);
 
-       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);
+       ao2_ref(tmpfmt, -1);
+       ao2_ref(native, -1);
 
        ast_channel_tech_pvt_set(tmp, CALLNO_TO_PTR(i->callno));
 
@@ -5766,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;
                }
        }
@@ -5798,7 +6020,7 @@ static unsigned int calc_txpeerstamp(struct iax2_trunk_peer *tpeer, int sampms,
        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 */
@@ -5829,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;
 
 
@@ -5841,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;
@@ -5870,7 +6093,8 @@ 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
@@ -5889,7 +6113,6 @@ static unsigned int calc_timestamp(struct chan_iax2_pvt *p, unsigned int ts, str
                                   changing at all.  But if a consistent different starts to develop it
                                   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)
@@ -5911,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 */
                                {
@@ -5939,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;
 }
 
@@ -5967,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
@@ -5995,7 +6220,7 @@ 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;
 
@@ -6003,7 +6228,7 @@ static struct iax2_trunk_peer *find_tpeer(struct sockaddr_in *sin, int fd)
        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;
                }
@@ -6013,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);
                }
        }
@@ -6042,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) {
@@ -6052,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;
                        }
@@ -6192,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;
 
@@ -6200,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);
                }
@@ -6239,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))
@@ -6343,7 +6570,8 @@ static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned in
                /* High two bytes are the same on timestamp, or sending on a trunk */ &&
            (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;
@@ -6357,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;
@@ -6412,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);
                }
@@ -6439,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)
@@ -6472,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,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,
+
+               .total_peers = 0,
+               .online_peers = 0,
+               .offline_peers = 0,
+               .unmonitored_peers = 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"
+       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;
@@ -6627,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));
-
-               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));
+               _iax2_show_peers_one(fd, s, &cont, peer);
 
-               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)
 {
@@ -6740,10 +7038,10 @@ static char *handle_cli_iax2_show_threads(struct ast_cli_entry *e, int cmd, stru
        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++;
@@ -6757,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++;
@@ -6770,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++;
@@ -6932,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;
 }
 
@@ -7014,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];
@@ -7037,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));
+
+               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));
+                               (reg->dnsmgr) ? "Y" : "N",
+                               reg->username, perceived, reg->refresh, regstate2str(reg->regstate));
                counter++;
        }
        AST_LIST_UNLOCK(&registrations);
@@ -7071,11 +7361,7 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
        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"
@@ -7093,21 +7379,17 @@ static int manager_iax2_show_registry(struct mansession *s, const struct message
        }
        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, };
@@ -7146,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,
@@ -7175,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]) {
@@ -7296,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;
@@ -7309,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)) {
@@ -7431,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);
 }
 
@@ -7479,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;
@@ -7489,7 +7771,6 @@ 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;
@@ -7534,24 +7815,26 @@ static int check_access(int callno, struct sockaddr_in *sin, struct iax_ies *ies
 
        /* 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_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)) {
@@ -7608,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);
@@ -7671,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;
@@ -7703,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);
@@ -7717,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)
@@ -7808,6 +8091,7 @@ static int authenticate_verify(struct chan_iax2_pvt *p, struct iax_ies *ies)
        if (p->authrej) {
                return res;
        }
+
        user = ao2_find(users, p->username, OBJ_KEY);
        if (user) {
                if (ast_test_flag64(p, IAX_MAXAUTHREQ)) {
@@ -7854,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, ";"))) {
@@ -7864,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;
@@ -7878,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] = "";
@@ -7891,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 */
@@ -7907,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;
        }
 
@@ -7936,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);
@@ -7998,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;
                }
@@ -8006,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);
@@ -8042,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;
@@ -8081,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);
                        }
@@ -8091,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;
 }
@@ -8100,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 */
@@ -8125,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_to_sin(&peer->addr, &peer_addr);
+                       ast_sockaddr_copy(&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 */
+                               /* 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;
@@ -8160,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) {
@@ -8223,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);
 }
@@ -8239,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 */
@@ -8264,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;
 }
@@ -8384,7 +8682,7 @@ static void iax2_publish_registry(const char *username, const char *domain, cons
 }
 
 /*! \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 */
@@ -8392,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));
@@ -8415,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 */
        }
@@ -8432,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) {
@@ -8442,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);
-               iax2_publish_registry(reg->username, ast_inet_ntoa(sin->sin_addr), "Registered", NULL);
+
+               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;
@@ -8455,23 +8753,35 @@ 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);
@@ -8577,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))
@@ -8604,8 +8914,6 @@ static int expire_registry(const void *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];
@@ -8660,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,
@@ -8672,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);
 
@@ -8690,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) {
@@ -8707,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);
 
-               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) {
+               str_addr = ast_strdupa(ast_sockaddr_stringify_addr(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}",
@@ -8744,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 */
@@ -8762,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_state_cache(), 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;
@@ -8888,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 */
@@ -8906,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)) {
@@ -8925,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 */
@@ -9129,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) {
@@ -9155,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;
@@ -9167,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;
@@ -9179,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;
@@ -9202,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;
@@ -9254,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];
@@ -9263,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;
 }
 
@@ -9341,7 +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_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,
@@ -9431,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) {
@@ -9475,7 +9785,7 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                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) {
@@ -9489,7 +9799,7 @@ 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);
@@ -9507,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;
@@ -9521,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;
        }
 
@@ -9539,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();
@@ -9569,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;
 
@@ -9590,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)
@@ -9610,7 +9920,7 @@ static int socket_process_meta(int packet_len, struct ast_iax2_meta_hdr *meta, s
                                        f.mallocd = 0;
                                        f.offset = 0;
                                        if (f.datalen && (f.frametype == AST_FRAME_VOICE))
-                                               f.samples = ast_codec_get_samples(&f);
+                                               f.samples = ast_codec_samples_count(&f);
                                        else
                                                f.samples = 0;
                                        fr->outoforder = 0;
@@ -9635,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;
@@ -9658,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) {
@@ -9729,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;
@@ -9755,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 */
@@ -9766,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));
@@ -9774,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;
                }
 
@@ -9799,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)) {
@@ -9818,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);
                }
@@ -9831,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 */
@@ -9842,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;
                                }
@@ -9862,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;
                        }
@@ -9899,11 +10223,11 @@ static int socket_process_helper(struct iax2_thread *thread)
                        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;
@@ -9911,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);
                }
        }
 
@@ -9930,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;
        }
@@ -9950,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
 
@@ -9980,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;
@@ -10001,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;
@@ -10017,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;
@@ -10057,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 */
@@ -10098,7 +10423,7 @@ static int socket_process_helper(struct iax2_thread *thread)
 
                /* 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;
@@ -10146,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)))) {
@@ -10164,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;
@@ -10245,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");
@@ -10279,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) {
@@ -10304,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) {
@@ -10374,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;
@@ -10391,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)) {
@@ -10431,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 */
 
@@ -10447,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;
@@ -10463,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))
@@ -10479,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 {
@@ -10502,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;
@@ -10516,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);
                                                                        }
                                                                }
 
                                                                if (!format) {
-                                                                       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);
+
                                                                        memset(&ied0, 0, sizeof(ied0));
                                                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
                                                                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_BEARERCAPABILITY_NOTAVAIL);
-                                                                       ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(tmp, sizeof(tmp), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
+                                                                       ast_log(LOG_ERROR, "No best format in '%s'???\n", iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
                                                                        send_command_final(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
                                                                        if (!iaxs[fr->callno]) {
                                                                                break;
                                                                        }
                                                                        if (authdebug) {
                                                                                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));
                                                                        }
                                                                        ast_set_flag64(iaxs[fr->callno], IAX_ALREADYGONE);
                                                                        break;
@@ -10558,7 +10886,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                                "%sactual format = %s,\n"
                                                                                                "%shost prefs = %s,\n"
                                                                                                "%spriority = %s\n",
-                                                                                               ast_inet_ntoa(sin.sin_addr),
+                                                                                               ast_sockaddr_stringify(&addr),
                                                                                                VERBOSE_PREFIX_4,
                                                                                                iax2_getformatname(iaxs[fr->callno]->peerformat),
                                                                                                VERBOSE_PREFIX_4,
@@ -10578,7 +10906,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        } else {
                                                                ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD);
                                                                /* If this is a TBD call, we're ready but now what...  */
-                                                               ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_inet_ntoa(sin.sin_addr));
+                                                               ast_verb(3, "Accepted unauthenticated TBD call from %s\n", ast_sockaddr_stringify(&addr));
                                                        }
                                                }
                                        }
@@ -10631,7 +10959,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                if (!ast_test_flag64(iaxs[fr->callno], IAX_PROVISION)) {
                                        if (iaxs[fr->callno]->owner && authdebug)
                                                ast_log(LOG_WARNING, "Call rejected by %s: %s\n",
-                                                       ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr),
+                                                       ast_sockaddr_stringify(&addr),
                                                        ies.cause ? ies.cause : "<Unknown>");
                                        ast_debug(1, "Immediately destroying %d, having received reject\n",
                                                fr->callno);
@@ -10685,11 +11013,12 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        iaxs[fr->callno]->peerformat = ies.format;
                                } else {
                                        if (iaxs[fr->callno]->owner)
-                                               iaxs[fr->callno]->peerformat = ast_format_cap_to_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
+                                               iaxs[fr->callno]->peerformat = iax2_format_compatibility_cap2bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner));
                                        else
                                                iaxs[fr->callno]->peerformat = iaxs[fr->callno]->capability;
                                }
-                               ast_verb(3, "Call accepted by %s (format %s)\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iax2_getformatname(iaxs[fr->callno]->peerformat));
+                               ast_verb(3, "Call accepted by %s (format %s)\n", ast_sockaddr_stringify(&addr),
+                                               iax2_getformatname(iaxs[fr->callno]->peerformat));
                                if (!(iaxs[fr->callno]->peerformat & iaxs[fr->callno]->capability)) {
                                        memset(&ied0, 0, sizeof(ied0));
                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "Unable to negotiate codec");
@@ -10699,28 +11028,38 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                break;
                                        }
                                        if (authdebug) {
-                                               char tmp1[256], tmp2[256];
+                                               struct ast_str *peer_buf = ast_str_alloca(64);
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+
                                                ast_log(LOG_NOTICE, "Rejected call to %s, format %s incompatible with our capability %s.\n",
-                                                       ast_inet_ntoa(sin.sin_addr),
-                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), 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_buf),
+                                                       iax2_getformatname_multiple(iaxs[fr->callno]->capability, &cap_buf));
                                        }
                                } else {
+                                       struct ast_format_cap *native = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
+
                                        ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_STARTED);
                                        iax2_lock_owner(fr->callno);
-                                       if (iaxs[fr->callno] && iaxs[fr->callno]->owner) {
-                                               char tmp[256];
+                                       if (iaxs[fr->callno] && iaxs[fr->callno]->owner && native) {
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+
                                                /* Switch us to use a compatible format */
-                                               ast_format_cap_from_old_bitfield(ast_channel_nativeformats(iaxs[fr->callno]->owner), iaxs[fr->callno]->peerformat);
-                                               ast_verb(3, "Format for call is %s\n", ast_getformatname_multiple(tmp, sizeof(tmp), ast_channel_nativeformats(iaxs[fr->callno]->owner)));
+                                               iax2_codec_pref_best_bitfield2cap(
+                                                       iaxs[fr->callno]->peerformat, &iaxs[fr->callno]->rprefs,
+                                                       native);
+                                               ast_channel_nativeformats_set(iaxs[fr->callno]->owner, native);
+                                               ast_verb(3, "Format for call is %s\n", ast_format_cap_get_names(ast_channel_nativeformats(iaxs[fr->callno]->owner), &cap_buf));
 
                                                /* Setup read/write formats properly. */
-                                               if (ast_channel_writeformat(iaxs[fr->callno]->owner)->id)
+                                               if (ast_channel_writeformat(iaxs[fr->callno]->owner))
                                                        ast_set_write_format(iaxs[fr->callno]->owner, ast_channel_writeformat(iaxs[fr->callno]->owner));
-                                               if (ast_channel_readformat(iaxs[fr->callno]->owner)->id)
+                                               if (ast_channel_readformat(iaxs[fr->callno]->owner))
                                                        ast_set_read_format(iaxs[fr->callno]->owner, ast_channel_readformat(iaxs[fr->callno]->owner));
                                                ast_channel_unlock(iaxs[fr->callno]->owner);
                                        }
+
+                                       ao2_cleanup(native);
                                }
                                if (iaxs[fr->callno]) {
                                        AST_LIST_LOCK(&dpcache);
@@ -10756,7 +11095,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        peer = iaxs[fr->callno]->peerpoke;
                                        if ((peer->lastms < 0)  || (peer->historicms > peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime <= peer->maxms) {
-                                                       ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %d\n", peer->name, iaxs[fr->callno]->pingtime);
+                                                       ast_log(LOG_NOTICE, "Peer '%s' is now REACHABLE! Time: %u\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
                                                        blob = ast_json_pack("{s: s, s: i}",
                                                                "peer_status", "Reachable",
@@ -10765,7 +11104,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                }
                                        } else if ((peer->historicms > 0) && (peer->historicms <= peer->maxms)) {
                                                if (iaxs[fr->callno]->pingtime > peer->maxms) {
-                                                       ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%d ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
+                                                       ast_log(LOG_NOTICE, "Peer '%s' is now TOO LAGGED (%u ms)!\n", peer->name, iaxs[fr->callno]->pingtime);
                                                        ast_endpoint_set_state(peer->endpoint, AST_ENDPOINT_ONLINE);
                                                        blob = ast_json_pack("{s: s, s: i}",
                                                                "peer_status", "Lagged",
@@ -10823,7 +11162,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        iaxs[fr->callno]->lag = ts - fr->ts;
                                        if (iaxdebug)
                                                ast_debug(1, "Peer %s lag measured as %dms\n",
-                                                       ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->lag);
+                                                       ast_sockaddr_stringify(&addr), iaxs[fr->callno]->lag);
                                }
                                break;
                        case IAX_COMMAND_AUTHREQ:
@@ -10837,7 +11176,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        };
                                        ast_log(LOG_WARNING,
                                                "I don't know how to authenticate %s to %s\n",
-                                               ies.username ? ies.username : "<unknown>", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr));
+                                               ies.username ? ies.username : "<unknown>", ast_sockaddr_stringify(&addr));
                                        iax2_queue_frame(fr->callno, &hangup_fr);
                                }
                                break;
@@ -10852,7 +11191,8 @@ static int socket_process_helper(struct iax2_thread *thread)
                                }
                                if (authenticate_verify(iaxs[fr->callno], &ies)) {
                                        if (authdebug)
-                                               ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_inet_ntoa(iaxs[fr->callno]->addr.sin_addr), iaxs[fr->callno]->username);
+                                               ast_log(LOG_NOTICE, "Host %s failed to authenticate as %s\n", ast_sockaddr_stringify(&addr),
+                                                               iaxs[fr->callno]->username);
                                        memset(&ied0, 0, sizeof(ied0));
                                        auth_fail(fr->callno, IAX_COMMAND_REJECT);
                                        break;
@@ -10864,7 +11204,10 @@ static int socket_process_helper(struct iax2_thread *thread)
                                        exists = 0;
                                if (strcmp(iaxs[fr->callno]->exten, "TBD") && !exists) {
                                        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);
+                                               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);
                                        memset(&ied0, 0, sizeof(ied0));
                                        iax_ie_append_str(&ied0, IAX_IE_CAUSE, "No such context/extension");
                                        iax_ie_append_byte(&ied0, IAX_IE_CAUSECODE, AST_CAUSE_NO_ROUTE_DESTINATION);
@@ -10885,11 +11228,11 @@ 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 (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 (ast_test_flag64(iaxs[fr->callno], IAX_CODEC_USER_FIRST)) {
                                                                pref = iaxs[fr->callno]->rprefs;
                                                                using_prefs = "caller";
@@ -10898,30 +11241,34 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                        }
                                                } else /* if no codec_prefs IE do it the old way */
                                                        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) {
-                                               char tmp1[256], tmp2[256], tmp3[256];
+                                               struct ast_str *cap_buf = ast_str_alloca(64);
+                                               struct ast_str *peer_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_debug(1, "We don't do requested format %s, falling back to peer capability '%s'\n",
                                                                iax2_getformatname(iaxs[fr->callno]->peerformat),
-                                                               iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability));
+                                                               iax2_getformatname_multiple(iaxs[fr->callno]->peercapability, &peer_buf));
                                                        format = iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability;
                                                }
                                                if (!format) {
                                                        if (authdebug) {
                                                                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(tmp1, sizeof(tmp1), iaxs[fr->callno]->peerformat),
-                                                                               iax2_getformatname_multiple(tmp2, sizeof(tmp2), iaxs[fr->callno]->capability));
+                                                                       ast_log(LOG_NOTICE, "Rejected connect attempt from %s, requested '%s' incompatible with our capability '%s'.\n",
+                                                                                       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(tmp1, sizeof(tmp1), 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));
                                                                }
                                                        }
                                                        memset(&ied0, 0, sizeof(ied0));
@@ -10940,14 +11287,15 @@ 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 = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP) ?
-                                                                               iaxs[fr->callno]->peerformat : iax2_best_codec(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability);
+                                                                       format = ast_test_flag64(iaxs[fr->callno], IAX_CODEC_NOCAP)
+                                                                               ? iaxs[fr->callno]->peerformat
+                                                                               : 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;
@@ -10955,27 +11303,30 @@ 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);
                                                                }
                                                        }
                                                        if (!format) {
-                                                               char tmp1[256], tmp2[256], tmp3[256];
+                                                               struct ast_str *cap_buf = ast_str_alloca(64);
+                                                               struct ast_str *peer_buf = ast_str_alloca(64);
+                                                               struct ast_str *peer_form_buf = ast_str_alloca(64);
+
                                                                ast_log(LOG_ERROR, "No best format in %s???\n",
-                                                                       iax2_getformatname_multiple(tmp1, sizeof(tmp1), iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability));
+                                                                       iax2_getformatname_multiple(iaxs[fr->callno]->peercapability & iaxs[fr->callno]->capability, &cap_buf));
                                                                if (authdebug) {
                                                                        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(tmp1, sizeof(tmp1), 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(tmp1, sizeof(tmp1), 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));
                                                                        }
                                                                }
                                                                memset(&ied0, 0, sizeof(ied0));
@@ -11002,7 +11353,7 @@ static int socket_process_helper(struct iax2_thread *thread)
                                                                                        "%sactual format = %s,\n"
                                                                                        "%shost prefs = %s,\n"
                                                                                        "%spriority = %s\n",
-                                                                           &nb