From 7842c88a081bb98d80b430edab81efcbf6116122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com> Date: Sat, 12 Apr 2014 22:31:16 -0400 Subject: [PATCH] net: use sockaddr when relevant --- .../src/audio/audiortp/audio_rtp_factory.cpp | 9 +- .../audiortp/audio_symmetric_rtp_session.cpp | 46 ++ .../audiortp/audio_symmetric_rtp_session.h | 34 ++ daemon/src/call.cpp | 14 +- daemon/src/call.h | 26 +- daemon/src/eventthread.cpp | 4 +- daemon/src/eventthread.h | 6 +- daemon/src/iax/iaxvoiplink.cpp | 2 +- daemon/src/sip/sdp.cpp | 54 ++- daemon/src/sip/sdp.h | 8 +- daemon/src/sip/sip_utils.cpp | 86 +++- daemon/src/sip/sip_utils.h | 32 +- daemon/src/sip/sipaccount.cpp | 69 +-- daemon/src/sip/sipaccount.h | 37 +- daemon/src/sip/siptransport.cpp | 413 +++++++++--------- daemon/src/sip/siptransport.h | 58 ++- daemon/src/sip/sipvoiplink.cpp | 128 +++--- daemon/src/sip/sipvoiplink.h | 2 +- 18 files changed, 634 insertions(+), 394 deletions(-) diff --git a/daemon/src/audio/audiortp/audio_rtp_factory.cpp b/daemon/src/audio/audiortp/audio_rtp_factory.cpp index 50aa556834..085097a4b3 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 5d59f86bd1..607704fe26 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 77a597313f..0d91285e34 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 7411397c33..cfe39c74c6 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 41ba244ce2..839306a807 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 a6876aef7f..2aae290f34 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 43986b86a9..1dfddf5044 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 1e9ad8bdaa..990de886a2 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 b195017809..15b00e5915 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 a44b7a4602..048b0f873f 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 014bc61504..d8110b7f9e 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 a5d662bff3..5bc69fa304 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 6f1296874e..403c8cf357 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 1d016a12f1..b8d0ff6584 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 b4cae6942c..9e689bb5cf 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_, ¶m) != 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_, ¶m) != 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 0896576821..fe1cc1c67a 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 c1afd873f2..ddabbb8de7 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 a0ac97b769..dadcd94544 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; }; -- GitLab