diff --git a/src/jamidht/CMakeLists.txt b/src/jamidht/CMakeLists.txt index ea9d74b3e5ef10424ee83c20a5c9a90eeaf5c732..733f0070e346de302f18dfb73c02d8c3548209a0 100644 --- a/src/jamidht/CMakeLists.txt +++ b/src/jamidht/CMakeLists.txt @@ -5,6 +5,7 @@ # eth/libdevcore|eth/libdevcrypto list (APPEND Source_Files__jamidht + "${CMAKE_CURRENT_SOURCE_DIR}/abstract_sip_transport.h" "${CMAKE_CURRENT_SOURCE_DIR}/account_manager.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/account_manager.h" "${CMAKE_CURRENT_SOURCE_DIR}/accountarchive.cpp" diff --git a/src/jamidht/Makefile.am b/src/jamidht/Makefile.am index d2c7c3147f556a1b3203f70f963dbe1218567301..c991556d13059cf01a4bc2f3b8c1a1280b830a57 100644 --- a/src/jamidht/Makefile.am +++ b/src/jamidht/Makefile.am @@ -12,6 +12,7 @@ libringacc_la_LIBADD = $(DHT_LIBS) \ ./eth/libdevcrypto/libdevcrypto.la libringacc_la_SOURCES = \ + abstract_sip_transport.h \ jamiaccount.cpp \ jamiaccount.h \ connectionmanager.h \ diff --git a/src/jamidht/abstract_sip_transport.h b/src/jamidht/abstract_sip_transport.h new file mode 100644 index 0000000000000000000000000000000000000000..6f2c2268cd4698ecfff73c6d3afb9cb75ddc338e --- /dev/null +++ b/src/jamidht/abstract_sip_transport.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Savoir-faire Linux Inc. + * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +#include "ip_utils.h" +#include "sip/sip_utils.h" + +#include <pjsip.h> +#include <pj/pool.h> + +namespace jami { + +namespace tls { + +/** + * AbstractSIPTransport + * + * Implements a pjsip_transport on top + */ +class AbstractSIPTransport +{ +public: + using TransportData = struct { + pjsip_transport base; // do not move, SHOULD be the fist member + AbstractSIPTransport* self {nullptr}; + }; + static_assert(std::is_standard_layout<TransportData>::value, + "TranportData requires standard-layout"); + + virtual ~AbstractSIPTransport() {}; + + virtual pjsip_transport* getTransportBase() = 0; + + virtual IpAddr getLocalAddress() const = 0; +}; + +}} // namespace jami::tls diff --git a/src/jamidht/channeled_transport.cpp b/src/jamidht/channeled_transport.cpp index 3540e263e6a9f50af435022e70e357d202837004..c30543b6abcb30b19fe9ce704b2c2e3efda16808 100644 --- a/src/jamidht/channeled_transport.cpp +++ b/src/jamidht/channeled_transport.cpp @@ -89,18 +89,18 @@ ChanneledSIPTransport::ChanneledSIPTransport(pjsip_endpoint* endpt, int tp_type, pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr, int addr_len, void *token, pjsip_transport_callback callback) -> pj_status_t { - auto& this_ = reinterpret_cast<TransportData*>(transport)->self; + auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self); return this_->send(tdata, rem_addr, addr_len, token, callback); }; base.do_shutdown = [](pjsip_transport *transport) -> pj_status_t { - auto& this_ = reinterpret_cast<TransportData*>(transport)->self; + auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self); JAMI_DBG("ChanneledSIPTransport@%p {tr=%p {rc=%ld}}: shutdown", this_, transport, pj_atomic_get(transport->ref_cnt)); if (this_->socket_) this_->socket_->shutdown(); return PJ_SUCCESS; }; base.destroy = [](pjsip_transport *transport) -> pj_status_t { - auto& this_ = reinterpret_cast<TransportData*>(transport)->self; + auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self); JAMI_DBG("ChanneledSIPTransport@%p: destroying", this_); delete this_; return PJ_SUCCESS; @@ -289,4 +289,5 @@ ChanneledSIPTransport::send(pjsip_tx_data* tdata, const pj_sockaddr_t* rem_addr, return PJ_EPENDING; } + }} // namespace jami::tls diff --git a/src/jamidht/channeled_transport.h b/src/jamidht/channeled_transport.h index a082f400efd18601ca1d5848194a41474f596210..eb5fd6b06aaca7f8f92deed21d5b470595afec5d 100644 --- a/src/jamidht/channeled_transport.h +++ b/src/jamidht/channeled_transport.h @@ -20,13 +20,9 @@ #pragma once -#include "ip_utils.h" #include "noncopyable.h" #include "scheduled_executor.h" -#include "sip/sip_utils.h" - -#include <pjsip.h> -#include <pj/pool.h> +#include "jamidht/abstract_sip_transport.h" #include <atomic> #include <condition_variable> @@ -49,23 +45,21 @@ namespace tls { * * Implements a pjsip_transport on top of a ChannelSocket */ -class ChanneledSIPTransport +class ChanneledSIPTransport : public AbstractSIPTransport { public: - using TransportData = struct { - pjsip_transport base; // do not move, SHOULD be the fist member - ChanneledSIPTransport* self {nullptr}; - }; - static_assert(std::is_standard_layout<TransportData>::value, - "TranportData requires standard-layout"); - ChanneledSIPTransport(pjsip_endpoint* endpt, int tp_type, const std::shared_ptr<ChannelSocket>& socket, const IpAddr& local, const IpAddr& remote, onShutdownCb&& cb); ~ChanneledSIPTransport(); - pjsip_transport* getTransportBase() { return &trData_.base; } + pjsip_transport* getTransportBase() override { return &trData_.base; } + + IpAddr getLocalAddress() const override { + return local_; + } + private: NON_COPYABLE(ChanneledSIPTransport); diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index cfffc9452b427b2ff89693b2c8d8236c2f0dcb24..fb078ff4448b4aa7d2370f78f86097b75943334f 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -36,6 +36,7 @@ #include "contact_list.h" #include "archive_account_manager.h" #include "server_account_manager.h" +#include "jamidht/channeled_transport.h" #include "sip/sdp.h" #include "sip/sipvoiplink.h" @@ -322,9 +323,34 @@ JamiAccount::flush() } std::shared_ptr<SIPCall> -JamiAccount::newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details) +JamiAccount::newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details, const std::shared_ptr<SipTransport>& sipTr) { std::lock_guard<std::mutex> lock(callsMutex_); + + if (sipTr) { + std::unique_lock<std::mutex> lk(sipConnectionsMtx_); + auto sipConnIt = sipConnections_.find(from); + if (sipConnIt != sipConnections_.end() && !sipConnIt->second.empty()) { + for (auto dit = sipConnIt->second.rbegin(); dit != sipConnIt->second.rend(); ++dit) { + for (auto it = dit->second.rbegin(); it != dit->second.rend(); ++it) { + // Search linked Sip Transport + if (it->transport != sipTr) continue; + + auto call = Manager::instance().callFactory.newCall<SIPCall, JamiAccount>(*this, Manager::instance().getNewCallID(), Call::CallType::INCOMING); + if (!call) return {}; + + std::weak_ptr<SIPCall> wcall = call; + call->setPeerUri(RING_URI_PREFIX + from); + call->setPeerNumber(from); + + call->updateDetails(details); + return call; + } + } + } + lk.unlock(); + } + auto call_it = pendingSipCalls_.begin(); while (call_it != pendingSipCalls_.end()) { auto call = call_it->call.lock(); @@ -443,10 +469,29 @@ JamiAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: }); #endif + // Call connected devices + std::set<std::string> devices; + std::unique_lock<std::mutex> lk(sipConnectionsMtx_); + for (auto deviceConnIt = sipConnections_[toUri].begin(); deviceConnIt != sipConnections_[toUri].end(); ++deviceConnIt) { + if (deviceConnIt->second.empty()) continue; + auto& it = deviceConnIt->second.back(); + + auto transport = it.transport; + if (!transport) continue; + call->setTransport(transport); + + auto remote_addr = it.channel->underlyingICE()->getRemoteAddress(ICE_COMP_SIP_TRANSPORT); + onConnectedOutgoingCall(*call, deviceConnIt->first, remote_addr); + + devices.emplace(deviceConnIt->first); + } + // Find listening devices for this account dht::InfoHash peer_account(toUri); - accountManager_->forEachDevice(peer_account, [this, wCall, toUri, peer_account](const dht::InfoHash& dev) + accountManager_->forEachDevice(peer_account, [this, wCall, toUri, peer_account, devices](const dht::InfoHash& dev) { + // Test if already sent via a SIP transport + if (devices.find(dev.toString()) != devices.end()) return; auto call = wCall.lock(); if (not call) return; JAMI_DBG("[call %s] calling device %s", call->getCallId().c_str(), dev.toString().c_str()); @@ -2445,9 +2490,9 @@ JamiAccount::getContactHeader(pjsip_transport* t) { std::string quotedDisplayName = "\"" + displayName_ + "\" " + (displayName_.empty() ? "" : " "); if (t) { - // FIXME: be sure that given transport is from SipIceTransport - auto tlsTr = reinterpret_cast<tls::SipsIceTransport::TransportData*>(t)->self; - auto address = tlsTr->getLocalAddress().toString(true); + auto* td = reinterpret_cast<tls::AbstractSIPTransport::TransportData*>(t); + auto address = td->self->getLocalAddress().toString(true); + contact_.slen = pj_ansi_snprintf(contact_.ptr, PJSIP_MAX_URL_SIZE, "%s<sips:%s%s%s;transport=dtls>", quotedDisplayName.c_str(), diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index 9f1230b4b687e4902a4407e11253d5be3afd3aa2..60ff268281d6b800036c945abc47dd9f6977d8b1 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -263,12 +263,13 @@ public: * Create incoming SIPCall. * @param[in] from The origin of the call * @param details use to set some specific details + * @param sipTr: current SIP Transport * @return std::shared_ptr<T> A shared pointer on the created call. * The type of this instance is given in template argument. * This type can be any base class of SIPCall class (included). */ virtual std::shared_ptr<SIPCall> - newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}) override; + newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}, const std::shared_ptr<SipTransport>& sipTr = nullptr) override; virtual bool isTlsEnabled() const override { return true; diff --git a/src/jamidht/sips_transport_ice.cpp b/src/jamidht/sips_transport_ice.cpp index afff4e0ea9c3c232f2fddebfc6e8f297839df401..964cc579c0d62c5c5a073331b5e94dc8c5e28267 100644 --- a/src/jamidht/sips_transport_ice.cpp +++ b/src/jamidht/sips_transport_ice.cpp @@ -183,7 +183,7 @@ SipsIceTransport::SipsIceTransport(pjsip_endpoint* endpt, pjsip_tx_data *tdata, const pj_sockaddr_t *rem_addr, int addr_len, void *token, pjsip_transport_callback callback) -> pj_status_t { - auto& this_ = reinterpret_cast<TransportData*>(transport)->self; + auto* this_ = reinterpret_cast<SipsIceTransport*>(reinterpret_cast<TransportData*>(transport)->self); return this_->send(tdata, rem_addr, addr_len, token, callback); }; base.do_shutdown = [](pjsip_transport *transport) -> pj_status_t { @@ -706,7 +706,7 @@ SipsIceTransport::send(pjsip_tx_data* tdata, const pj_sockaddr_t* rem_addr, } uint16_t -SipsIceTransport::getTlsSessionMtu() +SipsIceTransport::getTlsSessionMtu() const { return tls_->maxPayload(); } diff --git a/src/jamidht/sips_transport_ice.h b/src/jamidht/sips_transport_ice.h index 13990ef809841a3ce6ceaa1fdf377dd6f212977b..f4b389999849a22f42441f06f85c11249ba60f3e 100644 --- a/src/jamidht/sips_transport_ice.h +++ b/src/jamidht/sips_transport_ice.h @@ -22,9 +22,9 @@ #pragma once #include "security/tls_session.h" -#include "ip_utils.h" #include "noncopyable.h" #include "scheduled_executor.h" +#include "jamidht/abstract_sip_transport.h" #include <pjsip.h> #include <pj/pool.h> @@ -54,16 +54,9 @@ namespace jami { namespace tls { * * Implements TLS transport as an pjsip_transport */ -struct SipsIceTransport +class SipsIceTransport : public AbstractSIPTransport { - using clock = std::chrono::steady_clock; - using TransportData = struct { - pjsip_transport base; // do not move, SHOULD be the fist member - SipsIceTransport* self {nullptr}; - }; - static_assert(std::is_standard_layout<TransportData>::value, - "TranportData requires standard-layout"); - +public: SipsIceTransport(pjsip_endpoint* endpt, int tp_type, const TlsParams& param, const std::shared_ptr<IceTransport>& ice, int comp_id); ~SipsIceTransport(); @@ -71,13 +64,13 @@ struct SipsIceTransport void shutdown(); std::shared_ptr<IceTransport> getIceTransport() const { return ice_; } - pjsip_transport* getTransportBase() { return &trData_.base; } + pjsip_transport* getTransportBase() override { return &trData_.base; } - IpAddr getLocalAddress() const { return local_; } + IpAddr getLocalAddress() const override { return local_; } IpAddr getRemoteAddress() const { return remote_; } // uses the tls_ uniquepointer internal gnutls_session_t, to call its method to get its MTU - uint16_t getTlsSessionMtu(); + uint16_t getTlsSessionMtu() const; private: NON_COPYABLE(SipsIceTransport); diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 0d1342ad634319db00ba8cf16252826c07e1ba58..96798b72c08cfd4df52dd2dad40f658c12103501 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -170,7 +170,7 @@ SIPAccount::~SIPAccount() } std::shared_ptr<SIPCall> -SIPAccount::newIncomingCall(const std::string& from UNUSED, const std::map<std::string, std::string>& details) +SIPAccount::newIncomingCall(const std::string& from UNUSED, const std::map<std::string, std::string>& details, const std::shared_ptr<SipTransport>&) { auto& manager = Manager::instance(); return manager.callFactory.newCall<SIPCall, SIPAccount>(*this, diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index 4b65318e388f6fda762fb3665e4e643452602de8..8b505ac7201152fa781924bb2a6ea36a4cfe3790 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -515,7 +515,7 @@ class SIPAccount : public SIPAccountBase { * This type can be any base class of SIPCall class (included). */ std::shared_ptr<SIPCall> - newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}) override; + newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}, const std::shared_ptr<SipTransport>& = nullptr) override; void onRegister(pjsip_regc_cbparam *param); diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h index 8e452e84523e0cfa9e6e93d0349dabc93a21b74d..aebe3ac5fb1a0974adfff37fe39158c7324a18b6 100644 --- a/src/sip/sipaccountbase.h +++ b/src/sip/sipaccountbase.h @@ -52,6 +52,8 @@ struct pjmedia_sdp_session; namespace jami { +class SipTransport; + namespace Conf { // SIP specific configuration keys const char *const BIND_ADDRESS_KEY = "bindAddress"; @@ -134,7 +136,7 @@ public: * This type can be any base class of SIPCall class (included). */ virtual std::shared_ptr<SIPCall> - newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}) = 0; + newIncomingCall(const std::string& from, const std::map<std::string, std::string>& details = {}, const std::shared_ptr<SipTransport>& = nullptr) = 0; virtual bool isStunEnabled() const { return false; diff --git a/src/sip/siptransport.cpp b/src/sip/siptransport.cpp index bb607ece60743b1ec6587a6a242b3559a850583d..e3aea4ece88d189296bf0f93a3100c4a3913655f 100644 --- a/src/sip/siptransport.cpp +++ b/src/sip/siptransport.cpp @@ -163,8 +163,9 @@ SipTransport::removeStateListener(uintptr_t lid) uint16_t SipTransport::getTlsMtu() { + auto* td = reinterpret_cast<tls::AbstractSIPTransport::TransportData*>(transport_.get()); if (isIceTransport_ && isSecure()) { - auto tls_tr = reinterpret_cast<tls::SipsIceTransport::TransportData*>(transport_.get())->self; + auto* tls_tr = reinterpret_cast<tls::SipsIceTransport*>(td->self); return tls_tr->getTlsSessionMtu(); } return 1232; /* Hardcoded yes (it's the IPv6 value). @@ -440,7 +441,7 @@ SipTransportBroker::getChanneledTransport(const std::shared_ptr<ChannelSocket>& auto sips_tr = std::make_unique<tls::ChanneledSIPTransport>(endpt_, type, socket, local, remote, std::move(cb)); auto tr = sips_tr->getTransportBase(); auto sip_tr = std::make_shared<SipTransport>(tr); - sip_tr->setIsIceTransport(); + sip_tr->setIsChanneledTransport(); sips_tr.release(); // managed by PJSIP now { diff --git a/src/sip/siptransport.h b/src/sip/siptransport.h index 7fd04a6d6604bf8ef03ea76723e95f4008bd6edc..ccbfc26c784fdf2fde83fe6afab699d132ee8552 100644 --- a/src/sip/siptransport.h +++ b/src/sip/siptransport.h @@ -114,6 +114,7 @@ class SipTransport bool isConnected() const noexcept { return connected_; } void setIsIceTransport() { isIceTransport_ = true; } + void setIsChanneledTransport() { isChanneledTransport_ = true; } uint16_t getTlsMtu(); @@ -129,6 +130,7 @@ class SipTransport bool connected_ {false}; bool isIceTransport_ {false}; + bool isChanneledTransport_ {false}; TlsInfos tlsInfos_; }; diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp index 7af2660029e83ed48041ada1af884fc2ba5cb91e..00e9b95280c61f9f72f420e98a56b76d863edbe1 100644 --- a/src/sip/sipvoiplink.cpp +++ b/src/sip/sipvoiplink.cpp @@ -294,7 +294,8 @@ transaction_request_cb(pjsip_rx_data *rdata) } } - auto call = account->newIncomingCall(remote_user, {{"AUDIO_ONLY", (hasVideo ? "false" : "true") }}); + auto transport = link->sipTransportBroker->addTransport(rdata->tp_info.transport); + auto call = account->newIncomingCall(remote_user, {{"AUDIO_ONLY", (hasVideo ? "false" : "true") }}, transport); if (!call) { return PJ_FALSE; } @@ -303,7 +304,6 @@ transaction_request_cb(pjsip_rx_data *rdata) // viaHostname.c_str(), toUsername.c_str(), addrToUse.toString().c_str(), addrSdp.toString().c_str(), peerNumber.c_str()); // Append PJSIP transport to the broker's SipTransport list - auto transport = link->sipTransportBroker->addTransport(rdata->tp_info.transport); if (!transport) { if (not ::strcmp(account->getAccountType(), SIPAccount::ACCOUNT_TYPE)) { JAMI_WARN("Using transport from account.");