diff --git a/configure.ac b/configure.ac index ddf51cd4a1978a231344cebc05f553197ea02827..604c07c7c0f8bca71ccb693bcfea64c6c5ed0dc1 100644 --- a/configure.ac +++ b/configure.ac @@ -638,7 +638,6 @@ AC_CONFIG_FILES([Makefile \ ringtones/Makefile \ test/Makefile\ test/sip/Makefile - test/turn/Makefile \ test/unitTest/Makefile \ man/Makefile \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2489e952681a48f786525791e86b9e9c6c542e7..e7c29d0c88d06bdb63076f317502ba132701cc71 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,8 +60,6 @@ list (APPEND Source_Files "${CMAKE_CURRENT_SOURCE_DIR}/string_utils.h" "${CMAKE_CURRENT_SOURCE_DIR}/threadloop.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/threadloop.h" - "${CMAKE_CURRENT_SOURCE_DIR}/turn_transport.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/turn_transport.h" "${CMAKE_CURRENT_SOURCE_DIR}/utf8_utils.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/utf8_utils.h" ) diff --git a/src/Makefile.am b/src/Makefile.am index 3c0dbbc769387f3aef7f33a2109bf27583fb9182..88b0cf40e71b1308a56ff6a97dc97d7b039fabd5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -164,8 +164,6 @@ libring_la_SOURCES = \ smartools.h \ base64.h \ base64.cpp \ - turn_transport.h \ - turn_transport.cpp \ channel.h \ peer_connection.cpp \ peer_connection.h \ diff --git a/src/jamidht/p2p.cpp b/src/jamidht/p2p.cpp index 95ff77b05c4cbf10ebdd64814f0ec9ebe1c732b6..183c27a503e3199cbbe0c5436e5b02ee413419f9 100644 --- a/src/jamidht/p2p.cpp +++ b/src/jamidht/p2p.cpp @@ -28,7 +28,6 @@ #include "ftp_server.h" #include "manager.h" #include "peer_connection.h" -#include "turn_transport.h" #include "account_manager.h" #include "multiplexed_socket.h" #include "connectionmanager.h" diff --git a/src/meson.build b/src/meson.build index b8c611b6cf2f540c6f9a6846d84cf971fc0b2e96..82a31297f600718972b8107e19f4ddb8ee1d8d97 100644 --- a/src/meson.build +++ b/src/meson.build @@ -109,7 +109,6 @@ libjami_sources = files( 'smartools.cpp', 'string_utils.cpp', 'threadloop.cpp', - 'turn_transport.cpp', 'utf8_utils.cpp' ) if host_machine.system() == 'windows' diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index ba4ccdd0cfd6129a46f5d59945c736457b92110c..fb354d09e99ed1865df68a9d81e646a7862c7062 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -26,7 +26,6 @@ #include "jamidht/jamiaccount.h" #include "string_utils.h" #include "channel.h" -#include "turn_transport.h" #include "security/tls_session.h" #include <algorithm> @@ -89,246 +88,6 @@ static constexpr std::size_t IO_BUFFER_SIZE {8192}; ///< Size of char buffer use //============================================================================== -class TlsTurnEndpoint::Impl -{ -public: - static constexpr auto TLS_TIMEOUT = std::chrono::seconds(20); - - Impl(std::unique_ptr<ConnectedTurnTransport>&& turn_ep, - std::function<bool(const dht::crypto::Certificate&)>&& cert_check, - const Identity& local_identity, - const std::shared_future<tls::DhParams>& dh_params) - : peerCertificateCheckFunc {std::move(cert_check)} - { - // Add TLS over TURN - tls::TlsSession::TlsSessionCallbacks tls_cbs - = {/*.onStateChange = */ [this](tls::TlsSessionState state) { onTlsStateChange(state); }, - /*.onRxData = */ [this](std::vector<uint8_t>&& buf) { onTlsRxData(std::move(buf)); }, - /*.onCertificatesUpdate = */ - [this](const gnutls_datum_t* l, const gnutls_datum_t* r, unsigned int n) { - onTlsCertificatesUpdate(l, r, n); - }, - /*.verifyCertificate = */ - [this](gnutls_session_t session) { - return verifyCertificate(session); - }}; - tls::TlsParams tls_param = { - /*.ca_list = */ "", - /*.peer_ca = */ nullptr, - /*.cert = */ local_identity.second, - /*.cert_key = */ local_identity.first, - /*.dh_params = */ dh_params, - /*.timeout = */ Impl::TLS_TIMEOUT, - /*.cert_check = */ nullptr, - }; - tls = std::make_unique<tls::TlsSession>(std::move(turn_ep), tls_param, tls_cbs); - } - - ~Impl(); - - // TLS callbacks - int verifyCertificate(gnutls_session_t); - void onTlsStateChange(tls::TlsSessionState); - void onTlsRxData(std::vector<uint8_t>&&); - void onTlsCertificatesUpdate(const gnutls_datum_t*, const gnutls_datum_t*, unsigned int); - - std::unique_ptr<tls::TlsSession> tls; - std::function<bool(const dht::crypto::Certificate&)> peerCertificateCheckFunc; - dht::crypto::Certificate peerCertificate; - std::mutex cbMtx_ {}; - OnStateChangeCb onStateChangeCb_; -}; - -// Declaration at namespace scope is necessary (until C++17) -constexpr std::chrono::seconds TlsTurnEndpoint::Impl::TLS_TIMEOUT; - -TlsTurnEndpoint::Impl::~Impl() {} - -int -TlsTurnEndpoint::Impl::verifyCertificate(gnutls_session_t session) -{ - dht::crypto::Certificate crt; - auto verified = init_crt(session, crt); - if (verified != GNUTLS_E_SUCCESS) - return verified; - - if (!peerCertificateCheckFunc(crt)) - return GNUTLS_E_CERTIFICATE_ERROR; - - peerCertificate = std::move(crt); - - return GNUTLS_E_SUCCESS; -} - -void -TlsTurnEndpoint::Impl::onTlsStateChange(tls::TlsSessionState state) -{ - std::lock_guard<std::mutex> lk(cbMtx_); - if (onStateChangeCb_ && !onStateChangeCb_(state)) - onStateChangeCb_ = {}; -} - -void -TlsTurnEndpoint::Impl::onTlsRxData(UNUSED std::vector<uint8_t>&& buf) -{ - JAMI_ERR() << "[TLS-TURN] rx " << buf.size() << " (but not implemented)"; -} - -void -TlsTurnEndpoint::Impl::onTlsCertificatesUpdate(UNUSED const gnutls_datum_t* local_raw, - UNUSED const gnutls_datum_t* remote_raw, - UNUSED unsigned int remote_count) -{} - -TlsTurnEndpoint::TlsTurnEndpoint(std::unique_ptr<ConnectedTurnTransport>&& turn_ep, - const Identity& local_identity, - const std::shared_future<tls::DhParams>& dh_params, - std::function<bool(const dht::crypto::Certificate&)>&& cert_check) - : pimpl_ { - std::make_unique<Impl>(std::move(turn_ep), std::move(cert_check), local_identity, dh_params)} -{} - -TlsTurnEndpoint::~TlsTurnEndpoint() = default; - -void -TlsTurnEndpoint::shutdown() -{ - pimpl_->tls->shutdown(); -} - -bool -TlsTurnEndpoint::isInitiator() const -{ - return pimpl_->tls->isInitiator(); -} - -void -TlsTurnEndpoint::waitForReady(const std::chrono::steady_clock::duration& timeout) -{ - pimpl_->tls->waitForReady(timeout); -} - -int -TlsTurnEndpoint::maxPayload() const -{ - return pimpl_->tls->maxPayload(); -} - -std::size_t -TlsTurnEndpoint::read(ValueType* buf, std::size_t len, std::error_code& ec) -{ - return pimpl_->tls->read(buf, len, ec); -} - -std::size_t -TlsTurnEndpoint::write(const ValueType* buf, std::size_t len, std::error_code& ec) -{ - return pimpl_->tls->write(buf, len, ec); -} - -const dht::crypto::Certificate& -TlsTurnEndpoint::peerCertificate() const -{ - return pimpl_->peerCertificate; -} - -int -TlsTurnEndpoint::waitForData(std::chrono::milliseconds timeout, std::error_code& ec) const -{ - return pimpl_->tls->waitForData(timeout, ec); -} - -void -TlsTurnEndpoint::setOnStateChange(std::function<bool(tls::TlsSessionState state)>&& cb) -{ - std::lock_guard<std::mutex> lk(pimpl_->cbMtx_); - pimpl_->onStateChangeCb_ = std::move(cb); -} - -//============================================================================== - -TcpSocketEndpoint::TcpSocketEndpoint(const IpAddr& addr) - : addr_ {addr} - , sock_ {static_cast<int>(::socket(addr.getFamily(), SOCK_STREAM, 0))} -{ - if (sock_ < 0) - std::system_error(errno, std::generic_category()); - auto bound = ip_utils::getAnyHostAddr(addr.getFamily()); - if (::bind(sock_, bound, bound.getLength()) < 0) - std::system_error(errno, std::generic_category()); -} - -TcpSocketEndpoint::~TcpSocketEndpoint() -{ -#ifndef _MSC_VER - ::close(sock_); -#else - ::closesocket(sock_); -#endif -} - -void -TcpSocketEndpoint::connect(const std::chrono::milliseconds& timeout) -{ - int ms = timeout.count(); - setsockopt(sock_, SOL_SOCKET, SO_RCVTIMEO, (const char*) &ms, sizeof(ms)); - setsockopt(sock_, SOL_SOCKET, SO_SNDTIMEO, (const char*) &ms, sizeof(ms)); - - if ((::connect(sock_, addr_, addr_.getLength())) < 0) - throw std::system_error(errno, std::generic_category()); -} - -int -TcpSocketEndpoint::waitForData(std::chrono::milliseconds timeout, std::error_code& ec) const -{ - for (;;) { - struct timeval tv; - tv.tv_sec = timeout.count() / 1000; - tv.tv_usec = (timeout.count() % 1000) * 1000; - - fd_set read_fds; - FD_ZERO(&read_fds); - FD_SET(sock_, &read_fds); - - auto res = ::select(sock_ + 1, &read_fds, nullptr, nullptr, &tv); - if (res < 0) - break; - if (res == 0) - return 0; // timeout - if (FD_ISSET(sock_, &read_fds)) - return 1; - } - - ec.assign(errno, std::generic_category()); - return -1; -} - -std::size_t -TcpSocketEndpoint::read(ValueType* buf, std::size_t len, std::error_code& ec) -{ - // NOTE: recv buf args is a void* on POSIX compliant system, but it's a char* on mingw - auto res = ::recv(sock_, reinterpret_cast<char*>(buf), len, 0); - if (res < 0) - ec.assign(errno, std::generic_category()); - else - ec.clear(); - return (res >= 0) ? res : 0; -} - -std::size_t -TcpSocketEndpoint::write(const ValueType* buf, std::size_t len, std::error_code& ec) -{ - // NOTE: recv buf args is a void* on POSIX compliant system, but it's a char* on mingw - auto res = ::send(sock_, reinterpret_cast<const char*>(buf), len, 0); - if (res < 0) - ec.assign(errno, std::generic_category()); - else - ec.clear(); - return (res >= 0) ? res : 0; -} - -//============================================================================== - IceSocketEndpoint::IceSocketEndpoint(std::shared_ptr<IceTransport> ice, bool isSender) : ice_(std::move(ice)) , iceIsSender(isSender) @@ -405,14 +164,12 @@ class TlsSocketEndpoint::Impl public: static constexpr auto TLS_TIMEOUT = std::chrono::seconds(20); - Impl(std::unique_ptr<AbstractSocketEndpoint>&& ep, + Impl(std::unique_ptr<IceSocketEndpoint>&& ep, const dht::crypto::Certificate& peer_cert, const Identity& local_identity, - const std::shared_future<tls::DhParams>& dh_params, - bool isIceTransport = true) + const std::shared_future<tls::DhParams>& dh_params) : peerCertificate {peer_cert} , ep_ {ep.get()} - , isIce_ {isIceTransport} { tls::TlsSession::TlsSessionCallbacks tls_cbs = {/*.onStateChange = */ [this](tls::TlsSessionState state) { onTlsStateChange(state); }, @@ -436,22 +193,16 @@ public: }; tls = std::make_unique<tls::TlsSession>(std::move(ep), tls_param, tls_cbs); - if (isIce_) { - if (const auto* iceSocket = reinterpret_cast<const IceSocketEndpoint*>(ep_)) { - iceSocket->underlyingICE()->setOnShutdown([this]() { tls->shutdown(); }); - } - } + ep_->underlyingICE()->setOnShutdown([this]() { tls->shutdown(); }); } - Impl(std::unique_ptr<AbstractSocketEndpoint>&& ep, + Impl(std::unique_ptr<IceSocketEndpoint>&& ep, std::function<bool(const dht::crypto::Certificate&)>&& cert_check, const Identity& local_identity, - const std::shared_future<tls::DhParams>& dh_params, - bool isIce = true) + const std::shared_future<tls::DhParams>& dh_params) : peerCertificateCheckFunc {std::move(cert_check)} , peerCertificate {null_cert} , ep_ {ep.get()} - , isIce_ {isIce} { tls::TlsSession::TlsSessionCallbacks tls_cbs = {/*.onStateChange = */ [this](tls::TlsSessionState state) { onTlsStateChange(state); }, @@ -475,14 +226,10 @@ public: }; tls = std::make_unique<tls::TlsSession>(std::move(ep), tls_param, tls_cbs); - if (isIce_) { - if (const auto* iceSocket = reinterpret_cast<const IceSocketEndpoint*>(ep_)) { - iceSocket->underlyingICE()->setOnShutdown([this]() { - if (tls) - tls->shutdown(); - }); - } - } + ep_->underlyingICE()->setOnShutdown([this]() { + if (tls) + tls->shutdown(); + }); } ~Impl() @@ -509,8 +256,7 @@ public: std::atomic_bool isReady_ {false}; OnReadyCb onReadyCb_; std::unique_ptr<tls::TlsSession> tls; - const AbstractSocketEndpoint* ep_; - bool isIce_ {true}; + const IceSocketEndpoint* ep_; }; // Declaration at namespace scope is necessary (until C++17) @@ -564,25 +310,20 @@ TlsSocketEndpoint::Impl::onTlsCertificatesUpdate(UNUSED const gnutls_datum_t* lo UNUSED unsigned int remote_count) {} -TlsSocketEndpoint::TlsSocketEndpoint(std::unique_ptr<AbstractSocketEndpoint>&& tr, +TlsSocketEndpoint::TlsSocketEndpoint(std::unique_ptr<IceSocketEndpoint>&& tr, const Identity& local_identity, const std::shared_future<tls::DhParams>& dh_params, - const dht::crypto::Certificate& peer_cert, - bool isIce) - : pimpl_ {std::make_unique<Impl>(std::move(tr), peer_cert, local_identity, dh_params, isIce)} + const dht::crypto::Certificate& peer_cert) + : pimpl_ {std::make_unique<Impl>(std::move(tr), peer_cert, local_identity, dh_params)} {} TlsSocketEndpoint::TlsSocketEndpoint( - std::unique_ptr<AbstractSocketEndpoint>&& tr, + std::unique_ptr<IceSocketEndpoint>&& tr, const Identity& local_identity, const std::shared_future<tls::DhParams>& dh_params, - std::function<bool(const dht::crypto::Certificate&)>&& cert_check, - bool isIce) - : pimpl_ {std::make_unique<Impl>(std::move(tr), - std::move(cert_check), - local_identity, - dh_params, - isIce)} + std::function<bool(const dht::crypto::Certificate&)>&& cert_check) + : pimpl_ { + std::make_unique<Impl>(std::move(tr), std::move(cert_check), local_identity, dh_params)} {} TlsSocketEndpoint::~TlsSocketEndpoint() {} @@ -661,7 +402,7 @@ TlsSocketEndpoint::setOnReady(std::function<void(bool ok)>&& cb) void TlsSocketEndpoint::shutdown() { - if (pimpl_->ep_ && pimpl_->isIce_) { + if (pimpl_->ep_) { const auto* iceSocket = reinterpret_cast<const IceSocketEndpoint*>(pimpl_->ep_); if (iceSocket && iceSocket->underlyingICE()) iceSocket->underlyingICE()->cancelOperations(); @@ -672,7 +413,7 @@ TlsSocketEndpoint::shutdown() std::shared_ptr<IceTransport> TlsSocketEndpoint::underlyingICE() const { - if (pimpl_->ep_ && pimpl_->isIce_) + if (pimpl_->ep_) if (const auto* iceSocket = reinterpret_cast<const IceSocketEndpoint*>(pimpl_->ep_)) return iceSocket->underlyingICE(); return {}; diff --git a/src/peer_connection.h b/src/peer_connection.h index e3c36f8f3455163251299ee139ea77f5c300bd0c..eaec7be13e9764523872aaecb8bf6e093a813fe2 100644 --- a/src/peer_connection.h +++ b/src/peer_connection.h @@ -68,10 +68,7 @@ public: (void) buffer; return false; } - virtual bool write(std::string_view) - { - return false; - }; + virtual bool write(std::string_view) { return false; }; virtual void setOnRecv(std::function<void(std::string_view)>&&) { // Not implemented @@ -82,82 +79,7 @@ public: //============================================================================== -/// Implement a server TLS session IO over a client TURN connection -class TlsTurnEndpoint : public GenericSocket<uint8_t> -{ -public: - using SocketType = GenericSocket<uint8_t>; - using Identity = std::pair<std::shared_ptr<dht::crypto::PrivateKey>, - std::shared_ptr<dht::crypto::Certificate>>; - - TlsTurnEndpoint(std::unique_ptr<ConnectedTurnTransport>&& turn, - const Identity& local_identity, - const std::shared_future<tls::DhParams>& dh_params, - std::function<bool(const dht::crypto::Certificate&)>&& cert_check); - ~TlsTurnEndpoint(); - - void shutdown() override; - bool isReliable() const override { return true; } - bool isInitiator() const override; - int maxPayload() const override; - std::size_t read(ValueType* buf, std::size_t len, std::error_code& ec) override; - std::size_t write(const ValueType* buf, std::size_t len, std::error_code& ec) override; - - void setOnRecv(RecvCb&&) override - { - throw std::logic_error("TlsTurnEndpoint::setOnRecv not implemented"); - } - int waitForData(std::chrono::milliseconds, std::error_code&) const override; - void waitForReady(const std::chrono::steady_clock::duration& timeout = {}); - - const dht::crypto::Certificate& peerCertificate() const; - void setOnStateChange(OnStateChangeCb&& cb); - -private: - class Impl; - std::unique_ptr<Impl> pimpl_; -}; - -//============================================================================== - -class AbstractSocketEndpoint : public GenericSocket<uint8_t> -{ -public: - virtual void connect(const std::chrono::milliseconds& = {}) {}; - - void setOnRecv(RecvCb&&) override - { - throw std::logic_error("AbstractSocketEndpoint::setOnRecv not implemented"); - } - - virtual void setOnShutdown(onShutdownCb&&) {}; -}; - -/// Implement system socket IO -class TcpSocketEndpoint : public AbstractSocketEndpoint -{ -public: - using SocketType = GenericSocket<uint8_t>; - explicit TcpSocketEndpoint(const IpAddr& addr); - ~TcpSocketEndpoint(); - - bool isReliable() const override { return true; } - bool isInitiator() const override { return true; } - int maxPayload() const override { return 1280; } - int waitForData(std::chrono::milliseconds timeout, std::error_code& ec) const override; - std::size_t read(ValueType* buf, std::size_t len, std::error_code& ec) override; - std::size_t write(const ValueType* buf, std::size_t len, std::error_code& ec) override; - void connect(const std::chrono::milliseconds& timeout = {}) override; - - void setOnShutdown(onShutdownCb&& cb) override { scb = cb; } - -private: - onShutdownCb scb; - const IpAddr addr_; - int sock_ {-1}; -}; - -class IceSocketEndpoint : public AbstractSocketEndpoint +class IceSocketEndpoint : public GenericSocket<uint8_t> { public: using SocketType = GenericSocket<uint8_t>; @@ -183,7 +105,7 @@ public: ice_->setOnRecv(compId_, cb); } - void setOnShutdown(onShutdownCb&& cb) override { ice_->setOnShutdown(std::move(cb)); } + void setOnShutdown(onShutdownCb&& cb) { ice_->setOnShutdown(std::move(cb)); } private: std::shared_ptr<IceTransport> ice_ {nullptr}; @@ -202,16 +124,14 @@ public: using Identity = std::pair<std::shared_ptr<dht::crypto::PrivateKey>, std::shared_ptr<dht::crypto::Certificate>>; - TlsSocketEndpoint(std::unique_ptr<AbstractSocketEndpoint>&& tr, + TlsSocketEndpoint(std::unique_ptr<IceSocketEndpoint>&& tr, const Identity& local_identity, const std::shared_future<tls::DhParams>& dh_params, - const dht::crypto::Certificate& peer_cert, - bool isIceTransport = true); - TlsSocketEndpoint(std::unique_ptr<AbstractSocketEndpoint>&& tr, + const dht::crypto::Certificate& peer_cert); + TlsSocketEndpoint(std::unique_ptr<IceSocketEndpoint>&& tr, const Identity& local_identity, const std::shared_future<tls::DhParams>& dh_params, - std::function<bool(const dht::crypto::Certificate&)>&& cert_check, - bool isIceTransport = true); + std::function<bool(const dht::crypto::Certificate&)>&& cert_check); ~TlsSocketEndpoint(); bool isReliable() const override { return true; } diff --git a/src/turn_transport.cpp b/src/turn_transport.cpp deleted file mode 100644 index f0e5cf9bf71d515c13a4201d761fed99e9320c5f..0000000000000000000000000000000000000000 --- a/src/turn_transport.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright (C) 2004-2020 Savoir-faire Linux Inc. - * - * Author: Guillaume Roguez <guillaume.roguez@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. - */ - -#include "turn_transport.h" -#include "transport/peer_channel.h" - -#include "logger.h" -#include "ip_utils.h" -#include "sip/sip_utils.h" -#include "map_utils.h" - -#include <pjnath.h> -#include <pjlib-util.h> -#include <pjlib.h> - -#include <future> -#include <atomic> -#include <thread> -#include <vector> -#include <iterator> -#include <mutex> -#include <sstream> -#include <limits> -#include <map> -#include <condition_variable> - -namespace jami { - -using MutexGuard = std::lock_guard<std::mutex>; -using MutexLock = std::unique_lock<std::mutex>; - -inline namespace { - -enum class RelayState { - NONE, - READY, - DOWN, -}; - -} - -//============================================================================== - -template<class Callable, class... Args> -inline void -PjsipCall(Callable& func, Args... args) -{ - auto status = func(args...); - if (status != PJ_SUCCESS) - throw sip_utils::PjsipFailure(status); -} - -template<class Callable, class... Args> -inline auto -PjsipCallReturn(const Callable& func, Args... args) -> decltype(func(args...)) -{ - auto res = func(args...); - if (!res) - throw sip_utils::PjsipFailure(); - return res; -} - -//============================================================================== - -class TurnTransportPimpl -{ -public: - TurnTransportPimpl() = default; - ~TurnTransportPimpl(); - - void onTurnState(pj_turn_state_t old_state, pj_turn_state_t new_state); - void onRxData(const uint8_t* pkt, - unsigned pkt_len, - const pj_sockaddr_t* peer_addr, - unsigned addr_len); - void onPeerConnection(pj_uint32_t conn_id, - const pj_sockaddr_t* peer_addr, - unsigned addr_len, - pj_status_t status); - void ioJob(); - - std::mutex apiMutex_; - - std::map<IpAddr, PeerChannel> peerChannels_; - - TurnTransportParams settings; - pj_caching_pool poolCache {}; - pj_pool_t* pool {nullptr}; - pj_stun_config stunConfig {}; - pj_turn_sock* relay {nullptr}; - pj_str_t relayAddr {}; - IpAddr peerRelayAddr; // address where peers should connect to - IpAddr mappedAddr; - - std::atomic<RelayState> state {RelayState::NONE}; - std::atomic_bool ioJobQuit {false}; - std::thread ioWorker; -}; - -TurnTransportPimpl::~TurnTransportPimpl() -{ - if (relay && state.load() != RelayState::DOWN) { - try { - pj_turn_sock_destroy(relay); - } catch (...) { - JAMI_ERR() << "exception during pj_turn_sock_destroy() call (ignored)"; - } - } - ioJobQuit = true; - if (ioWorker.joinable()) - ioWorker.join(); - if (stunConfig.ioqueue) - pj_ioqueue_destroy(stunConfig.ioqueue); - if (stunConfig.timer_heap) - pj_timer_heap_destroy(stunConfig.timer_heap); - pj_caching_pool_destroy(&poolCache); -} - -void -TurnTransportPimpl::onTurnState(pj_turn_state_t old_state, pj_turn_state_t new_state) -{ - if (new_state == PJ_TURN_STATE_READY) { - pj_turn_session_info info; - pj_turn_sock_get_info(relay, &info); - peerRelayAddr = IpAddr {info.relay_addr}; - mappedAddr = IpAddr {info.mapped_addr}; - JAMI_DBG("TURN server ready, peer relay address: %s", - peerRelayAddr.toString(true, true).c_str()); - state = RelayState::READY; - } else if (old_state <= PJ_TURN_STATE_READY and new_state > PJ_TURN_STATE_READY) { - JAMI_WARN("TURN server disconnected (%s)", pj_turn_state_name(new_state)); - state = RelayState::DOWN; - MutexGuard lk {apiMutex_}; - peerChannels_.clear(); - } -} - -void -TurnTransportPimpl::onRxData(const uint8_t* pkt, - unsigned pkt_len, - const pj_sockaddr_t* addr, - unsigned addr_len) -{ - IpAddr peer_addr(*static_cast<const pj_sockaddr*>(addr), addr_len); - { - MutexGuard lk {apiMutex_}; - auto channel_it = peerChannels_.find(peer_addr); - if (channel_it == std::end(peerChannels_)) - return; - std::error_code ec; - auto ret = channel_it->second.write((const char*) pkt, pkt_len, ec); - if (ret < 0) { - JAMI_ERR("TURN rx: channel is closed"); - } - } -} - -void -TurnTransportPimpl::onPeerConnection(pj_uint32_t conn_id, - const pj_sockaddr_t* addr, - unsigned addr_len, - pj_status_t status) -{ - IpAddr peer_addr(*static_cast<const pj_sockaddr*>(addr), addr_len); - if (status == PJ_SUCCESS) { - JAMI_DBG() << "Received connection attempt from " << peer_addr.toString(true, true) - << ", id=" << std::hex << conn_id; - { - MutexGuard lk {apiMutex_}; - peerChannels_[peer_addr]; - } - } - - if (settings.onPeerConnection) - settings.onPeerConnection(conn_id, peer_addr, status == PJ_SUCCESS); -} - -void -TurnTransportPimpl::ioJob() -{ - sip_utils::register_thread(); - - while (!ioJobQuit.load()) { - const pj_time_val delay = {0, 10}; - pj_ioqueue_poll(stunConfig.ioqueue, &delay); - pj_timer_heap_poll(stunConfig.timer_heap, nullptr); - } -} - -//============================================================================== - -TurnTransport::TurnTransport(const TurnTransportParams& params) -{ - sip_utils::register_thread(); - - auto server = params.server; - if (!server.getPort()) - server.setPort(PJ_STUN_PORT); - - if (server.isUnspecified()) - throw std::invalid_argument("invalid turn server address"); - - pimpl_ = std::unique_ptr<TurnTransportPimpl>(new TurnTransportPimpl); - pimpl_->settings = params; - - // PJSIP memory pool - pj_caching_pool_init(&pimpl_->poolCache, &pj_pool_factory_default_policy, 0); - pimpl_->pool = PjsipCallReturn(pj_pool_create, - &pimpl_->poolCache.factory, - "RgTurnTr", - 512, - 512, - nullptr); - - // STUN config - pj_stun_config_init(&pimpl_->stunConfig, &pimpl_->poolCache.factory, 0, nullptr, nullptr); - - // create global timer heap - PjsipCall(pj_timer_heap_create, pimpl_->pool, 1000, &pimpl_->stunConfig.timer_heap); - - // create global ioqueue - PjsipCall(pj_ioqueue_create, pimpl_->pool, 16, &pimpl_->stunConfig.ioqueue); - - // run a thread to handles timer/ioqueue events - pimpl_->ioWorker = std::thread([this] { pimpl_->ioJob(); }); - - // TURN callbacks - pj_turn_sock_cb relay_cb; - pj_bzero(&relay_cb, sizeof(relay_cb)); - relay_cb.on_rx_data = [](pj_turn_sock* relay, - void* pkt, - unsigned pkt_len, - const pj_sockaddr_t* peer_addr, - unsigned addr_len) { - auto pimpl = static_cast<TurnTransportPimpl*>(pj_turn_sock_get_user_data(relay)); - pimpl->onRxData(reinterpret_cast<uint8_t*>(pkt), pkt_len, peer_addr, addr_len); - }; - relay_cb.on_state = - [](pj_turn_sock* relay, pj_turn_state_t old_state, pj_turn_state_t new_state) { - auto pimpl = static_cast<TurnTransportPimpl*>(pj_turn_sock_get_user_data(relay)); - pimpl->onTurnState(old_state, new_state); - }; - relay_cb.on_connection_status = [](pj_turn_sock* relay, - pj_status_t status, - pj_uint32_t conn_id, - const pj_sockaddr_t* peer_addr, - unsigned addr_len) { - auto pimpl = static_cast<TurnTransportPimpl*>(pj_turn_sock_get_user_data(relay)); - pimpl->onPeerConnection(conn_id, peer_addr, addr_len, status); - }; - - // TURN socket config - pj_turn_sock_cfg turn_sock_cfg; - pj_turn_sock_cfg_default(&turn_sock_cfg); - turn_sock_cfg.max_pkt_size = params.maxPacketSize; - - // TURN socket creation - PjsipCall(pj_turn_sock_create, - &pimpl_->stunConfig, - server.getFamily(), - PJ_TURN_TP_TCP, - &relay_cb, - &turn_sock_cfg, - &*this->pimpl_, - &pimpl_->relay); - - // TURN allocation setup - pj_turn_alloc_param turn_alloc_param; - pj_turn_alloc_param_default(&turn_alloc_param); - if (params.authorized_family != 0) - turn_alloc_param.af = params.authorized_family; // RFC 6156!!! - - if (params.isPeerConnection) - turn_alloc_param.peer_conn_type = PJ_TURN_TP_TCP; // RFC 6062!!! - - pj_stun_auth_cred cred; - pj_bzero(&cred, sizeof(cred)); - cred.type = PJ_STUN_AUTH_CRED_STATIC; - pj_strset(&cred.data.static_cred.realm, - (char*) pimpl_->settings.realm.c_str(), - pimpl_->settings.realm.size()); - pj_strset(&cred.data.static_cred.username, - (char*) pimpl_->settings.username.c_str(), - pimpl_->settings.username.size()); - cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; - pj_strset(&cred.data.static_cred.data, - (char*) pimpl_->settings.password.c_str(), - pimpl_->settings.password.size()); - - pimpl_->relayAddr = pj_strdup3(pimpl_->pool, server.toString().c_str()); - - // TURN connection/allocation - JAMI_DBG() << "Connecting to TURN " << server.toString(true, true); - try { - PjsipCall(pj_turn_sock_alloc, - pimpl_->relay, - &pimpl_->relayAddr, - server.getPort(), - nullptr, - &cred, - &turn_alloc_param); - } catch (const sip_utils::PjsipFailure& e) { - JAMI_ERR("pj_turn_sock_alloc failed: %s", e.what()); - } -} - -TurnTransport::~TurnTransport() = default; - -void -TurnTransport::shutdown(const IpAddr& addr) -{ - MutexLock lk {pimpl_->apiMutex_}; - auto& channel = pimpl_->peerChannels_.at(addr); - channel.stop(); -} - -bool -TurnTransport::isInitiator() const -{ - return !pimpl_->settings.server; -} - -void -TurnTransport::permitPeer(const IpAddr& addr) -{ - if (addr.isUnspecified()) - throw std::invalid_argument("invalid peer address"); - - if (addr.getFamily() != pimpl_->peerRelayAddr.getFamily()) - throw std::invalid_argument("mismatching peer address family"); - - sip_utils::register_thread(); - PjsipCall(pj_turn_sock_set_perm, pimpl_->relay, 1, addr.pjPtr(), 1); -} - -bool -TurnTransport::isReady() const -{ - return pimpl_->state.load() == RelayState::READY; -} - -void -TurnTransport::waitServerReady() -{ - while (pimpl_->state.load() != RelayState::READY) { - std::this_thread::sleep_for(std::chrono::milliseconds(250)); - } -} - -const IpAddr& -TurnTransport::peerRelayAddr() const -{ - return pimpl_->peerRelayAddr; -} - -const IpAddr& -TurnTransport::mappedAddr() const -{ - return pimpl_->mappedAddr; -} - -bool -TurnTransport::sendto(const IpAddr& peer, const char* const buffer, std::size_t length) -{ - sip_utils::register_thread(); - auto status = pj_turn_sock_sendto(pimpl_->relay, - reinterpret_cast<const pj_uint8_t*>(buffer), - length, - peer.pjPtr(), - peer.getLength()); - if (status != PJ_SUCCESS && status != PJ_EPENDING && status != PJ_EBUSY) - throw sip_utils::PjsipFailure(PJ_STATUS_TO_OS(status)); - - return status != PJ_EBUSY; -} - -bool -TurnTransport::sendto(const IpAddr& peer, const std::vector<char>& buffer) -{ - return sendto(peer, &buffer[0], buffer.size()); -} - -ssize_t -TurnTransport::recvfrom(const IpAddr& peer, char* buffer, std::size_t size, std::error_code& ec) -{ - MutexLock lk {pimpl_->apiMutex_}; - auto& channel = pimpl_->peerChannels_.at(peer); - lk.unlock(); - return channel.read(buffer, size, ec); -} - -std::vector<IpAddr> -TurnTransport::peerAddresses() const -{ - MutexLock lk {pimpl_->apiMutex_}; - return map_utils::extractKeys(pimpl_->peerChannels_); -} - -int -TurnTransport::waitForData(const IpAddr& peer, - std::chrono::milliseconds timeout, - std::error_code& ec) const -{ - (void) ec; ///< \todo handle errors - MutexLock lk {pimpl_->apiMutex_}; - auto& channel = pimpl_->peerChannels_.at(peer); - lk.unlock(); - return channel.wait(timeout, ec); -} - -//============================================================================== - -ConnectedTurnTransport::ConnectedTurnTransport(TurnTransport& turn, const IpAddr& peer) - : turn_ {turn} - , peer_ {peer} -{} - -void -ConnectedTurnTransport::shutdown() -{ - turn_.shutdown(peer_); -} - -int -ConnectedTurnTransport::waitForData(std::chrono::milliseconds timeout, std::error_code& ec) const -{ - return turn_.waitForData(peer_, timeout, ec); -} - -std::size_t -ConnectedTurnTransport::write(const ValueType* buf, std::size_t size, std::error_code& ec) -{ - try { - auto success = turn_.sendto(peer_, reinterpret_cast<const char*>(buf), size); - if (!success) { - // if !success, pj_turn_sock_sendto returned EBUSY - // So, we should retry to send this later - ec.assign(EAGAIN, std::generic_category()); - return 0; - } - } catch (const sip_utils::PjsipFailure& ex) { - ec = ex.code(); - return 0; - } - - ec.clear(); - return size; -} - -std::size_t -ConnectedTurnTransport::read(ValueType* buf, std::size_t size, std::error_code& ec) -{ - if (size > 0) { - return turn_.recvfrom(peer_, reinterpret_cast<char*>(buf), size, ec); - } - - ec.clear(); - return size; -} - -} // namespace jami diff --git a/src/turn_transport.h b/src/turn_transport.h deleted file mode 100644 index 4ae67d20fc99d841c3a94973b39f08200b2975a0..0000000000000000000000000000000000000000 --- a/src/turn_transport.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2004-2020 Savoir-faire Linux Inc. - * - * Author: Guillaume Roguez <guillaume.roguez@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 "generic_io.h" - -#include <string> -#include <memory> -#include <functional> -#include <map> -#include <stdexcept> - -namespace jami { - -class TurnTransportPimpl; - -struct TurnTransportParams -{ - IpAddr server; - - // Plain Credentials - std::string realm; - std::string username; - std::string password; - - pj_uint16_t authorized_family {0}; - - bool isPeerConnection {false}; - uint32_t connectionId {0}; - std::function<void(uint32_t conn_id, const IpAddr& peer_addr, bool success)> onPeerConnection; - - std::size_t maxPacketSize {4096}; ///< size of one "logical" packet -}; - -class TurnTransport -{ -public: - /// Constructs a TurnTransport connected by TCP to given server. - /// - /// Throw std::invalid_argument of peer address is invalid. - /// - /// \param param parameters to setup the transport - /// - /// \note If TURN server port is not set, the default TURN port 3478 (RFC5766) is used. - /// - TurnTransport(const TurnTransportParams& param); - - ~TurnTransport(); - - void shutdown(const IpAddr& addr); - - bool isInitiator() const; - - /// Wait for successful connection on the TURN server. - /// - /// TurnTransport constructor connects asynchronously on the TURN server. - /// You need to wait the READY state before calling any other APIs. - /// - void waitServerReady(); - - /// \return true if the TURN server is connected and ready to accept peers. - bool isReady() const; - - /// \return socket address (IP/port) where peers should connect to before doing IO with this client. - const IpAddr& peerRelayAddr() const; - - /// \return public address of this client as seen by the TURN server. - const IpAddr& mappedAddr() const; - - /// \return a vector of connected peer addresses - std::vector<IpAddr> peerAddresses() const; - - /// Gives server access permission to given peer by its address. - /// - /// Throw std::invalid_argument of peer address is invalid. - /// Throw std::runtime_error if case of backend errors. - /// - /// \param addr peer address - /// - /// \note The peer address family must be same as the turn server. - /// \note Must be called only if server is ready. - /// \see waitServerReady - /// - void permitPeer(const IpAddr& addr); - - /// Collect pending data from a given peer. - /// - /// Data are read from given \a peer incoming buffer until EOF or \a data size() is reached. - /// If \a peer is not connected this function raise an exception. - /// If \a peer exists but no data are available this method blocks until TURN deconnection - /// or at first incoming character. - /// - /// \param [in] peer target peer address where data are read - /// \param [in,out] pre-dimensionned character vector to write incoming data - /// \exception std::out_of_range \a peer is not connected yet - /// - /// Works as recvfrom() vector version but accept a simple char array. - /// - ssize_t recvfrom(const IpAddr& peer, char* buffer, std::size_t size, std::error_code& ec); - - /// Send data to given peer through the TURN tunnel. - /// - /// This method blocks until all given characters in \a data are sent to the given \a peer. - /// If \a peer is not connected this function raise an exception. - /// - /// \param [in] peer target peer address where data are read - /// \param [in,out] pre-dimensionned character vector to write incoming data - /// \exception std::out_of_range \a peer is not connected yet - /// - bool sendto(const IpAddr& peer, const std::vector<char>& data); - - /// Works as sendto() vector version but accept a simple char array. - /// - bool sendto(const IpAddr& peer, const char* const buffer, std::size_t size); - - int waitForData(const IpAddr& peer, - std::chrono::milliseconds timeout, - std::error_code& ec) const; - -public: - // Move semantic only, not copiable - TurnTransport(TurnTransport&&) = default; - TurnTransport& operator=(TurnTransport&&) = default; - -private: - TurnTransport() = delete; - std::unique_ptr<TurnTransportPimpl> pimpl_; -}; - -class ConnectedTurnTransport final : public GenericSocket<uint8_t> -{ -public: - using SocketType = GenericSocket<uint8_t>; - - ConnectedTurnTransport(TurnTransport& turn, const IpAddr& peer); - - void shutdown() override; - bool isReliable() const override { return true; } - bool isInitiator() const override { return turn_.isInitiator(); } - int maxPayload() const override { return 3000; } - - int waitForData(std::chrono::milliseconds timeout, std::error_code& ec) const override; - std::size_t read(ValueType* buf, std::size_t length, std::error_code& ec) override; - std::size_t write(const ValueType* buf, std::size_t length, std::error_code& ec) override; - - void setOnRecv(RecvCb&&) override { throw std::logic_error("ConnectedTurnTransport bad call"); } - -private: - TurnTransport& turn_; - const IpAddr peer_; -}; - -} // namespace jami diff --git a/test/Makefile.am b/test/Makefile.am index aed31137f7da6fcbae587f941ed45434fb0e7c13..74b09f88ed74a4fcdacfd316b736fb0975b904b5 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,2 +1,2 @@ SUBDIRS = unitTest -SUBDIRS += sip turn +SUBDIRS += sip diff --git a/test/turn/Makefile.am b/test/turn/Makefile.am deleted file mode 100644 index 19fea982e6332daafabd3e43119397b41dbe53da..0000000000000000000000000000000000000000 --- a/test/turn/Makefile.am +++ /dev/null @@ -1,10 +0,0 @@ -# Rules for the test code (use `make check` to execute) -include $(top_srcdir)/globals.mk - -AM_CXXFLAGS = -I$(top_srcdir)/src -AM_LDFLAGS = $(CPPUNIT_LIBS) $(top_builddir)/src/libring.la - -check_PROGRAMS = ut_turn -ut_turn_SOURCES = main.cpp test_turn.h test_TURN.cpp - -TESTS = $(check_PROGRAMS) diff --git a/test/turn/main.cpp b/test/turn/main.cpp deleted file mode 100644 index df976f04b564937fbee387002f8a3f050f18cee6..0000000000000000000000000000000000000000 --- a/test/turn/main.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2004-2020 Savoir-faire Linux Inc. - * Author: Guillaume Roguez <guillaume.roguez@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. - */ - -#include <cppunit/ui/text/TestRunner.h> -#include <cppunit/extensions/TestFactoryRegistry.h> -#include <cppunit/CompilerOutputter.h> - -#include "dring.h" - -#include <stdexcept> - -void init_daemon() -{ - DRing::init(DRing::InitFlag(DRing::DRING_FLAG_DEBUG | DRing::DRING_FLAG_CONSOLE_LOG)); - DRing::start("dring-sample.yml"); -} - -int main() -{ - init_daemon(); - - CppUnit::TextUi::TestRunner runner; - - // Register all tests - auto& registry = CppUnit::TestFactoryRegistry::getRegistry(); - runner.addTest(registry.makeTest()); - - // Use a compiler error format outputter for results and output into stderr - runner.setOutputter(new CppUnit::CompilerOutputter(&runner.result(), std::cerr )); - - bool ret; - - try { - // Run tests - ret = !runner.run("", false); - } catch (const std::exception& e) { - std::cerr << "Exception catched during tests: " << e.what() << '\n'; - ret = 1; - } - - DRing::fini(); - - return ret; -} diff --git a/test/turn/test_TURN.cpp b/test/turn/test_TURN.cpp deleted file mode 100644 index ebd41d6f7836c6f1e93fef7f199eb2b80a3915a5..0000000000000000000000000000000000000000 --- a/test/turn/test_TURN.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2004-2020 Savoir-faire Linux Inc. - * Author: Guillaume Roguez <guillaume.roguez@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. - */ - -#include "test_TURN.h" -#include "turn_transport.h" - -#include <chrono> -#include <opendht/sockaddr.h> -#include <stdexcept> -#include <sys/socket.h> -#include <sys/unistd.h> -#include <thread> -#include <vector> - -using namespace jami; - -CPPUNIT_TEST_SUITE_REGISTRATION( test_TURN ); - -class TCPSocket { -public: - TCPSocket(int fa) { - sock_ = ::socket(fa, SOCK_STREAM, 0); - if (sock_ < 0) - throw std::system_error(errno, std::system_category()); - IpAddr bound {"0.0.0.0"}; - ::bind(sock_, bound, bound.getLength()); - } - - ~TCPSocket() { - if (sock_ >= 0) - ::close(sock_); - } - - void connect(const IpAddr& addr) { - if (::connect(sock_, addr, addr.getLength()) < 0) - throw std::system_error(errno, std::system_category()); - } - - void send(const std::string& pkt) { - if (::send(sock_, pkt.data(), pkt.size(), 0) < 0) - throw std::system_error(errno, std::system_category()); - } - - void send(const std::vector<char>& pkt) { - if (::send(sock_, pkt.data(), pkt.size(), 0) < 0) - throw std::system_error(errno, std::system_category()); - } - - std::vector<char> recv(std::size_t max_len) { - std::vector<char> pkt(max_len); - auto rs = ::recv(sock_, pkt.data(), pkt.size(), 0); - if (rs < 0) - throw std::system_error(errno, std::system_category()); - pkt.resize(rs); - pkt.shrink_to_fit(); - return pkt; - } - - IpAddr address() const { - struct sockaddr addr; - socklen_t addrlen; - if (::getsockname(sock_, &addr, &addrlen) < 0) - throw std::system_error(errno, std::system_category()); - return IpAddr {addr}; - } - -private: - int sock_ {-1}; -}; - -void -test_TURN::testSimpleConnection() -{ - TurnTransportParams param; - param.server = IpAddr {"turn.jami.net"}; - param.realm = "ring"; - param.username = "ring"; - param.password = "ring"; - param.isPeerConnection = true; - - TurnTransport turn {param}; - turn.waitServerReady(); - - TCPSocket sock = {param.server.getFamily()}; - - // Permit myself - auto mapped = static_cast<dht::SockAddr>(turn.mappedAddr()); - turn.permitPeer(IpAddr { mapped.getMappedIPv4().toString() }); - std::this_thread::sleep_for(std::chrono::seconds(2)); - - sock.connect(turn.peerRelayAddr()); - - std::this_thread::sleep_for(std::chrono::seconds(1)); - auto peers = turn.peerAddresses(); - CPPUNIT_ASSERT(peers.size() == 1); - auto remotePeer = peers[0]; - - // Peer send data - std::string test_data = "Hello, World!"; - sock.send(test_data); - - // Client read - std::vector<char> data(1000); - turn.recvfrom(remotePeer, data); - CPPUNIT_ASSERT(std::string(std::begin(data), std::end(data)) == test_data); - - turn.sendto(remotePeer, std::vector<char>{1, 2, 3, 4}); - - auto res = sock.recv(1000); - CPPUNIT_ASSERT(res.size() == 4); - -#if 0 - // DISABLED SECTION - // This code higly load the network and can be long to execute. - // Only kept for manual testing purpose. - std::vector<char> big(100000); - std::size_t count = 1000; - using clock = std::chrono::high_resolution_clock; - - auto t1 = clock::now(); - auto i = count; - while (i--) - sock.send(big); - auto t2 = clock::now(); - - auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(t2-t1).count(); - std::cout << "T= " << duration << "ns" - << ", V= " << (8000. * count * big.size() / duration) << "Mb/s" - << " / " << (1000. * count * big.size() / duration) << "MB/s" - << '\n'; - std::this_thread::sleep_for(std::chrono::seconds(5)); -#endif -} diff --git a/test/turn/test_TURN.h b/test/turn/test_TURN.h deleted file mode 100644 index b70fb6a85b5100625f8cb073a3e8caa56f10f0a7..0000000000000000000000000000000000000000 --- a/test/turn/test_TURN.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2004-2020 Savoir-faire Linux Inc. - * Author: Guillaume Roguez <guillaume.roguez@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 - -// Cppunit import -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/TestCaller.h> -#include <cppunit/TestCase.h> -#include <cppunit/TestSuite.h> - - -/* - * @file test_TURN.h - * @brief Regroups unitary tests related to the TURN transport class - */ - -class test_TURN : public CppUnit::TestFixture -{ -private: - void testSimpleConnection(void); - - /** - * Use cppunit library macros to add unit test to the factory - */ - CPPUNIT_TEST_SUITE(test_TURN); - CPPUNIT_TEST(testSimpleConnection); - CPPUNIT_TEST_SUITE_END(); -};