diff --git a/daemon/src/audio/audiortp/audio_rtp_factory.cpp b/daemon/src/audio/audiortp/audio_rtp_factory.cpp
index 50aa556834481f854d95860fbfef267de93b2655..085097a4b3df4164f9da45b34ea3ebfd30ff2176 100644
--- a/daemon/src/audio/audiortp/audio_rtp_factory.cpp
+++ b/daemon/src/audio/audiortp/audio_rtp_factory.cpp
@@ -28,11 +28,12 @@
  *  as that of the covered work.
  */
 
+#include "audio_rtp_factory.h"
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "audio_rtp_factory.h"
 #if HAVE_ZRTP
 #include "audio_zrtp_session.h"
 #endif
@@ -122,7 +123,11 @@ void AudioRtpFactory::initSession()
                 throw UnsupportedRtpSessionType("Unsupported Rtp Session Exception Type!");
         }
     } else {
-        rtpSession_.reset(new AudioSymmetricRtpSession(*call_));
+        /*if (call_->isIPv6()) {
+            rtpSession_.reset(new AudioSymmetricRtpSessionIPv6(*call_));
+        } else */ {
+            rtpSession_.reset(new AudioSymmetricRtpSession(*call_));
+        }
     }
 }
 
diff --git a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp
index 5d59f86bd1a70c8be2f4cf2f529c345f5a24bcc2..607704fe26afcd776f85e172cc25101213585cc4 100644
--- a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp
+++ b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp
@@ -155,4 +155,50 @@ void AudioSymmetricRtpSession::onGotSR(ost::SyncSource& source, ost::RTCPCompoun
     }
 }
 
+// IPv6
+
+AudioSymmetricRtpSessionIPv6::AudioSymmetricRtpSessionIPv6(SIPCall &call) :
+    ost::SymmetricRTPSessionIPV6(ost::IPV6Host(call.getLocalIp().c_str()), call.getLocalAudioPort())
+    , AudioRtpSession(call, *this)
+{
+    DEBUG("Setting new RTP/IPv6 session with destination %s:%d",
+          call_.getLocalIp().c_str(), call_.getLocalAudioPort());
+}
+
+std::vector<long>
+AudioSymmetricRtpSessionIPv6::getSocketDescriptors() const
+{
+    std::vector<long> result;
+    result.push_back(dso->getRecvSocket());
+    result.push_back(cso->getRecvSocket());
+    return result;
+}
+
+void AudioSymmetricRtpSessionIPv6::startRTPLoop()
+{
+    ost::SymmetricRTPSessionIPV6::startRunning();
+}
+
+// redefined from QueueRTCPManager
+void AudioSymmetricRtpSessionIPv6::onGotRR(ost::SyncSource& source, ost::RTCPCompoundHandler::RecvReport& RR, uint8 blocks)
+{
+    ost::SymmetricRTPSessionIPV6::onGotRR(source, RR, blocks);
+    // TODO: do something with this data
+#if 0
+    std::cout << "I got an RR RTCP report from "
+        << std::hex << (int)source.getID() << "@"
+        << std::dec
+        << source.getNetworkAddress() << ":"
+        << source.getControlTransportPort() << std::endl;
+#endif
+}
+
+// redefined from QueueRTCPManager
+void AudioSymmetricRtpSessionIPv6::onGotSR(ost::SyncSource& source, ost::RTCPCompoundHandler::SendReport& SR, uint8 blocks)
+{
+    ost::SymmetricRTPSessionIPV6::onGotSR(source, SR, blocks);
+    // TODO: do something with this data
+}
+
+
 }
diff --git a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h
index 77a597313f81395d95791d0c3eb468576970e9ed..0d91285e34cba036ffadf4552dbc0b74d7ca8b10 100644
--- a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h
+++ b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.h
@@ -77,6 +77,40 @@ class AudioSymmetricRtpSession : public ost::SymmetricRTPSession, public AudioRt
         void startRTPLoop();
 };
 
+class AudioSymmetricRtpSessionIPv6 : public ost::SymmetricRTPSessionIPV6, public AudioRtpSession {
+    public:
+        /**
+        * Constructor
+        * @param call The SIP call
+        */
+        AudioSymmetricRtpSessionIPv6(SIPCall &call);
+
+        std::vector<long>
+        getSocketDescriptors() const;
+
+        virtual bool onRTPPacketRecv(ost::IncomingRTPPkt& pkt) {
+            return AudioRtpSession::onRTPPacketRecv(pkt);
+        }
+
+    protected:
+        virtual size_t recvData(unsigned char*, size_t s, ost::IPV4Host&, ost::tpport_t&) {
+            ERROR("IPv4 dummy function recvData called in ipv6 stack, size %d", s);
+            //ost::SymmetricRTPSessionIPV6::recvData();
+        }
+
+        virtual size_t recvControl(unsigned char*, size_t s, ost::IPV4Host&, ost::tpport_t&) {
+            ERROR("IPv4 dummy function recvControl called in ipv6 stack, size %d", s);
+        }
+
+    private:
+        void onGotRR(ost::SyncSource& source, ost::RTCPCompoundHandler::RecvReport& RR, uint8 blocks);
+        void onGotSR(ost::SyncSource& source, ost::RTCPCompoundHandler::SendReport& SR, uint8 blocks);
+
+        NON_COPYABLE(AudioSymmetricRtpSessionIPv6);
+
+        void startRTPLoop();
+};
+
 }
 #pragma GCC diagnostic warning "-Weffc++"
 #endif // AUDIO_SYMMETRIC_RTP_SESSION_H__
diff --git a/daemon/src/call.cpp b/daemon/src/call.cpp
index 7411397c333dfad303f7af640040166fd2b41783..cfe39c74c68fdae99c5a7d9f10f7ba70ea8276e8 100644
--- a/daemon/src/call.cpp
+++ b/daemon/src/call.cpp
@@ -36,6 +36,7 @@
 Call::Call(const std::string& id, Call::CallType type, const std::string &accountID)
     : callMutex_()
     , localIPAddress_("")
+    , localIPAddr_()
     , localAudioPort_(0)
     , localVideoPort_(0)
     , id_(id)
@@ -123,21 +124,28 @@ Call::getStateStr()
 
 
 std::string
-Call::getLocalIp()
+Call::getLocalIp() const
 {
     std::lock_guard<std::mutex> lock(callMutex_);
     return localIPAddress_;
 }
 
+pj_sockaddr
+Call::getLocalIpAddr() const
+{
+    std::lock_guard<std::mutex> lock(callMutex_);
+    return localIPAddr_;
+}
+
 unsigned int
-Call::getLocalAudioPort()
+Call::getLocalAudioPort() const
 {
     std::lock_guard<std::mutex> lock(callMutex_);
     return localAudioPort_;
 }
 
 unsigned int
-Call::getLocalVideoPort()
+Call::getLocalVideoPort() const
 {
     std::lock_guard<std::mutex> lock(callMutex_);
     return localVideoPort_;
diff --git a/daemon/src/call.h b/daemon/src/call.h
index 41ba244ce24ced424a2abf13473a591eebdf4890..839306a80748fad4723fcaf71986c9a078325607 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -32,10 +32,14 @@
 #ifndef __CALL_H__
 #define __CALL_H__
 
-#include <sstream>
-#include <map>
-#include <mutex>
+#include "logger.h"
+
 #include "audio/recordable.h"
+#include "sip/sip_utils.h"
+
+#include <mutex>
+#include <map>
+#include <sstream>
 
 /*
  * @file call.h
@@ -183,8 +187,9 @@ class Call : public Recordable {
          * Set my IP [not protected]
          * @param ip  The local IP address
          */
-        void setLocalIp(const std::string& ip) {
-            localIPAddress_ = ip;
+        void setLocalIp(const pj_sockaddr& ip) {
+            pj_sockaddr_cp(&localIPAddr_, &ip);
+            localIPAddress_ = sip_utils::addrToStr(localIPAddr_);
         }
 
         /**
@@ -207,19 +212,21 @@ class Call : public Recordable {
          * Return my IP [mutex protected]
          * @return std::string The local IP
          */
-        std::string getLocalIp();
+        std::string getLocalIp() const;
+
+        pj_sockaddr getLocalIpAddr() const;
 
         /**
          * Return port used locally (for my machine) [mutex protected]
          * @return unsigned int  The local audio port
          */
-        unsigned int getLocalAudioPort();
+        unsigned int getLocalAudioPort() const;
 
         /**
          * Return port used locally (for my machine) [mutex protected]
          * @return unsigned int  The local video port
          */
-        unsigned int getLocalVideoPort();
+        unsigned int getLocalVideoPort() const;
 
         void time_stop();
         virtual std::map<std::string, std::string> getDetails();
@@ -233,12 +240,13 @@ class Call : public Recordable {
     private:
         std::string getTypeStr() const;
         /** Protect every attribute that can be changed by two threads */
-        std::mutex callMutex_;
+        mutable std::mutex callMutex_;
 
         // Informations about call socket / audio
 
         /** My IP address */
         std::string localIPAddress_;
+        pj_sockaddr localIPAddr_;
 
         /** Local audio port, as seen by me. */
         unsigned int localAudioPort_;
diff --git a/daemon/src/eventthread.cpp b/daemon/src/eventthread.cpp
index a6876aef7fb08f6ebe46689ae6789c2630d971aa..2aae290f3426c3bcbb5f9f61060d99fe2b84ea90 100644
--- a/daemon/src/eventthread.cpp
+++ b/daemon/src/eventthread.cpp
@@ -37,7 +37,7 @@
 #define YIELD pthread_yield
 #endif
 
-EventThread::EventThread(VoIPLink *link) : link_(link), thread_()
+EventThread::EventThread(VoIPLink &link) : link_(link), thread_()
 {}
 
 EventThread::~EventThread()
@@ -58,6 +58,6 @@ void EventThread::start()
 
 void EventThread::run()
 {
-    while (link_->getEvent())
+    while (link_.getEvent())
         YIELD();
 }
diff --git a/daemon/src/eventthread.h b/daemon/src/eventthread.h
index 43986b86a94140bf77e41484c97f5adfcfde0613..1dfddf504496833f7036a4d0226afbb9edb16969 100644
--- a/daemon/src/eventthread.h
+++ b/daemon/src/eventthread.h
@@ -31,7 +31,6 @@
 #ifndef EVENT_THREAD_H_
 #define EVENT_THREAD_H_
 
-#include "noncopyable.h"
 #include <thread>
 
 class VoIPLink;
@@ -43,16 +42,15 @@ class VoIPLink;
 
 class EventThread {
     public:
-        EventThread(VoIPLink* link);
+        EventThread(VoIPLink& link);
         ~EventThread();
         // spawns thread
         void start();
         void join();
 
     private:
-        NON_COPYABLE(EventThread);
         // VoIPLink is the object being called by getEvents() method
-        VoIPLink* link_;
+        VoIPLink& link_;
         std::thread thread_;
         void run();
 };
diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp
index 1e9ad8bdaa8e710bc81490a93d69ef3983e4cac0..990de886a21e890b6f3249ce1cf32d5a234b44d5 100644
--- a/daemon/src/iax/iaxvoiplink.cpp
+++ b/daemon/src/iax/iaxvoiplink.cpp
@@ -59,7 +59,7 @@ IAXVoIPLink::IAXVoIPLink(const std::string& accountID) :
     , resampler_(44100)
     , initDone_(false)
     , accountID_(accountID)
-    , evThread_(this)
+    , evThread_(*this)
 {
     srand(time(NULL));    // to get random number for RANDOM_PORT
 }
diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp
index b1950178099cfdc2b1d653c775bbd35a941a6ed6..15b00e591583395be9a8fd97b4ac9dd28ae1ea67 100644
--- a/daemon/src/sip/sdp.cpp
+++ b/daemon/src/sip/sdp.cpp
@@ -40,6 +40,7 @@
 
 #include <algorithm>
 #include "sipaccount.h"
+#include "sipaccount.h"
 
 
 #ifdef SFL_VIDEO
@@ -53,16 +54,17 @@ using std::stringstream;
 
 Sdp::Sdp(pj_pool_t *pool)
     : memPool_(pool)
-    , negotiator_(NULL)
-    , localSession_(NULL)
-    , remoteSession_(NULL)
-    , activeLocalSession_(NULL)
-    , activeRemoteSession_(NULL)
+    , negotiator_(nullptr)
+    , localSession_(nullptr)
+    , remoteSession_(nullptr)
+    , activeLocalSession_(nullptr)
+    , activeRemoteSession_(nullptr)
     , audio_codec_list_()
     , video_codec_list_()
     , sessionAudioMedia_()
     , sessionVideoMedia_()
     , publishedIpAddr_()
+    , publishedIpAddrStr_()
     , remoteIpAddr_()
     , localAudioDataPort_(0)
     , localAudioControlPort_(0)
@@ -340,16 +342,9 @@ Sdp::setMediaDescriptorLines(bool audio)
 
 void Sdp::addRTCPAttribute(pjmedia_sdp_media *med)
 {
-    std::ostringstream os;
-    os << publishedIpAddr_ << ":" << localAudioControlPort_;
-    const std::string str(os.str());
-    pj_str_t input_str = pj_str((char*) str.c_str());
     pj_sockaddr outputAddr;
-    pj_status_t status = pj_sockaddr_parse(PJ_AF_UNSPEC, 0, &input_str, &outputAddr);
-    if (status != PJ_SUCCESS) {
-        ERROR("Could not parse address %s", str.c_str());
-        return;
-    }
+    pj_sockaddr_cp(&outputAddr, &publishedIpAddr_);
+    pj_sockaddr_set_port(&outputAddr, localAudioControlPort_);
     pjmedia_sdp_attr *attr = pjmedia_sdp_attr_create_rtcp(memPool_, &outputAddr);
     if (attr)
         pjmedia_sdp_attr_add(&med->attr_count, med->attr, attr);
@@ -357,10 +352,22 @@ void Sdp::addRTCPAttribute(pjmedia_sdp_media *med)
 
 void
 Sdp::setPublishedIP(const std::string &ip_addr)
+{
+    setPublishedIP(sip_utils::strToAddr(ip_addr));
+}
+
+void
+Sdp::setPublishedIP(const pj_sockaddr& ip_addr)
 {
     publishedIpAddr_ = ip_addr;
+    publishedIpAddrStr_ = sip_utils::addrToStr(publishedIpAddr_);
+
     if (localSession_) {
-        localSession_->origin.addr = pj_str((char*) publishedIpAddr_.c_str());
+        if (publishedIpAddr_.addr.sa_family == pj_AF_INET6())
+            localSession_->origin.addr_type = pj_str((char*) "IP6");
+        else
+            localSession_->origin.addr_type = pj_str((char*) "IP4");
+        localSession_->origin.addr = pj_str((char*) publishedIpAddrStr_.c_str());
         localSession_->conn->addr = localSession_->origin.addr;
         if (pjmedia_sdp_validate(localSession_) != PJ_SUCCESS)
             ERROR("Could not validate SDP");
@@ -368,12 +375,12 @@ Sdp::setPublishedIP(const std::string &ip_addr)
 }
 
 void
-Sdp::updatePorts(const std::vector<pj_sockaddr_in> &sockets)
+Sdp::updatePorts(const std::vector<pj_sockaddr> &sockets)
 {
-    localAudioDataPort_     = pj_ntohs(sockets[0].sin_port);
-    localAudioControlPort_  = pj_ntohs(sockets[1].sin_port);
-    localVideoDataPort_     = pj_ntohs(sockets[2].sin_port);
-    localVideoControlPort_  = pj_ntohs(sockets[3].sin_port);
+    localAudioDataPort_     = pj_sockaddr_get_port(&sockets[0]);
+    localAudioControlPort_  = pj_sockaddr_get_port(&sockets[1]);
+    localVideoDataPort_     = pj_sockaddr_get_port(&sockets[2]);
+    localVideoControlPort_  = pj_sockaddr_get_port(&sockets[3]);
 
     if (localSession_) {
         if (localSession_->media[0]) {
@@ -467,8 +474,11 @@ int Sdp::createLocalSession(const vector<int> &selectedAudioCodecs, const vector
     // Use Network Time Protocol format timestamp to ensure uniqueness.
     localSession_->origin.id = tv.sec + 2208988800UL;
     localSession_->origin.net_type = pj_str((char*) "IN");
-    localSession_->origin.addr_type = pj_str((char*) "IP4");
-    localSession_->origin.addr = pj_str((char*) publishedIpAddr_.c_str());
+    if (publishedIpAddr_.addr.sa_family == pj_AF_INET6())
+        localSession_->origin.addr_type = pj_str((char*) "IP6");
+    else
+        localSession_->origin.addr_type = pj_str((char*) "IP4");
+    localSession_->origin.addr = pj_str((char*) publishedIpAddrStr_.c_str());
 
     localSession_->name = pj_str((char*) PACKAGE);
 
diff --git a/daemon/src/sip/sdp.h b/daemon/src/sip/sdp.h
index a44b7a4602b7033cf96e1376fb2d35ca60a26630..048b0f873f0e5769d6c239df8c079d81626ad90a 100644
--- a/daemon/src/sip/sdp.h
+++ b/daemon/src/sip/sdp.h
@@ -154,11 +154,12 @@ class Sdp {
          * Write accessor. Set the local IP address that will be used in the sdp session
          */
         void setPublishedIP(const std::string &ip_addr);
+        void setPublishedIP(const pj_sockaddr& ip_addr);
 
         /*
          * Read accessor. Get the local IP address
          */
-        std::string getPublishedIP() const {
+        pj_sockaddr getPublishedIP() const {
             return publishedIpAddr_;
         }
 
@@ -172,7 +173,7 @@ class Sdp {
             localVideoControlPort_ = port + 1;
         }
 
-        void updatePorts(const std::vector<pj_sockaddr_in> &sockets);
+        void updatePorts(const std::vector<pj_sockaddr> &sockets);
 
         /**
          * Return IP of destination
@@ -309,7 +310,8 @@ class Sdp {
         std::vector<sfl::AudioCodec *> sessionAudioMedia_;
         std::vector<std::string> sessionVideoMedia_;
 
-        std::string publishedIpAddr_;
+        pj_sockaddr publishedIpAddr_;
+        std::string publishedIpAddrStr_;
         std::string remoteIpAddr_;
 
         int localAudioDataPort_;
diff --git a/daemon/src/sip/sip_utils.cpp b/daemon/src/sip/sip_utils.cpp
index 014bc615045d63789dc343360ddc776910337b9c..d8110b7f9e97092bf630610ab04a43e11da850cb 100644
--- a/daemon/src/sip/sip_utils.cpp
+++ b/daemon/src/sip/sip_utils.cpp
@@ -29,6 +29,9 @@
  *  as that of the covered work.
  */
 
+#include "sip_utils.h"
+#include "logger.h"
+
 #include <pjsip.h>
 #include <pjlib.h>
 #include <pjsip_ua.h>
@@ -40,16 +43,14 @@
 #include <pjsip/sip_types.h>
 #include <pjsip/sip_uri.h>
 #include <pj/list.h>
-#include "sip_utils.h"
 
-#include <vector>
-#include <algorithm>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
-#include "logger.h"
+#include <vector>
+#include <algorithm>
 
 std::string
 sip_utils::fetchHeaderValue(pjsip_msg *msg, const std::string &field)
@@ -198,24 +199,22 @@ sip_utils::getIPList(const std::string &name)
     hints.ai_socktype = SOCK_DGRAM;
     hints.ai_flags = AI_ADDRCONFIG;
     /* resolve the domain name into a list of addresses */
-    const int error = getaddrinfo(name.c_str(), NULL, &hints, &result);
+    const int error = getaddrinfo(name.c_str(), nullptr, &hints, &result);
     if (error != 0) {
         DEBUG("getaddrinfo on \"%s\" failed: %s", name.c_str(), gai_strerror(error));
         return ipList;
     }
 
-    for (struct addrinfo *res = result; res != NULL; res = res->ai_next) {
-
+    for (struct addrinfo *res = result; res != nullptr; res = res->ai_next) {
         void *ptr = 0;
         std::vector<char> addrstr;
-        static const int AF_INET_STRLEN = 16, AF_INET6_STRLEN = 40;
         switch (res->ai_family) {
             case AF_INET:
-                addrstr.resize(AF_INET_STRLEN);
+                addrstr.resize(INET_ADDRSTRLEN);
                 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
                 break;
             case AF_INET6:
-                addrstr.resize(AF_INET6_STRLEN);
+                addrstr.resize(INET6_ADDRSTRLEN);
                 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
                 break;
             default:
@@ -226,14 +225,79 @@ sip_utils::getIPList(const std::string &name)
         // don't add duplicates, and don't use an std::set because
         // we want this order preserved.
         const std::string tmp(addrstr.begin(), addrstr.end());
-        if (std::find(ipList.begin(), ipList.end(), tmp) == ipList.end())
+        if (std::find(ipList.begin(), ipList.end(), tmp) == ipList.end()) {
             ipList.push_back(tmp);
+        }
     }
 
     freeaddrinfo(result);
     return ipList;
 }
 
+std::string
+sip_utils::addrToStr(const pj_sockaddr& ip, bool include_port, bool force_ipv6_brackets)
+{
+    std::string str(PJ_INET6_ADDRSTRLEN, (char)0);
+    if(include_port) force_ipv6_brackets = true;
+    pj_sockaddr_print(&ip, &(*str.begin()), PJ_INET6_ADDRSTRLEN, (include_port?1:0)|(force_ipv6_brackets?2:0));
+    return str;
+}
+
+std::string
+sip_utils::addrToStr(const std::string& ip_str, bool include_port, bool force_ipv6_brackets)
+{
+    pj_sockaddr ip = strToAddr(ip_str);
+    if (ip.addr.sa_family == pj_AF_UNSPEC())
+        return ip_str;
+    return addrToStr(ip, include_port, force_ipv6_brackets);
+}
+
+pj_sockaddr
+sip_utils::strToAddr(const std::string& str)
+{
+    pj_str_t pjstring;
+    pj_cstr(&pjstring, str.c_str());
+    pj_sockaddr ip;
+    auto status = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &pjstring, &ip);
+    if (status != PJ_SUCCESS)
+        ip.addr.sa_family = pj_AF_UNSPEC();
+    return ip;
+}
+
+pj_sockaddr
+sip_utils::getAnyHostAddr(pj_uint16_t family)
+{
+    if (family == pj_AF_UNSPEC()) family = pj_AF_INET();
+    pj_sockaddr addr = {};
+    addr.addr.sa_family = family;
+    return addr;
+}
+
+bool
+sip_utils::isIPv6(const std::string &address)
+{
+    return isValidAddr(address, pj_AF_INET6());
+}
+
+bool
+sip_utils::isValidAddr(const std::string &address, pj_uint16_t family)
+{
+    pj_str_t pjstring;
+    pj_cstr(&pjstring, address.c_str());
+    pj_str_t ret_str;
+    pj_uint16_t ret_port;
+    int ret_family;
+    auto status = pj_sockaddr_parse2(pj_AF_UNSPEC(), 0, &pjstring, &ret_str, &ret_port, &ret_family);
+    if (status != PJ_SUCCESS || (family != pj_AF_UNSPEC() && ret_family != family))
+        return false;
+
+    char buf[PJ_INET6_ADDRSTRLEN];
+    pj_str_t addr_with_null = {buf, 0};
+    pj_strncpy_with_null(&addr_with_null, &ret_str, sizeof(buf));
+    struct sockaddr sa;
+    return inet_pton(ret_family==pj_AF_INET6()?AF_INET6:AF_INET, buf, &(sa.sa_data)) == 1;
+}
+
 void
 sip_utils::addContactHeader(const pj_str_t *contact_str, pjsip_tx_data *tdata)
 {
diff --git a/daemon/src/sip/sip_utils.h b/daemon/src/sip/sip_utils.h
index a5d662bff3b78332fc5b739f35847ceea9a6a8fe..5bc69fa30422a926ba5707662957f59b3bc63225 100644
--- a/daemon/src/sip/sip_utils.h
+++ b/daemon/src/sip/sip_utils.h
@@ -32,11 +32,13 @@
 #ifndef SIP_UTILS_H_
 #define SIP_UTILS_H_
 
+#include <pjsip/sip_msg.h>
+#include <pjlib.h>
+
+#include <utility>
 #include <string>
 #include <vector>
 
-#include <pjsip/sip_msg.h>
-
 struct pjsip_msg;
 
 namespace sip_utils {
@@ -55,8 +57,34 @@ namespace sip_utils {
 
     std::string getHostFromUri(const std::string& sipUri);
 
+    /**
+     * Convert a binary IP address to a standard string representation.
+     */
+    std::string addrToStr(const pj_sockaddr& ip, bool include_port = false, bool force_ipv6_brackets = false);
+
+    /**
+     * Format an IP address string. If formating the address fails, the original string is returned.
+     */
+    std::string addrToStr(const std::string& ip, bool include_port = false, bool force_ipv6_brackets = false);
+
+    /**
+     * Convert a string representation of an IP adress to its binary counterpart.
+     *
+     * Performs hostname resolution if necessary.
+     * If conversion fails, returned adress will have its family set to PJ_AF_UNSPEC.
+     */
+    pj_sockaddr strToAddr(const std::string& str);
+
+    /**
+     * Returns true if address is a valid IPv6.
+     */
+    bool isIPv6(const std::string &address);
+    bool isValidAddr(const std::string &address, pj_uint16_t family = pj_AF_UNSPEC());
+
     std::vector<std::string> getIPList(const std::string &name);
 
+    pj_sockaddr getAnyHostAddr(pj_uint16_t family = pj_AF_UNSPEC());
+
     void addContactHeader(const pj_str_t *contactStr, pjsip_tx_data *tdata);
 }
 
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 6f1296874e09ce6535f787ea8c18b7a4107eb7f8..403c8cf357756de3df5e378d72cb7b670cc1bdb7 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -30,13 +30,12 @@
  *  as that of the covered work.
 */
 
+#include "sipaccount.h"
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "account_schema.h"
-#include "sipaccount.h"
-#include "sip_utils.h"
 #include "sipvoiplink.h"
 #include "config/yamlnode.h"
 #include "config/yamlemitter.h"
@@ -48,18 +47,17 @@
 #include "client/configurationmanager.h"
 #endif
 
+#ifdef SFL_VIDEO
+#include "video/libav_utils.h"
+#endif
+
 #include <unistd.h>
 #include <pwd.h>
-#include <sstream>
 #include <algorithm>
-#include <cstdlib>
 #include <array>
 #include <memory>
-
-#ifdef SFL_VIDEO
-#include "video/libav_utils.h"
-#endif
-
+#include <sstream>
+#include <cstdlib>
 
 const char * const SIPAccount::IP2IP_PROFILE = "IP2IP";
 const char * const SIPAccount::OVERRTP_STR = "overrtp";
@@ -87,6 +85,7 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
     , interface_("default")
     , publishedSameasLocal_(true)
     , publishedIpAddress_()
+    , publishedIp_()
     , localPort_(DEFAULT_SIP_PORT)
     , publishedPort_(DEFAULT_SIP_PORT)
     , serviceRoute_()
@@ -138,7 +137,7 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
     , videoPortRange_({49152, (MAX_PORT) - 2})
 #endif
 #ifdef SFL_PRESENCE
-    , presence_(presenceEnabled ? new SIPPresence(this) : 0)
+    , presence_(presenceEnabled ? new SIPPresence(this) : nullptr)
 #endif
 {
     via_addr_.host.ptr = 0;
@@ -152,6 +151,11 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
 
 SIPAccount::~SIPAccount()
 {
+    if (transport_) {
+        pjsip_transport_dec_ref(transport_);
+        transport_ = nullptr;
+    }
+
 #ifdef SFL_PRESENCE
     delete presence_;
 #endif
@@ -882,6 +886,8 @@ void SIPAccount::registerVoIPLink()
     if (hostname_.length() >= PJ_MAX_HOSTNAME)
         return;
 
+    DEBUG("SIPAccount::registerVoIPLink");
+
 #if HAVE_TLS
 
     // Init TLS settings if the user wants to use TLS
@@ -1150,7 +1156,7 @@ std::string SIPAccount::getFromUri() const
     std::string hostname(hostname_);
 
     // UDP does not require the transport specification
-    if (transportType_ == PJSIP_TRANSPORT_TLS) {
+    if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
         scheme = "sips:";
         transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
     } else
@@ -1174,7 +1180,7 @@ std::string SIPAccount::getToUri(const std::string& username) const
     std::string hostname;
 
     // UDP does not require the transport specification
-    if (transportType_ == PJSIP_TRANSPORT_TLS) {
+    if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
         scheme = "sips:";
         transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
     } else
@@ -1197,12 +1203,11 @@ std::string SIPAccount::getServerUri() const
     std::string transport;
 
     // UDP does not require the transport specification
-    if (transportType_ == PJSIP_TRANSPORT_TLS) {
+    if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
         scheme = "sips:";
         transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
     } else {
         scheme = "sip:";
-        transport = "";
     }
 
     return "<" + scheme + hostname_ + transport + ">";
@@ -1222,20 +1227,19 @@ SIPAccount::getContactHeader()
         transportType = PJSIP_TRANSPORT_UDP;
 
     // Else we determine this infor based on transport information
-    std::string address, port;
-    std::ostringstream portstr;
+    std::string address;
+    pj_uint16_t port;
 
     link_->sipTransport->findLocalAddressFromTransport(transport_, transportType, address, port);
 
     if (not publishedSameasLocal_) {
         address = publishedIpAddress_;
-        portstr << publishedPort_;
-        port = portstr.str();
-        DEBUG("Using published address %s and port %s", address.c_str(), port.c_str());
+        port = publishedPort_;
+        DEBUG("Using published address %s and port %d", address.c_str(), port);
     } else if (stunEnabled_) {
         link_->sipTransport->findLocalAddressFromSTUN(transport_, &stunServerName_, stunPort_, address, port);
-        publishedIpAddress_ = address;
-        publishedPort_ = atoi(port.c_str());
+        setPublishedAddress(sip_utils::strToAddr(address));
+        publishedPort_ = port;
         usePublishedAddressPortInVIA();
     } else {
         if (!receivedParameter_.empty()) {
@@ -1244,9 +1248,8 @@ SIPAccount::getContactHeader()
         }
 
         if (rPort_ != -1 and rPort_ != 0) {
-            portstr << rPort_;
-            port = portstr.str();
-            DEBUG("Using received port %s", port.c_str());
+            port = rPort_;
+            DEBUG("Using received port %d", port);
         }
     }
 
@@ -1254,21 +1257,26 @@ SIPAccount::getContactHeader()
     std::string scheme;
     std::string transport;
 
-    if (transportType_ == PJSIP_TRANSPORT_TLS) {
+    /* Enclose IPv6 address in square brackets */
+    if (transportType > PJSIP_TRANSPORT_IPV6 || sip_utils::isIPv6(address)) {
+        address = sip_utils::addrToStr(address, false, true);
+    }
+
+    if (transportType != PJSIP_TRANSPORT_UDP and transportType != PJSIP_TRANSPORT_UDP6) {
         scheme = "sips:";
         transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType));
     } else
         scheme = "sip:";
 
     contact_.slen = pj_ansi_snprintf(contact_.ptr, PJSIP_MAX_URL_SIZE,
-                                     "%s%s<%s%s%s%s:%s%s>",
+                                     "%s%s<%s%s%s%s:%d%s>",
                                      displayName_.c_str(),
                                      (displayName_.empty() ? "" : " "),
                                      scheme.c_str(),
                                      username_.c_str(),
                                      (username_.empty() ? "" : "@"),
                                      address.c_str(),
-                                     port.c_str(),
+                                     port,
                                      transport.c_str());
     return contact_;
 }
@@ -1276,14 +1284,13 @@ SIPAccount::getContactHeader()
 pjsip_host_port
 SIPAccount::getHostPortFromSTUN(pj_pool_t *pool)
 {
-    std::string addr, port;
+    std::string addr;
+    pj_uint16_t port;
     link_->sipTransport->findLocalAddressFromSTUN(transport_, &stunServerName_, stunPort_, addr, port);
     pjsip_host_port result;
     pj_strdup2(pool, &result.host, addr.c_str());
     result.host.slen = addr.length();
-    std::stringstream ss;
-    ss << port;
-    ss >> result.port;
+    result.port = port;
     return result;
 }
 
diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h
index 1d016a12f1a25003ea882d6ace3e459f6d3051ac..b8d0ff6584360c88e780d752649dde0b43be253c 100644
--- a/daemon/src/sip/sipaccount.h
+++ b/daemon/src/sip/sipaccount.h
@@ -38,18 +38,19 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
-
-#include <vector>
-#include <map>
-
-#include "pjsip/sip_transport_tls.h"
-#include "pjsip/sip_types.h"
-#include "pjsip-ua/sip_regc.h"
-
 #include "noncopyable.h"
 #include "account.h"
+#include "sip_utils.h"
+
+#include <pjsip/sip_transport_tls.h>
+#include <pjsip/sip_types.h>
+#include <pjsip-ua/sip_regc.h>
+
 #include <openssl/x509v3.h>
 
+#include <vector>
+#include <map>
+
 typedef std::vector<pj_ssl_cipher> CipherArray;
 
 namespace Conf {
@@ -279,12 +280,12 @@ class SIPAccount : public Account {
 
         /**
          * Registration flag
-	 */
+         */
         bool isRegistered() const {
             return bRegister_;
         }
 
-	/**
+        /**
          * Set registration flag
          */
         void setRegister(bool result) {
@@ -396,6 +397,7 @@ class SIPAccount : public Account {
 
         /**
          * Get the contact header for
+         * @param prefer_ipv6 If we are dual-stack, use IPv6 contact header.
          * @return pj_str_t The contact header based on account information
          */
         pj_str_t getContactHeader();
@@ -403,7 +405,7 @@ class SIPAccount : public Account {
         /**
          * Get the local interface name on which this account is bound.
          */
-        std::string getLocalInterface() const {
+        const std::string& getLocalInterface() const {
             return interface_;
         }
 
@@ -463,16 +465,20 @@ class SIPAccount : public Account {
          * Get the public IP address set by the user for this account.
          * If this setting is not provided, the local bound adddress
          * will be used.
-         * @return std::string The public IPV4 address formatted in the standard dot notation.
+         * @return std::string The public IPv4 or IPv6 address formatted in standard notation.
          */
         std::string getPublishedAddress() const {
             return publishedIpAddress_;
         }
 
-        void setPublishedAddress(const std::string &ip_addr) {
-            publishedIpAddress_ = ip_addr;
+        pj_sockaddr getPublishedIpAddress() const {
+            return publishedIp_;
         }
 
+        void setPublishedAddress(const pj_sockaddr& ip_addr) {
+            pj_sockaddr_cp(&publishedIp_, &ip_addr);
+            publishedIpAddress_ = sip_utils::addrToStr(ip_addr);
+        }
 
         std::string getServiceRoute() const {
             return serviceRoute_;
@@ -663,9 +669,10 @@ class SIPAccount : public Account {
         bool publishedSameasLocal_;
 
         /**
-         * Published IP address, ued only if defined by the user in account
+         * Published IP address, used only if defined by the user in account
          * configuration
          */
+        pj_sockaddr publishedIp_;
         std::string publishedIpAddress_;
 
         /**
diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp
index b4cae6942c4455a65c8cd84ecb2c63f1324b7328..9e689bb5cfc6cd6f23243ed264cc99fb2c08d3df 100644
--- a/daemon/src/sip/siptransport.cpp
+++ b/daemon/src/sip/siptransport.cpp
@@ -29,55 +29,53 @@
  *  as that of the covered work.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "siptransport.h"
+#include "sipaccount.h"
 
-#include <map>
+#include "manager.h"
+#include "client/configurationmanager.h"
 
 #include <pjsip.h>
-#include <pjlib.h>
 #include <pjsip_ua.h>
-#include <pjlib-util.h>
+#include <pjsip/sip_types.h>
+#if HAVE_TLS
+#include <pjsip/sip_transport_tls.h>
+#endif
 #include <pjnath.h>
 #include <pjnath/stun_config.h>
+#include <pjlib.h>
+#include <pjlib-util.h>
+
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
-#include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <arpa/inet.h>
 #include <net/if.h>
+#include <unistd.h>
+
 #include <stdexcept>
 #include <sstream>
 
-#include "logger.h"
-#include "siptransport.h"
-#include "manager.h"
-
-#include "sipaccount.h"
-
-#include "pjsip/sip_types.h"
-#if HAVE_TLS
-#include "pjsip/sip_transport_tls.h"
-#endif
-
-#include "client/configurationmanager.h"
-
 static const char * const DEFAULT_INTERFACE = "default";
-static const char * const ANY_HOSTS = "0.0.0.0";
 
 #define RETURN_IF_FAIL(A, VAL, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); return (VAL); }
 
-std::string SipTransport::getSIPLocalIP()
+pj_sockaddr SipTransport::getSIPLocalIP(pj_uint16_t family)
 {
+    if (family == pj_AF_UNSPEC()) family = pj_AF_INET();
     pj_sockaddr ip_addr;
-
-    const pj_status_t status = pj_gethostip(pj_AF_INET(), &ip_addr);
-    RETURN_IF_FAIL(status == PJ_SUCCESS, "", "Could not get local IP");
-    return pj_inet_ntoa(ip_addr.ipv4.sin_addr);
+    pj_status_t status = pj_gethostip(family, &ip_addr);
+    if (status == PJ_SUCCESS) return ip_addr;
+    WARN("Could not get preferred IP version (%s)", (family == pj_AF_INET6()) ? "IPv6" : "IPv4");
+    family = (family == pj_AF_INET()) ? pj_AF_INET6() : pj_AF_INET();
+    status = pj_gethostip(family, &ip_addr);
+    if (status == PJ_SUCCESS) return ip_addr;
+    ERROR("Could not get local IP");
+    ip_addr.addr.sa_family = pj_AF_UNSPEC();
+    return ip_addr;
 }
 
 std::vector<std::string> SipTransport::getAllIpInterfaceByName()
@@ -91,7 +89,7 @@ std::vector<std::string> SipTransport::getAllIpInterfaceByName()
     ifconf.ifc_buf = (char*) (ifreqs);
     ifconf.ifc_len = sizeof(ifreqs);
 
-    int sock = socket(AF_INET,SOCK_STREAM,0);
+    int sock = socket(AF_INET6, SOCK_STREAM, 0);
 
     if (sock >= 0) {
         if (ioctl(sock, SIOCGIFCONF, &ifconf) >= 0)
@@ -104,30 +102,44 @@ std::vector<std::string> SipTransport::getAllIpInterfaceByName()
     return ifaceList;
 }
 
-std::string SipTransport::getInterfaceAddrFromName(const std::string &ifaceName)
+pj_sockaddr SipTransport::getInterfaceAddr(const std::string &ifaceName, bool forceIPv6)
 {
     if (ifaceName == DEFAULT_INTERFACE)
-        return getSIPLocalIP();
-
-    int fd = socket(AF_INET, SOCK_DGRAM,0);
-    RETURN_IF_FAIL(fd >= 0, "", "Could not open socket: %m");
-
+        return getSIPLocalIP(forceIPv6 ? pj_AF_INET6() : pj_AF_INET());
+    int fd = socket(AF_INET6, SOCK_DGRAM, 0);
+    if(!forceIPv6) {
+        int no = 0;
+        setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&no, sizeof(no));
+    }
+    pj_sockaddr saddr;
+    if(fd < 0) {
+        ERROR("Could not open socket: %m", fd);
+        saddr.addr.sa_family = pj_AF_UNSPEC();
+        return saddr;
+    }
     ifreq ifr;
     strncpy(ifr.ifr_name, ifaceName.c_str(), sizeof ifr.ifr_name);
     // guarantee that ifr_name is NULL-terminated
     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
 
     memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
-    ifr.ifr_addr.sa_family = AF_INET;
+    ifr.ifr_addr.sa_family = AF_INET6;
 
     ioctl(fd, SIOCGIFADDR, &ifr);
     close(fd);
 
-    sockaddr_in *saddr_in = (sockaddr_in *) &ifr.ifr_addr;
-    std::string result(inet_ntoa(saddr_in->sin_addr));
-    if (result == ANY_HOSTS)
-        result = getSIPLocalIP();
-    return result;
+    sockaddr* unix_addr = &ifr.ifr_addr;
+    memcpy(&saddr, &ifr.ifr_addr, sizeof(pj_sockaddr));
+    if ((ifr.ifr_addr.sa_family == AF_INET  &&  IN_IS_ADDR_UNSPECIFIED(&((sockaddr_in *)unix_addr)->sin_addr ))
+    || (ifr.ifr_addr.sa_family == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&((sockaddr_in6*)unix_addr)->sin6_addr))) {
+        return getSIPLocalIP(saddr.addr.sa_family);
+    }
+    return saddr;
+}
+
+std::string SipTransport::getInterfaceAddrFromName(const std::string &ifaceName, bool forceIPv6)
+{
+    return sip_utils::addrToStr(getInterfaceAddr(ifaceName, forceIPv6));
 }
 
 std::vector<std::string> SipTransport::getAllIpInterface()
@@ -137,9 +149,9 @@ std::vector<std::string> SipTransport::getAllIpInterface()
 
     std::vector<std::string> ifaceList;
 
-    if (pj_enum_ip_interface(pj_AF_INET(), &addrCnt, addrList) == PJ_SUCCESS) {
+    if (pj_enum_ip_interface(pj_AF_UNSPEC(), &addrCnt, addrList) == PJ_SUCCESS) {
         for (unsigned i = 0; i < addrCnt; i++) {
-            char addr[PJ_INET_ADDRSTRLEN];
+            char addr[PJ_INET6_ADDRSTRLEN];
             pj_sockaddr_print(&addrList[i], addr, sizeof(addr), 0);
             ifaceList.push_back(std::string(addr));
         }
@@ -148,41 +160,143 @@ std::vector<std::string> SipTransport::getAllIpInterface()
     return ifaceList;
 }
 
-SipTransport::SipTransport(pjsip_endpoint *endpt, pj_caching_pool *cp, pj_pool_t *pool) : transportMap_(), cp_(cp), pool_(pool), endpt_(endpt)
+SipTransport::SipTransport(pjsip_endpoint *endpt, pj_caching_pool& cp, pj_pool_t& pool) : transportMap_(), cp_(cp), pool_(pool), endpt_(endpt)
 {}
 
+namespace {
+std::string transportMapKey(const std::string &interface, int port)
+{
+    std::ostringstream os;
+    os << interface << ":" << port;
+    return os.str();
+}
+}
+
+void SipTransport::createSipTransport(SIPAccount &account, pj_uint16_t family)
+{
+    if (account.transport_) {
+        pjsip_transport_dec_ref(account.transport_);
+        //DEBUG("Transport %s has count %d", account.transport_->info, pj_atomic_get(account.transport_->ref_cnt));
+        account.transport_ = nullptr;
+    }
+    auto interface = account.getLocalInterface();
+    if (family == pj_AF_UNSPEC()) family = account.getPublishedIpAddress().addr.sa_family;
+
 #if HAVE_TLS
-pjsip_tpfactory* SipTransport::createTlsListener(SIPAccount &account)
+    if (account.isTlsEnabled()) {
+        std::string key(transportMapKey(interface, account.getTlsListenerPort()));
+        auto iter = transportMap_.find(key);
+
+        // if this transport already exists, reuse it
+        if (iter != transportMap_.end()) {
+            account.transport_ = iter->second;
+            auto status = pjsip_transport_add_ref(account.transport_);
+            if (status != PJ_SUCCESS)
+                account.transport_ = nullptr;
+        }
+        if (!account.transport_) {
+            account.transport_ = createTlsTransport(account);
+            transportMap_[key] = account.transport_;
+        }
+    } else {
+#else
+    {
+#endif
+        auto port = account.getLocalPort();
+        std::string key = transportMapKey(interface, port);
+        auto iter = transportMap_.find(key);
+
+        // if this transport already exists, reuse it
+        if (iter != transportMap_.end()) {
+            account.transport_ = iter->second;
+            auto status = pjsip_transport_add_ref(account.transport_);
+            if (status != PJ_SUCCESS)
+                account.transport_ = nullptr;
+        }
+        if (!account.transport_) {
+            account.transport_ = createUdpTransport(interface, port);
+            transportMap_[key] = account.transport_;
+        }
+    }
+
+    cleanupTransports();
+
+    if (!account.transport_) {
+#if HAVE_TLS
+        if (account.isTlsEnabled())
+            throw std::runtime_error("Could not create TLS connection");
+        else
+#endif
+            throw std::runtime_error("Could not create new UDP transport");
+    }
+}
+
+pjsip_transport *
+SipTransport::createUdpTransport(const std::string &interface, pj_uint16_t port, pj_uint16_t family)
 {
-    pj_sockaddr_in local_addr;
-    pj_sockaddr_in_init(&local_addr, 0, 0);
-    local_addr.sin_port = pj_htons(account.getTlsListenerPort());
+    pj_sockaddr listeningAddress;
+    if (interface == DEFAULT_INTERFACE)
+        listeningAddress = sip_utils::getAnyHostAddr(family);
+    else
+        listeningAddress = getInterfaceAddr(interface, family == pj_AF_INET6());
 
-    RETURN_IF_FAIL(account.getTlsSetting() != NULL, NULL, "TLS settings not specified");
+    RETURN_IF_FAIL(not listeningAddress.addr.sa_family == pj_AF_UNSPEC(), nullptr, "Could not determine ip address for this transport");
+    RETURN_IF_FAIL(port != 0, nullptr, "Could not determine port for this transport");
+
+    pj_sockaddr_set_port(&listeningAddress, port);
+    pj_status_t status;
+    pjsip_transport *transport = nullptr;
+
+    if (listeningAddress.addr.sa_family == pj_AF_INET()) {
+        status = pjsip_udp_transport_start(endpt_, &listeningAddress.ipv4, nullptr, 1, &transport);
+        if (status != PJ_SUCCESS) {
+            ERROR("UDP IPV4 Transport did not start");
+            sip_strerror(status);
+            return nullptr;
+        }
+    } else if (listeningAddress.addr.sa_family == pj_AF_INET6()) {
+        status = pjsip_udp_transport_start6(endpt_, &listeningAddress.ipv6, nullptr, 1, &transport);
+        if (status != PJ_SUCCESS) {
+            ERROR("UDP IPV6 Transport did not start");
+            sip_strerror(status);
+            return nullptr;
+        }
+    }
+
+    DEBUG("Created UDP transport on %s : %s", interface.c_str(), sip_utils::addrToStr(listeningAddress, true, true).c_str());
+    // dump debug information to stdout
+    pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
+    return transport;
+}
+
+#if HAVE_TLS
+pjsip_tpfactory*
+SipTransport::createTlsListener(SIPAccount &account, pj_uint16_t family)
+{
+    RETURN_IF_FAIL(account.getTlsSetting() != nullptr, nullptr, "TLS settings not specified");
 
     std::string interface(account.getLocalInterface());
-    std::string listeningAddress;
+    pj_sockaddr listeningAddress;
     if (interface == DEFAULT_INTERFACE)
-        listeningAddress = ANY_HOSTS;
+        listeningAddress = sip_utils::getAnyHostAddr(family);
     else
-        listeningAddress = getInterfaceAddrFromName(interface);
+        listeningAddress = getInterfaceAddr(interface, family==pj_AF_INET6());
 
-    if (listeningAddress.empty())
-        ERROR("Could not determine IP address for this transport");
+    pj_sockaddr_set_port(&listeningAddress, account.getTlsListenerPort());
 
-    pj_str_t pjAddress;
-    pj_cstr(&pjAddress, listeningAddress.c_str());
-    pj_sockaddr_in_set_str_addr(&local_addr, &pjAddress);
-    pj_sockaddr_in_set_port(&local_addr, account.getTlsListenerPort());
+    RETURN_IF_FAIL(not listeningAddress.addr.sa_family == pj_AF_UNSPEC(), nullptr, "Could not determine IP address for this transport");
 
     DEBUG("Creating Listener...");
     DEBUG("CRT file : %s", account.getTlsSetting()->ca_list_file.ptr);
     DEBUG("PEM file : %s", account.getTlsSetting()->cert_file.ptr);
 
-    pjsip_tpfactory *listener = NULL;
-    const pj_status_t status = pjsip_tls_transport_start(endpt_, account.getTlsSetting(), &local_addr, NULL, 1, &listener);
-    sip_strerror(status);
-    RETURN_IF_FAIL(status == PJ_SUCCESS, NULL, "Failed to start TLS listener with code %d", status);
+    pjsip_tpfactory *listener = nullptr;
+    const pj_status_t status = pjsip_tls_transport_start2(endpt_, account.getTlsSetting(), &listeningAddress, nullptr, 1, &listener);
+    if (status != PJ_SUCCESS) {
+        ERROR("TLS IPv6 Transport did not start");
+        sip_strerror(status);
+        return nullptr;
+    }
     return listener;
 }
 
@@ -216,124 +330,33 @@ SipTransport::createTlsTransport(SIPAccount &account)
     // FIXME: called only once as it is static -> that's why parameters are not saved
     pjsip_tpfactory *localTlsListener = createTlsListener(account);
 
-    pjsip_transport *transport = NULL;
+    pjsip_transport *transport = nullptr;
     pj_status_t status = pjsip_endpt_acquire_transport(endpt_, PJSIP_TRANSPORT_TLS, &rem_addr,
                                   sizeof rem_addr, NULL, &transport);
-    RETURN_IF_FAIL(transport != NULL and status == PJ_SUCCESS, NULL,
+    RETURN_IF_FAIL(transport != nullptr and status == PJ_SUCCESS, nullptr,
                    "Could not create new TLS transport");
 
     //pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
-    //transportMap_[transportMapKey(account.getLocalInterface(), port)] = transport;
     return transport;
 }
 #endif
 
-namespace {
-std::string transportMapKey(const std::string &interface, int port)
-{
-    std::ostringstream os;
-    os << interface << ":" << port;
-    return os.str();
-}
-}
-
-void SipTransport::createSipTransport(SIPAccount &account)
+void
+SipTransport::cleanupTransports()
 {
-    std::map<std::string, pjsip_transport *>::iterator iter;
-#if HAVE_TLS
-    if (account.isTlsEnabled()) {
-//        std::string key(transportMapKey(account.getLocalInterface(), account.getTlsListenerPort()));
-//        iter = transportMap_.find(key);
-        if (account.transport_ != nullptr) {
-            DEBUG("destroying old tls transport, and recreate it with new params");
-            const pj_status_t status = pjsip_transport_shutdown(account.transport_);
-            sip_strerror(status);
-            sip_strerror(pjsip_transport_dec_ref(account.transport_));
-        }
-
-        account.transport_ = createTlsTransport(account);
-    } else {
-#else
-    {
-#endif
-        // if this transport already exists, reuse it
-        std::string key(transportMapKey(account.getLocalInterface(), account.getLocalPort()));
-        iter = transportMap_.find(key);
-
-        if (iter != transportMap_.end()) {
-            account.transport_ = iter->second;
-            pjsip_transport_add_ref(account.transport_);
+    for (auto it = transportMap_.cbegin(); it != transportMap_.cend();) {
+        pjsip_transport* t = (*it).second;
+        pj_lock_acquire(t->lock);
+        if (pj_atomic_get(t->ref_cnt) == 0 || t->is_shutdown || t->is_destroying) {
+            DEBUG("Removing transport for %s (%s)", (*it).first.c_str(), pj_atomic_get(t->ref_cnt) );
+            transportMap_.erase(it++);
         } else {
-            // FIXME: transport should have its reference count decremented and
-            // be removed from the map if it's no longer in use
-            if (account.transport_)
-                WARN("Leaking old transport");
-            account.transport_ = createUdpTransport(account.getLocalInterface(), account.getLocalPort());
-        }
-    }
-
-    if (!account.transport_) {
-#if HAVE_TLS
-        if (account.isTlsEnabled())
-            throw std::runtime_error("Could not create TLS connection");
-        else
-#endif
-            throw std::runtime_error("Could not create new UDP transport");
-    }
-}
-
-pjsip_transport *
-SipTransport::createUdpTransport(const std::string &interface, unsigned int port)
-{
-    // init socket to bind this transport to
-    pj_uint16_t listeningPort = (pj_uint16_t) port;
-
-    // determine the IP address for this transport
-    std::string listeningAddress;
-    if (interface == DEFAULT_INTERFACE)
-        listeningAddress = ANY_HOSTS;
-    else
-        listeningAddress = getInterfaceAddrFromName(interface);
-
-    RETURN_IF_FAIL(not listeningAddress.empty(), NULL, "Could not determine ip address for this transport");
-    RETURN_IF_FAIL(listeningPort != 0, NULL, "Could not determine port for this transport");
-
-    std::ostringstream fullAddress;
-    fullAddress << listeningAddress << ":" << listeningPort;
-    pj_str_t udpString;
-    std::string fullAddressStr(fullAddress.str());
-    pj_cstr(&udpString, fullAddressStr.c_str());
-    pj_sockaddr boundAddr;
-    pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &udpString, &boundAddr);
-    pj_status_t status;
-    pjsip_transport *transport = NULL;
-
-    if (boundAddr.addr.sa_family == pj_AF_INET()) {
-        status = pjsip_udp_transport_start(endpt_, &boundAddr.ipv4, NULL, 1, &transport);
-        if (status != PJ_SUCCESS) {
-            ERROR("UDP IPV4 Transport did not start");
-            sip_strerror(status);
-            return NULL;
-        }
-    } else if (boundAddr.addr.sa_family == pj_AF_INET6()) {
-        status = pjsip_udp_transport_start6(endpt_, &boundAddr.ipv6, NULL, 1, &transport);
-        if (status != PJ_SUCCESS) {
-            ERROR("UDP IPV6 Transport did not start");
-            sip_strerror(status);
-            return NULL;
+            ++it;
         }
+        pj_lock_release(t->lock);
     }
-
-    DEBUG("Created UDP transport on %s:%d", interface.c_str(), port);
-    DEBUG("Listening address %s", fullAddressStr.c_str());
-    // dump debug information to stdout
-    pjsip_tpmgr_dump_transports(pjsip_endpt_get_tpmgr(endpt_));
-    transportMap_[transportMapKey(interface, port)] = transport;
-
-    return transport;
 }
 
-
 pjsip_tpselector *SipTransport::createTransportSelector(pjsip_transport *transport, pj_pool_t *tp_pool) const
 {
     RETURN_IF_FAIL(transport != NULL, NULL, "Transport is not initialized");
@@ -343,18 +366,18 @@ pjsip_tpselector *SipTransport::createTransportSelector(pjsip_transport *transpo
     return tp;
 }
 
-std::vector<pj_sockaddr_in>
+std::vector<pj_sockaddr>
 SipTransport::getSTUNAddresses(const SIPAccount &account,
         std::vector<long> &socketDescriptors) const
 {
     const pj_str_t serverName = account.getStunServerName();
     const pj_uint16_t port = account.getStunPort();
-
-    std::vector<pj_sockaddr_in> result(socketDescriptors.size());
+    const size_t ip_num = socketDescriptors.size();
+    pj_sockaddr_in ipv4[ip_num];
 
     pj_status_t ret;
-    if ((ret = pjstun_get_mapped_addr(&cp_->factory, socketDescriptors.size(), &socketDescriptors[0],
-                    &serverName, port, &serverName, port, &result[0])) != PJ_SUCCESS) {
+    if ((ret = pjstun_get_mapped_addr(&cp_.factory, socketDescriptors.size(), &socketDescriptors[0],
+                    &serverName, port, &serverName, port, ipv4)) != PJ_SUCCESS) {
         ERROR("STUN query to server \"%.*s\" failed", serverName.slen, serverName.ptr);
         switch (ret) {
             case PJLIB_UTIL_ESTUNNOTRESPOND:
@@ -369,43 +392,42 @@ SipTransport::getSTUNAddresses(const SIPAccount &account,
         throw std::runtime_error("Can't resolve STUN request");
     }
 
-
-    for (const auto & it : result)
-        WARN("STUN PORTS: %ld", pj_ntohs(it.sin_port));
-
+    std::vector<pj_sockaddr> result(ip_num);
+    for(size_t i=0; i<ip_num; i++) {
+        result[i].addr.sa_family = pj_AF_INET();
+        result[i].ipv4 = ipv4[i];
+        WARN("STUN PORTS: %ld", pj_ntohs(ipv4[i].sin_port));
+    }
     return result;
 }
 
 #define RETURN_IF_NULL(A, M, ...) if ((A) == NULL) { ERROR(M, ##__VA_ARGS__); return; }
 
-void SipTransport::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &addr, std::string &port) const
+void SipTransport::findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &addr, pj_uint16_t &port) const
 {
-
     // Initialize the sip port with the default SIP port
-    std::stringstream ss;
-    ss << DEFAULT_SIP_PORT;
-    port = ss.str();
+    port = DEFAULT_SIP_PORT;
 
     // Initialize the sip address with the hostname
     const pj_str_t *pjMachineName = pj_gethostname();
     addr = std::string(pjMachineName->ptr, pjMachineName->slen);
 
     // Update address and port with active transport
-    RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
+    RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port);
 
     // get the transport manager associated with the SIP enpoint
     pjsip_tpmgr *tpmgr = pjsip_endpt_get_tpmgr(endpt_);
-    RETURN_IF_NULL(tpmgr, "Transport manager is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
+    RETURN_IF_NULL(tpmgr, "Transport manager is NULL in findLocalAddress, using local address %s :%d", addr.c_str(), port);
 
     // initialize a transport selector
     // TODO Need to determine why we exclude TLS here...
     // if (transportType == PJSIP_TRANSPORT_UDP and transport_)
-    pjsip_tpselector *tp_sel = createTransportSelector(transport, pool_);
-    RETURN_IF_NULL(tp_sel, "Could not initialize transport selector, using local address %s:%s", addr.c_str(), port.c_str());
+    pjsip_tpselector *tp_sel = createTransportSelector(transport, &pool_);
+    RETURN_IF_NULL(tp_sel, "Could not initialize transport selector, using local address %s :%d", addr.c_str(), port);
 
-    pjsip_tpmgr_fla2_param param = {transportType, tp_sel, {0,0}, PJ_FALSE, {0,0}, 0, NULL};
-    if (pjsip_tpmgr_find_local_addr2(tpmgr, pool_, &param) != PJ_SUCCESS) {
-        WARN("Could not retrieve local address and port from transport, using %s:%s", addr.c_str(), port.c_str());
+    pjsip_tpmgr_fla2_param param = {transportType, tp_sel, {nullptr,0}, PJ_FALSE, {nullptr,0}, 0, nullptr};
+    if (pjsip_tpmgr_find_local_addr2(tpmgr, &pool_, &param) != PJ_SUCCESS) {
+        WARN("Could not retrieve local address and port from transport, using %s :%d", addr.c_str(), port);
         return;
     }
 
@@ -413,33 +435,29 @@ void SipTransport::findLocalAddressFromTransport(pjsip_transport *transport, pjs
     addr = std::string(param.ret_addr.ptr, param.ret_addr.slen);
 
     // Determine the local port based on transport information
-    ss.str("");
-    ss << param.ret_port;
-    port = ss.str();
+    port = param.ret_port;
 }
 
 void
 SipTransport::findLocalAddressFromSTUN(pjsip_transport *transport,
                                        pj_str_t *stunServerName,
                                        int stunPort,
-                                       std::string &addr, std::string &port) const
+                                       std::string &addr, pj_uint16_t &port) const
 {
     // Initialize the sip port with the default SIP port
-    std::stringstream ss;
-    ss << DEFAULT_SIP_PORT;
-    port = ss.str();
+    port = DEFAULT_SIP_PORT;
 
     // Initialize the sip address with the hostname
     const pj_str_t *pjMachineName = pj_gethostname();
     addr = std::string(pjMachineName->ptr, pjMachineName->slen);
 
     // Update address and port with active transport
-    RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s:%s", addr.c_str(), port.c_str());
+    RETURN_IF_NULL(transport, "Transport is NULL in findLocalAddress, using local address %s:%d", addr.c_str(), port);
 
     pj_sockaddr_in mapped_addr;
     pj_sock_t sipSocket = pjsip_udp_transport_get_socket(transport);
     const pjstun_setting stunOpt = {PJ_TRUE, *stunServerName, stunPort, *stunServerName, stunPort};
-    const pj_status_t stunStatus = pjstun_get_mapped_addr2(&cp_->factory,
+    const pj_status_t stunStatus = pjstun_get_mapped_addr2(&cp_.factory,
             &stunOpt, 1, &sipSocket, &mapped_addr);
 
     switch (stunStatus) {
@@ -453,13 +471,10 @@ SipTransport::findLocalAddressFromSTUN(pjsip_transport *transport,
            break;
     }
 
-    addr = std::string(pj_inet_ntoa(mapped_addr.sin_addr));
-    std::ostringstream os;
-    os << pj_ntohs(mapped_addr.sin_port);
-    port = os.str();
+    port = pj_sockaddr_get_port(&mapped_addr);
 
-    WARN("Using address %s:%s provided by STUN server %.*s",
-         addr.c_str(), port.c_str(), stunServerName->slen, stunServerName->ptr);
+    WARN("Using address %s:%d provided by STUN server %.*s",
+         addr.c_str(), port, stunServerName->slen, stunServerName->ptr);
 }
 
 #undef RETURN_IF_NULL
diff --git a/daemon/src/sip/siptransport.h b/daemon/src/sip/siptransport.h
index 0896576821e263adce01123a2c8a9af5c32138cd..fe1cc1c67a19a30bc0e0d75491171e24ffccb128 100644
--- a/daemon/src/sip/siptransport.h
+++ b/daemon/src/sip/siptransport.h
@@ -32,30 +32,43 @@
 #ifndef SIPTRANSPORT_H_
 #define SIPTRANSPORT_H_
 
-#include <string>
-#include <vector>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "noncopyable.h"
+#include "logger.h"
 
 #include <pjsip.h>
-#include <pjlib.h>
 #include <pjsip_ua.h>
+#include <pjlib.h>
 #include <pjlib-util.h>
 #include <pjnath.h>
 #include <pjnath/stun_config.h>
-#include "noncopyable.h"
 
-#include "config.h"
+#include <map>
+#include <string>
+#include <vector>
+#include <memory>
 
 class SIPAccount;
 
+/* An IPv4 equivalent to IN6_IS_ADDR_UNSPECIFIED */
+#ifndef IN_IS_ADDR_UNSPECIFIED
+#define IN_IS_ADDR_UNSPECIFIED(a) (((long int) (a)->s_addr) == 0x00000000)
+#endif /* IN_IS_ADDR_UNSPECIFIED */
+
 class SipTransport {
     public:
-        SipTransport(pjsip_endpoint *endpt, pj_caching_pool *cp, pj_pool_t *pool);
-        static std::string getSIPLocalIP();
+        SipTransport(pjsip_endpoint *endpt, pj_caching_pool& cp, pj_pool_t& pool);
+
+        static pj_sockaddr getSIPLocalIP(pj_uint16_t family = pj_AF_UNSPEC());
 
         /**
          * Get the IP for the network interface named ifaceName
+         * @param forceIPv6 If IPv4 and IPv6 are available, will force to IPv6.
          */
-        static std::string getInterfaceAddrFromName(const std::string &ifaceName);
+        static std::string getInterfaceAddrFromName(const std::string &ifaceName, bool forceIPv6 = false);
+        static pj_sockaddr getInterfaceAddr(const std::string &ifaceName, bool forceIPv6 = false);
 
         /**
         * List all the interfaces on the system and return
@@ -69,10 +82,10 @@ class SipTransport {
 
         /**
          * List all the interfaces on the system and return
-         * a vector list containing their IPV4 address.
+         * a vector list containing their IP address.
          * @param void
          * @return std::vector<std::string> A std::string vector
-         * of IPV4 address available on all of the interfaces on
+         * of IP address available on all of the interfaces on
          * the system.
          */
         static std::vector<std::string> getAllIpInterface();
@@ -82,7 +95,7 @@ class SipTransport {
          * transport type specified in account settings
          * @param account The account for which a transport must be created.
          */
-        void createSipTransport(SIPAccount &account);
+        void createSipTransport(SIPAccount &account, pj_uint16_t family = pj_AF_UNSPEC());
 
         /**
          * Initialize the transport selector
@@ -96,7 +109,7 @@ class SipTransport {
         /**
          * This function returns a list of STUN mapped sockets for
          * a given set of socket file descriptors */
-        std::vector<pj_sockaddr_in>
+        std::vector<pj_sockaddr>
         getSTUNAddresses(const SIPAccount &account,
                          std::vector<long> &socks) const;
 
@@ -108,10 +121,10 @@ class SipTransport {
          * @param uri The uri from which we want to discover the address to use
          * @param transport The transport to use to discover the address
          */
-        void findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &address, std::string &port) const;
+        void findLocalAddressFromTransport(pjsip_transport *transport, pjsip_transport_type_e transportType, std::string &address, pj_uint16_t &port) const;
 
         void findLocalAddressFromSTUN(pjsip_transport *transport, pj_str_t *stunServerName,
-                int stunPort, std::string &address, std::string &port) const;
+                int stunPort, std::string &address, pj_uint16_t &port) const;
 
     private:
         NON_COPYABLE(SipTransport);
@@ -131,18 +144,26 @@ class SipTransport {
          * Create The default TLS listener which is global to the application. This means that
          * only one TLS connection can be established for the momment.
          * @param the SIPAccount for which we are creating the TLS listener
+         * @param IP protocol version to use, can be pj_AF_INET() or pj_AF_INET6()
          * @return a pointer to the new listener
          */
         pjsip_tpfactory *
-        createTlsListener(SIPAccount &account);
+        createTlsListener(SIPAccount &account, pj_uint16_t family = pj_AF_UNSPEC());
 #endif
 
         /**
         * Create SIP UDP transport from account's setting
         * @param account The account for which a transport must be created.
+        * @param IP protocol version to use, can be pj_AF_INET() or pj_AF_INET6()
+        * @return a pointer to the new transport
         */
         pjsip_transport *createUdpTransport(const std::string &interface,
-                                            unsigned int port);
+                                            pj_uint16_t port, pj_uint16_t family = pj_AF_UNSPEC());
+
+        /**
+         * Go through the transport list and remove unused ones.
+         */
+        void cleanupTransports();
 
         /**
          * UDP Transports are stored in this map in order to retreive them in case
@@ -150,9 +171,8 @@ class SipTransport {
          */
         std::map<std::string, pjsip_transport*> transportMap_;
 
-        pj_caching_pool *cp_;
-
-        pj_pool_t *pool_;
+        pj_caching_pool& cp_;
+        pj_pool_t& pool_;
 
         pjsip_endpoint *endpt_;
 };
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index c1afd873f2e159a0a51fcaf3d7fb230640bd2447..ddabbb8de760556b5ec75a11076c5d573676c305 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -31,13 +31,13 @@
  *  as that of the covered work.
  */
 
+#include "sipvoiplink.h"
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "sip_utils.h"
-
-#include "sipvoiplink.h"
 #include "array_size.h"
 #include "manager.h"
 #include "map_utils.h"
@@ -51,7 +51,6 @@
 #endif
 #include "array_size.h"
 
-
 #if HAVE_INSTANT_MESSAGING
 #include "im/instant_messaging.h"
 #endif
@@ -71,6 +70,12 @@
 #include "pjsip/sip_uri.h"
 #include "pjnath.h"
 
+#ifdef SFL_PRESENCE
+#include "pjsip-simple/presence.h"
+#include "pjsip-simple/publish.h"
+#include "pres_sub_server.h"
+#endif
+
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <arpa/inet.h>
@@ -79,15 +84,9 @@
 #include <utility> // for std::pair
 #include <algorithm>
 
-#ifdef SFL_PRESENCE
-#include "pjsip-simple/presence.h"
-#include "pjsip-simple/publish.h"
-#include "pres_sub_server.h"
-#endif
-
 using namespace sfl;
 
-SIPVoIPLink *SIPVoIPLink::instance_ = 0;
+SIPVoIPLink *SIPVoIPLink::instance_ = nullptr;
 
 namespace {
 
@@ -105,7 +104,7 @@ static std::map<std::string, std::string> transferCallID;
  * localport, localip, localexternalport
  * @param call a SIPCall valid pointer
  */
-void setCallMediaLocal(SIPCall* call, const std::string &localIP);
+void setCallMediaLocal(SIPCall* call, const pj_sockaddr& localIP);
 
 static pj_caching_pool pool_cache, *cp_ = &pool_cache;
 static pj_pool_t *pool_;
@@ -197,12 +196,12 @@ void updateSDPFromSTUN(SIPCall &call, SIPAccount &account, const SipTransport &t
     std::vector<long> socketDescriptors(call.getAudioRtp().getSocketDescriptors());
 
     try {
-        std::vector<pj_sockaddr_in> stunPorts(transport.getSTUNAddresses(account, socketDescriptors));
+        std::vector<pj_sockaddr> stunPorts(transport.getSTUNAddresses(account, socketDescriptors));
 
         // FIXME: get video sockets
         stunPorts.resize(4);
 
-        account.setPublishedAddress(pj_inet_ntoa(stunPorts[0].sin_addr));
+        account.setPublishedAddress(stunPorts[0]);
         // published IP MUST be updated first, since RTCP depends on it
         call.getLocalSDP()->setPublishedIP(account.getPublishedAddress());
         call.getLocalSDP()->updatePorts(stunPorts);
@@ -315,10 +314,9 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
     SIPCall* call = new SIPCall(Manager::instance().getNewCallID(), Call::INCOMING, cp_, account_id);
 
     // May use the published address as well
-    std::string addrToUse = SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
-    std::string addrSdp = account->isStunEnabled() or (not account->getPublishedSameasLocal())
-                          ? account->getPublishedAddress()
-                          : addrToUse;
+    auto addrToUse = SipTransport::getInterfaceAddr(account->getLocalInterface());
+    auto addrSdp = account->isStunEnabled() or (not account->getPublishedSameasLocal())
+                    ? account->getPublishedIpAddress() : addrToUse;
 
     pjsip_tpselector *tp_sel = SIPVoIPLink::instance()->sipTransport->createTransportSelector(account->transport_, call->getMemoryPool());
 
@@ -339,6 +337,9 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
     if (not remote_user.empty() and not remote_hostname.empty())
         peerNumber = remote_user + "@" + remote_hostname;
 
+    //DEBUG("transaction_request_cb host %s userName %s addrToUse %s addrSdp %s remote_user %s remote_hostname %s" ,
+    //server.c_str(), userName.c_str(), sip_utils::addrToStr(addrToUse).c_str(), sip_utils::addrToStr(addrSdp).c_str(), remote_user.c_str(), remote_hostname.c_str());
+
     call->setConnectionState(Call::PROGRESSING);
     call->setPeerNumber(peerNumber);
     call->setDisplayName(displayName);
@@ -491,6 +492,7 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata)
         }
 
         // contactStr must stay in scope as long as tdata
+        ERROR("transaction_request_cb getContactHeader");
         const pj_str_t contactStr(account->getContactHeader());
         sip_utils::addContactHeader(&contactStr, tdata);
 
@@ -522,7 +524,7 @@ pjsip_module * SIPVoIPLink::getMod()
 }
 
 SIPVoIPLink::SIPVoIPLink() : sipTransport(), sipAccountMap_(),
-    sipCallMapMutex_(), sipCallMap_(), evThread_(this)
+    sipCallMapMutex_(), sipCallMap_(), evThread_(*this)
 #ifdef SFL_VIDEO
     , keyframeRequestsMutex_()
     , keyframeRequests_()
@@ -544,20 +546,20 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(), sipAccountMap_(),
     TRY(pjnath_init());
 
     pj_caching_pool_init(cp_, &pj_pool_factory_default_policy, 0);
-    pool_ = pj_pool_create(&cp_->factory, PACKAGE, 4000, 4000, NULL);
+    pool_ = pj_pool_create(&cp_->factory, PACKAGE, 4096, 4096, nullptr);
 
     if (!pool_)
         throw VoipLinkException("UserAgent: Could not initialize memory pool");
 
     TRY(pjsip_endpt_create(&cp_->factory, pj_gethostname()->ptr, &endpt_));
 
-    sipTransport.reset(new SipTransport(endpt_, cp_, pool_));
+    sipTransport.reset(new SipTransport(endpt_, *cp_, *pool_));
 
-    if (SipTransport::getSIPLocalIP().empty())
+    if (SipTransport::getSIPLocalIP().addr.sa_family == pj_AF_UNSPEC())
         throw VoipLinkException("UserAgent: Unable to determine network capabilities");
 
     TRY(pjsip_tsx_layer_init_module(endpt_));
-    TRY(pjsip_ua_init_module(endpt_, NULL));
+    TRY(pjsip_ua_init_module(endpt_, nullptr));
     TRY(pjsip_replaces_init_module(endpt_)); // See the Replaces specification in RFC 3891
     TRY(pjsip_100rel_init_module(endpt_));
 
@@ -583,11 +585,11 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(), sipAccountMap_(),
         outgoing_request_forked_cb,
         transaction_state_changed_cb,
         sdp_request_offer_cb,
-        NULL /* on_rx_reinvite */,
+        nullptr /* on_rx_reinvite */,
         sdp_create_offer_cb,
         sdp_media_update_cb,
-        NULL /* on_send_ack */,
-        NULL /* on_redirected */,
+        nullptr /* on_send_ack */,
+        nullptr /* on_redirected */,
     };
     TRY(pjsip_inv_usage_init(endpt_, &inv_cb));
 
@@ -598,13 +600,13 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(), sipAccountMap_(),
         CONST_PJ_STR("PUBLISH"),
     };
 
-    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
+    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ALLOW, nullptr, PJ_ARRAY_SIZE(allowed), allowed);
 
     static const pj_str_t text_plain = CONST_PJ_STR("text/plain");
-    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &text_plain);
+    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, nullptr, 1, &text_plain);
 
     static const pj_str_t accepted = CONST_PJ_STR("application/sdp");
-    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, NULL, 1, &accepted);
+    pjsip_endpt_add_capability(endpt_, &mod_ua_, PJSIP_H_ACCEPT, nullptr, 1, &accepted);
 
     DEBUG("pjsip version %s for %s initialized", pj_get_version(), PJ_OS_NAME);
 
@@ -627,18 +629,18 @@ SIPVoIPLink::~SIPVoIPLink()
 
     const pj_time_val tv = {0, 10};
     pjsip_endpt_handle_events(endpt_, &tv);
+
+    for (auto & a : sipAccountMap_)
+        unloadAccount(a);
+    sipAccountMap_.clear();
+    clearSipCallMap();
+
     pjsip_endpt_destroy(endpt_);
 
     pj_pool_release(pool_);
     pj_caching_pool_destroy(cp_);
 
-    for (auto & a : sipAccountMap_)
-        unloadAccount(a);
-
     pj_shutdown();
-    clearSipCallMap();
-
-    sipAccountMap_.clear();
 }
 
 SIPVoIPLink* SIPVoIPLink::instance()
@@ -654,7 +656,7 @@ SIPVoIPLink* SIPVoIPLink::instance()
 void SIPVoIPLink::destroy()
 {
     delete instance_;
-    instance_ = 0;
+    instance_ = nullptr;
 }
 
 std::string
@@ -788,6 +790,7 @@ void SIPVoIPLink::sendRegister(Account *a)
         }
     }
 
+    //DEBUG("pjsip_regc_init from:%s, srv:%s, contact:%s", from.c_str(), srvUri.c_str(), std::string(pj_strbuf(&pjContact), pj_strlen(&pjContact)).c_str());
     if (pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, account->getRegistrationExpire()) != PJ_SUCCESS)
         throw VoipLinkException("Unable to initialize account registration structure");
 
@@ -893,21 +896,6 @@ void SIPVoIPLink::cancelKeepAliveTimer(pj_timer_entry& timer)
     pjsip_endpt_cancel_timer(endpt_, &timer);
 }
 
-bool isValidIpAddress(const std::string &address)
-{
-    size_t pos = address.find(":");
-    std::string address_without_port(address);
-
-    if (pos != std::string::npos)
-        address_without_port = address.substr(0, pos);
-
-    DEBUG("Testing address %s", address_without_port.c_str());
-    struct sockaddr_in sa;
-    int result = inet_pton(AF_INET, address_without_port.data(), &(sa.sin_addr));
-    return result != 0;
-}
-
-
 Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toUrl, const std::string &account_id)
 {
     DEBUG("New outgoing call to %s", toUrl.c_str());
@@ -915,7 +903,7 @@ Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toU
 
     sip_utils::stripSipUriPrefix(toCpy);
 
-    const bool IPToIP = isValidIpAddress(toCpy);
+    const bool IPToIP = sip_utils::isValidAddr(toCpy);
     Manager::instance().setIPToIPForCall(id, IPToIP);
 
     if (IPToIP) {
@@ -925,9 +913,11 @@ Call *SIPVoIPLink::newOutgoingCall(const std::string& id, const std::string& toU
     }
 }
 
-Call *SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to)
+Call *SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to_raw)
 {
-    DEBUG("New IP to IP call to %s", to.c_str());
+    bool ipv6 = sip_utils::isIPv6(to_raw);
+    const std::string& to = ipv6 ? sip_utils::addrToStr(to_raw, false, true) : to_raw;
+    DEBUG("New %s IP to IP call to %s", ipv6?"IPv6":"IPv4", to.c_str());
 
     SIPAccount *account = Manager::instance().getIP2IPAccount();
 
@@ -939,7 +929,7 @@ Call *SIPVoIPLink::SIPNewIpToIpCall(const std::string& id, const std::string& to
     call->setIPToIP(true);
     call->initRecFilename(to);
 
-    std::string localAddress(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));
+    auto localAddress = SipTransport::getInterfaceAddr(account->getLocalInterface(), ipv6);
 
     setCallMediaLocal(call, localAddress);
 
@@ -987,7 +977,7 @@ Call *SIPVoIPLink::newRegisteredAccountCall(const std::string& id, const std::st
 
     SIPAccount *account = Manager::instance().getSipAccount(account_id);
 
-    if (account == NULL) // TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
+    if (account == nullptr) // TODO: We should investigate how we could get rid of this error and create a IP2IP call instead
         throw VoipLinkException("Could not get account for this call");
 
     SIPCall* call = new SIPCall(id, Call::OUTGOING, cp_, account->getAccountID());
@@ -1002,20 +992,19 @@ Call *SIPVoIPLink::newRegisteredAccountCall(const std::string& id, const std::st
         toUri = account->getToUri(toUrl);
 
     call->setPeerNumber(toUri);
-    std::string localAddr(SipTransport::getInterfaceAddrFromName(account->getLocalInterface()));
+    auto localAddr = SipTransport::getInterfaceAddr(account->getLocalInterface());
     setCallMediaLocal(call, localAddr);
 
     // May use the published address as well
-    std::string addrSdp = account->isStunEnabled() or (not account->getPublishedSameasLocal()) ?
-                          account->getPublishedAddress() :
-                          SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
+    auto addrSdp = account->isStunEnabled() or (not account->getPublishedSameasLocal()) ?
+                          account->getPublishedIpAddress() : localAddr;
 
     // Initialize the session using ULAW as default codec in case of early media
     // The session should be ready to receive media once the first INVITE is sent, before
     // the session initialization is completed
     sfl::AudioCodec* ac = Manager::instance().audioCodecFactory.instantiateCodec(PAYLOAD_CODEC_ULAW);
 
-    if (ac == NULL) {
+    if (!ac) {
         delete call;
         throw VoipLinkException("Could not instantiate codec for early media");
     }
@@ -1074,6 +1063,7 @@ SIPVoIPLink::answer(Call *call)
             updateSDPFromSTUN(*sipCall, *account, *SIPVoIPLink::instance()->sipTransport);
     }
 
+    ERROR("answer getContactHeader");
     pj_str_t contact(account->getContactHeader());
     sipCall->setContactHeader(&contact);
     sipCall->answer();
@@ -1137,6 +1127,7 @@ SIPVoIPLink::hangup(const std::string& id, int reason)
         return;
 
     // contactStr must stay in scope as long as tdata
+    ERROR("hangup getContactHeader");
     const pj_str_t contactStr(account->getContactHeader());
     sip_utils::addContactHeader(&contactStr, tdata);
 
@@ -1653,6 +1644,8 @@ SIPVoIPLink::SIPStartCall(SIPCall *call)
 
     pj_str_t pjContact(account->getContactHeader());
 
+    ERROR("SIPStartCall getContactHeader %s / %s -> %s", std::string(pj_strbuf(&pjContact), pj_strlen(&pjContact)).c_str(), from.c_str(), toUri.c_str());
+
     pjsip_dialog *dialog = NULL;
 
     if (pjsip_dlg_create_uac(pjsip_ua_instance(), &pjFrom, &pjContact, &pjTo, NULL, &dialog) != PJ_SUCCESS) {
@@ -1863,19 +1856,14 @@ void sdp_create_offer_cb(pjsip_inv_session *inv, pjmedia_sdp_session **p_offer)
     if (!account)
         return;
 
-    std::string address;
-
-    if (account->getPublishedSameasLocal())
-        address = SipTransport::getInterfaceAddrFromName(account->getLocalInterface());
-    else
-        address = account->getPublishedAddress();
-
-    const std::string addrSdp(address);
+    auto address = account->getPublishedSameasLocal()
+                    ? SipTransport::getInterfaceAddr(account->getLocalInterface())
+                    : account->getPublishedIpAddress();
 
     setCallMediaLocal(call, address);
 
     Sdp *localSDP = call->getLocalSDP();
-    localSDP->setPublishedIP(addrSdp);
+    localSDP->setPublishedIP(address);
     const bool created = localSDP->createOffer(account->getActiveAudioCodecs(), account->getActiveVideoCodecs());
 
     if (created)
@@ -2467,7 +2455,7 @@ void transfer_client_cb(pjsip_evsub *sub, pjsip_event *event)
     }
 }
 
-void setCallMediaLocal(SIPCall* call, const std::string &localIP)
+void setCallMediaLocal(SIPCall* call, const pj_sockaddr& localIP)
 {
     std::string account_id(call->getAccountId());
     SIPAccount *account = Manager::instance().getSipAccount(account_id);
diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h
index a0ac97b769bfbd549d09e79e001d1597027919e5..dadcd945445a09c8ca749466b535cddff50eafae 100644
--- a/daemon/src/sip/sipvoiplink.h
+++ b/daemon/src/sip/sipvoiplink.h
@@ -331,7 +331,7 @@ class SIPVoIPLink : public VoIPLink {
         std::queue<std::string> keyframeRequests_;
 #endif
 
-        static SIPVoIPLink *instance_;
+        static SIPVoIPLink * instance_;
 
         friend class SIPTest;
 };