LCOV - code coverage report
Current view: top level - src/sip - siptransport.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 137 210 65.2 %
Date: 2024-04-26 09:41:19 Functions: 22 29 75.9 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
       5             :  *  Author: Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com>
       6             :  *
       7             :  *  This program is free software; you can redistribute it and/or modify
       8             :  *  it under the terms of the GNU General Public License as published by
       9             :  *  the Free Software Foundation; either version 3 of the License, or
      10             :  *  (at your option) any later version.
      11             :  *
      12             :  *  This program is distributed in the hope that it will be useful,
      13             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  *  GNU General Public License for more details.
      16             :  *
      17             :  *  You should have received a copy of the GNU General Public License
      18             :  *  along with this program; if not, write to the Free Software
      19             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      20             :  */
      21             : 
      22             : #include "sip/siptransport.h"
      23             : #include "connectivity/sip_utils.h"
      24             : 
      25             : #include "jamidht/abstract_sip_transport.h"
      26             : #include "jamidht/channeled_transport.h"
      27             : 
      28             : #include "compiler_intrinsics.h"
      29             : #include "sip/sipvoiplink.h"
      30             : 
      31             : #include <pjsip.h>
      32             : #include <pjsip/sip_types.h>
      33             : #include <pjsip/sip_transport_tls.h>
      34             : #include <pj/ssl_sock.h>
      35             : #include <pjnath.h>
      36             : #include <pjnath/stun_config.h>
      37             : #include <pjlib.h>
      38             : #include <pjlib-util.h>
      39             : 
      40             : #include <dhtnet/multiplexed_socket.h>
      41             : #include <dhtnet/ip_utils.h>
      42             : #include <dhtnet/tls_session.h>
      43             : 
      44             : #include <opendht/crypto.h>
      45             : 
      46             : #include <stdexcept>
      47             : #include <sstream>
      48             : #include <algorithm>
      49             : 
      50             : #define RETURN_IF_FAIL(A, VAL, ...) \
      51             :     if (!(A)) { \
      52             :         JAMI_ERR(__VA_ARGS__); \
      53             :         return (VAL); \
      54             :     }
      55             : 
      56             : namespace jami {
      57             : 
      58             : constexpr const char* TRANSPORT_STATE_STR[] = {"CONNECTED",
      59             :                                                "DISCONNECTED",
      60             :                                                "SHUTDOWN",
      61             :                                                "DESTROY",
      62             :                                                "UNKNOWN STATE"};
      63             : constexpr const size_t TRANSPORT_STATE_SZ = std::size(TRANSPORT_STATE_STR);
      64             : 
      65             : void
      66        1221 : SipTransport::deleteTransport(pjsip_transport* t)
      67             : {
      68        1221 :     pjsip_transport_dec_ref(t);
      69        1221 : }
      70             : 
      71        1221 : SipTransport::SipTransport(pjsip_transport* t)
      72        1221 :     : transport_(nullptr, deleteTransport)
      73             : {
      74        1220 :     if (not t or pjsip_transport_add_ref(t) != PJ_SUCCESS)
      75           0 :         throw std::runtime_error("invalid transport");
      76             : 
      77             :     // Set pointer here, right after the successful pjsip_transport_add_ref
      78        1220 :     transport_.reset(t);
      79             : 
      80        3663 :     JAMI_DEBUG("SipTransport@{} tr={} rc={:d}",
      81             :                  fmt::ptr(this),
      82             :                  fmt::ptr(transport_.get()),
      83             :                  pj_atomic_get(transport_->ref_cnt));
      84        1221 : }
      85             : 
      86           0 : SipTransport::SipTransport(pjsip_transport* t, const std::shared_ptr<TlsListener>& l)
      87           0 :     : SipTransport(t)
      88             : {
      89           0 :     tlsListener_ = l;
      90           0 : }
      91             : 
      92        1196 : SipTransport::SipTransport(pjsip_transport* t,
      93        1196 :                            const std::shared_ptr<dht::crypto::Certificate>& peerCertficate)
      94        1196 :     : SipTransport(t)
      95             : {
      96        1196 :     tlsInfos_.peerCert = peerCertficate;
      97        1196 : }
      98             : 
      99        1219 : SipTransport::~SipTransport()
     100             : {
     101        3661 :     JAMI_DEBUG("~SipTransport@{} tr={} rc={:d}",
     102             :                  fmt::ptr(this),
     103             :                  fmt::ptr(transport_.get()),
     104             :                  pj_atomic_get(transport_->ref_cnt));
     105        1221 : }
     106             : 
     107             : bool
     108          13 : SipTransport::isAlive(pjsip_transport_state state)
     109             : {
     110           2 :     return state != PJSIP_TP_STATE_DISCONNECTED && state != PJSIP_TP_STATE_SHUTDOWN
     111          15 :            && state != PJSIP_TP_STATE_DESTROY;
     112             : }
     113             : 
     114             : const char*
     115        2249 : SipTransport::stateToStr(pjsip_transport_state state)
     116             : {
     117        2249 :     return TRANSPORT_STATE_STR[std::min<size_t>(state, TRANSPORT_STATE_SZ - 1)];
     118             : }
     119             : 
     120             : void
     121         719 : SipTransport::stateCallback(pjsip_transport_state state, const pjsip_transport_state_info* info)
     122             : {
     123         719 :     connected_ = state == PJSIP_TP_STATE_CONNECTED;
     124             : 
     125         719 :     auto extInfo = static_cast<const pjsip_tls_state_info*>(info->ext_info);
     126         719 :     if (isSecure() && extInfo && extInfo->ssl_sock_info && extInfo->ssl_sock_info->established) {
     127           0 :         auto tlsInfo = extInfo->ssl_sock_info;
     128           0 :         tlsInfos_.proto = (pj_ssl_sock_proto) tlsInfo->proto;
     129           0 :         tlsInfos_.cipher = tlsInfo->cipher;
     130           0 :         tlsInfos_.verifyStatus = (pj_ssl_cert_verify_flag_t) tlsInfo->verify_status;
     131           0 :         if (!tlsInfos_.peerCert) {
     132           0 :             const auto& peers = tlsInfo->remote_cert_info->raw_chain;
     133           0 :             std::vector<std::pair<const uint8_t*, const uint8_t*>> bits;
     134           0 :             bits.resize(peers.cnt);
     135           0 :             std::transform(peers.cert_raw,
     136           0 :                            peers.cert_raw + peers.cnt,
     137             :                            std::begin(bits),
     138           0 :                            [](const pj_str_t& crt) {
     139           0 :                                return std::make_pair((uint8_t*) crt.ptr,
     140           0 :                                                      (uint8_t*) (crt.ptr + crt.slen));
     141             :                            });
     142           0 :             tlsInfos_.peerCert = std::make_shared<dht::crypto::Certificate>(bits);
     143           0 :         }
     144             :     } else {
     145         719 :         tlsInfos_ = {};
     146             :     }
     147             : 
     148         719 :     std::vector<SipTransportStateCallback> cbs;
     149             :     {
     150         719 :         std::lock_guard lock(stateListenersMutex_);
     151         719 :         cbs.reserve(stateListeners_.size());
     152         833 :         for (auto& l : stateListeners_)
     153         114 :             cbs.push_back(l.second);
     154         719 :     }
     155         833 :     for (auto& cb : cbs)
     156         114 :         cb(state, info);
     157         719 : }
     158             : 
     159             : void
     160         317 : SipTransport::addStateListener(uintptr_t lid, SipTransportStateCallback cb)
     161             : {
     162         317 :     std::lock_guard lock(stateListenersMutex_);
     163         317 :     auto pair = stateListeners_.insert(std::make_pair(lid, cb));
     164         317 :     if (not pair.second)
     165           0 :         pair.first->second = cb;
     166         317 : }
     167             : 
     168             : bool
     169         316 : SipTransport::removeStateListener(uintptr_t lid)
     170             : {
     171         316 :     std::lock_guard lock(stateListenersMutex_);
     172         316 :     auto it = stateListeners_.find(lid);
     173         316 :     if (it != stateListeners_.end()) {
     174          24 :         stateListeners_.erase(it);
     175          24 :         return true;
     176             :     }
     177         292 :     return false;
     178         316 : }
     179             : 
     180             : uint16_t
     181         334 : SipTransport::getTlsMtu()
     182             : {
     183         334 :     return 1232; /* Hardcoded yes (it's the IPv6 value).
     184             :                   * This method is broken by definition.
     185             :                   * A MTU should not be defined at this layer.
     186             :                   * And a correct value should come from the underlying transport itself,
     187             :                   * not from a constant...
     188             :                   */
     189             : }
     190             : 
     191          31 : SipTransportBroker::SipTransportBroker(pjsip_endpoint* endpt)
     192          31 :     : endpt_(endpt)
     193          31 : {}
     194             : 
     195          31 : SipTransportBroker::~SipTransportBroker()
     196             : {
     197          31 :     shutdown();
     198             : 
     199          31 :     udpTransports_.clear();
     200          31 :     transports_.clear();
     201             : 
     202          31 :     JAMI_DBG("destroying SipTransportBroker@%p", this);
     203          31 : }
     204             : 
     205             : void
     206        2249 : SipTransportBroker::transportStateChanged(pjsip_transport* tp,
     207             :                                           pjsip_transport_state state,
     208             :                                           const pjsip_transport_state_info* info)
     209             : {
     210        2249 :     JAMI_DBG("pjsip transport@%p %s -> %s", tp, tp->info, SipTransport::stateToStr(state));
     211             : 
     212             :     // First make sure that this transport is handled by us
     213             :     // and remove it from any mapping if destroy pending or done.
     214             : 
     215        2249 :     std::shared_ptr<SipTransport> sipTransport;
     216        2249 :     std::lock_guard lock(transportMapMutex_);
     217        2249 :     auto key = transports_.find(tp);
     218        2249 :     if (key == transports_.end())
     219           0 :         return;
     220             : 
     221        2249 :     sipTransport = key->second.lock();
     222             : 
     223        2249 :     if (!isDestroying_ && state == PJSIP_TP_STATE_DESTROY) {
     224             :         // maps cleanup
     225        1051 :         JAMI_DBG("unmap pjsip transport@%p {SipTransport@%p}", tp, sipTransport.get());
     226        1051 :         transports_.erase(key);
     227             : 
     228             :         // If UDP
     229        1051 :         const auto type = tp->key.type;
     230        1051 :         if (type == PJSIP_TRANSPORT_UDP or type == PJSIP_TRANSPORT_UDP6) {
     231           0 :             const auto updKey = std::find_if(udpTransports_.cbegin(),
     232             :                                              udpTransports_.cend(),
     233           0 :                                              [tp](const std::pair<dhtnet::IpAddr, pjsip_transport*>& pair) {
     234           0 :                                                  return pair.second == tp;
     235             :                                              });
     236           0 :             if (updKey != udpTransports_.cend())
     237           0 :                 udpTransports_.erase(updKey);
     238             :         }
     239             :     }
     240             : 
     241             :     // Propagate the event to the appropriate transport
     242             :     // Note the SipTransport may not be in our mappings if marked as dead
     243        2249 :     if (sipTransport)
     244         719 :         sipTransport->stateCallback(state, info);
     245        2249 : }
     246             : 
     247             : std::shared_ptr<SipTransport>
     248       33618 : SipTransportBroker::addTransport(pjsip_transport* t)
     249             : {
     250       33618 :     if (t) {
     251       33618 :         std::lock_guard lock(transportMapMutex_);
     252             : 
     253       33621 :         auto key = transports_.find(t);
     254       33621 :         if (key != transports_.end()) {
     255       33621 :             if (auto sipTr = key->second.lock())
     256       33621 :                 return sipTr;
     257             :         }
     258             : 
     259           1 :         auto sipTr = std::make_shared<SipTransport>(t);
     260           1 :         if (key != transports_.end())
     261           1 :             key->second = sipTr;
     262             :         else
     263           0 :             transports_.emplace(std::make_pair(t, sipTr));
     264           1 :         return sipTr;
     265       33621 :     }
     266             : 
     267           0 :     return nullptr;
     268             : }
     269             : 
     270             : void
     271          62 : SipTransportBroker::shutdown()
     272             : {
     273          62 :     std::unique_lock lock(transportMapMutex_);
     274          62 :     isDestroying_ = true;
     275         370 :     for (auto& t : transports_) {
     276         308 :         if (auto transport = t.second.lock()) {
     277           0 :             pjsip_transport_shutdown(transport->get());
     278         308 :         }
     279             :     }
     280          62 : }
     281             : 
     282             : std::shared_ptr<SipTransport>
     283          26 : SipTransportBroker::getUdpTransport(const dhtnet::IpAddr& ipAddress)
     284             : {
     285          26 :     std::lock_guard lock(transportMapMutex_);
     286          26 :     auto itp = udpTransports_.find(ipAddress);
     287          26 :     if (itp != udpTransports_.end()) {
     288          17 :         auto it = transports_.find(itp->second);
     289          17 :         if (it != transports_.end()) {
     290          17 :             if (auto spt = it->second.lock()) {
     291           2 :                 JAMI_DBG("Reusing transport %s", ipAddress.toString(true).c_str());
     292           2 :                 return spt;
     293             :             } else {
     294             :                 // Transport still exists but have not been destroyed yet.
     295          15 :                 JAMI_WARN("Recycling transport %s", ipAddress.toString(true).c_str());
     296          15 :                 auto ret = std::make_shared<SipTransport>(itp->second);
     297          15 :                 it->second = ret;
     298          15 :                 return ret;
     299          32 :             }
     300             :         } else {
     301           0 :             JAMI_WARN("Cleaning up UDP transport %s", ipAddress.toString(true).c_str());
     302           0 :             udpTransports_.erase(itp);
     303             :         }
     304             :     }
     305           9 :     auto ret = createUdpTransport(ipAddress);
     306           9 :     if (ret) {
     307           9 :         udpTransports_[ipAddress] = ret->get();
     308           9 :         transports_[ret->get()] = ret;
     309             :     }
     310           9 :     return ret;
     311          26 : }
     312             : 
     313             : std::shared_ptr<SipTransport>
     314           9 : SipTransportBroker::createUdpTransport(const dhtnet::IpAddr& ipAddress)
     315             : {
     316           9 :     RETURN_IF_FAIL(ipAddress, nullptr, "Could not determine IP address for this transport");
     317             : 
     318             :     pjsip_udp_transport_cfg pj_cfg;
     319           9 :     pjsip_udp_transport_cfg_default(&pj_cfg, ipAddress.getFamily());
     320           9 :     pj_cfg.bind_addr = ipAddress;
     321           9 :     pjsip_transport* transport = nullptr;
     322           9 :     if (pj_status_t status = pjsip_udp_transport_start2(endpt_, &pj_cfg, &transport)) {
     323           0 :         JAMI_ERR("pjsip_udp_transport_start2 failed with error %d: %s",
     324             :                  status,
     325             :                  sip_utils::sip_strerror(status).c_str());
     326           0 :         JAMI_ERR("UDP IPv%s Transport did not start on %s",
     327             :                  ipAddress.isIpv4() ? "4" : "6",
     328             :                  ipAddress.toString(true).c_str());
     329           0 :         return nullptr;
     330             :     }
     331             : 
     332           9 :     JAMI_DBG("Created UDP transport on address %s", ipAddress.toString(true).c_str());
     333           9 :     return std::make_shared<SipTransport>(transport);
     334             : }
     335             : 
     336             : std::shared_ptr<TlsListener>
     337           0 : SipTransportBroker::getTlsListener(const dhtnet::IpAddr& ipAddress, const pjsip_tls_setting* settings)
     338             : {
     339           0 :     RETURN_IF_FAIL(settings, nullptr, "TLS settings not specified");
     340           0 :     RETURN_IF_FAIL(ipAddress, nullptr, "Could not determine IP address for this transport");
     341           0 :     JAMI_DEBUG("Creating TLS listener on {:s}...", ipAddress.toString(true));
     342             : #if 0
     343             :     JAMI_DBG(" ca_list_file : %s", settings->ca_list_file.ptr);
     344             :     JAMI_DBG(" cert_file    : %s", settings->cert_file.ptr);
     345             :     JAMI_DBG(" ciphers_num    : %d", settings->ciphers_num);
     346             :     JAMI_DBG(" verify server %d client %d client_cert %d", settings->verify_server, settings->verify_client, settings->require_client_cert);
     347             :     JAMI_DBG(" reuse_addr    : %d", settings->reuse_addr);
     348             : #endif
     349             : 
     350           0 :     pjsip_tpfactory* listener = nullptr;
     351             :     const pj_status_t status
     352           0 :         = pjsip_tls_transport_start2(endpt_, settings, ipAddress.pjPtr(), nullptr, 1, &listener);
     353           0 :     if (status != PJ_SUCCESS) {
     354           0 :         JAMI_ERR("TLS listener did not start: %s", sip_utils::sip_strerror(status).c_str());
     355           0 :         return nullptr;
     356             :     }
     357           0 :     return std::make_shared<TlsListener>(listener);
     358             : }
     359             : 
     360             : std::shared_ptr<SipTransport>
     361           0 : SipTransportBroker::getTlsTransport(const std::shared_ptr<TlsListener>& l,
     362             :                                     const dhtnet::IpAddr& remote,
     363             :                                     const std::string& remote_name)
     364             : {
     365           0 :     if (!l || !remote)
     366           0 :         return nullptr;
     367           0 :     dhtnet::IpAddr remoteAddr {remote};
     368           0 :     if (remoteAddr.getPort() == 0)
     369           0 :         remoteAddr.setPort(pjsip_transport_get_default_port_for_type(l->get()->type));
     370             : 
     371           0 :     JAMI_DBG("Get new TLS transport to %s", remoteAddr.toString(true).c_str());
     372             :     pjsip_tpselector sel;
     373           0 :     sel.type = PJSIP_TPSELECTOR_LISTENER;
     374           0 :     sel.u.listener = l->get();
     375           0 :     sel.disable_connection_reuse = PJ_FALSE;
     376             : 
     377             :     pjsip_tx_data tx_data;
     378           0 :     tx_data.dest_info.name = pj_str_t {(char*) remote_name.data(), (pj_ssize_t) remote_name.size()};
     379             : 
     380           0 :     pjsip_transport* transport = nullptr;
     381           0 :     pj_status_t status = pjsip_endpt_acquire_transport2(endpt_,
     382           0 :                                                         l->get()->type,
     383           0 :                                                         remoteAddr.pjPtr(),
     384           0 :                                                         remoteAddr.getLength(),
     385             :                                                         &sel,
     386           0 :                                                         remote_name.empty() ? nullptr : &tx_data,
     387             :                                                         &transport);
     388             : 
     389           0 :     if (!transport || status != PJ_SUCCESS) {
     390           0 :         JAMI_ERR("Could not get new TLS transport: %s", sip_utils::sip_strerror(status).c_str());
     391           0 :         return nullptr;
     392             :     }
     393           0 :     auto ret = std::make_shared<SipTransport>(transport, l);
     394           0 :     pjsip_transport_dec_ref(transport);
     395             :     {
     396           0 :         std::lock_guard lock(transportMapMutex_);
     397           0 :         transports_[ret->get()] = ret;
     398           0 :     }
     399           0 :     return ret;
     400           0 : }
     401             : 
     402             : std::shared_ptr<SipTransport>
     403        1196 : SipTransportBroker::getChanneledTransport(const std::shared_ptr<SIPAccountBase>& account,
     404             :                                           const std::shared_ptr<dhtnet::ChannelSocket>& socket,
     405             :                                           onShutdownCb&& cb)
     406             : {
     407        1196 :     if (!socket)
     408           0 :         return {};
     409        1195 :     auto sips_tr = std::make_unique<tls::ChanneledSIPTransport>(endpt_,
     410             :                                                                 socket,
     411        1195 :                                                                 std::move(cb));
     412        1196 :     auto tr = sips_tr->getTransportBase();
     413        1196 :     auto sip_tr = std::make_shared<SipTransport>(tr, socket->peerCertificate());
     414        1196 :     sip_tr->setDeviceId(socket->deviceId().toString());
     415        1196 :     sip_tr->setAccount(account);
     416             : 
     417             :     {
     418        1196 :         std::lock_guard lock(transportMapMutex_);
     419             :         // we do not check for key existence as we've just created it
     420             :         // (member of new SipIceTransport instance)
     421        1196 :         transports_.emplace(tr, sip_tr);
     422        1196 :     }
     423             : 
     424        1196 :     sips_tr->start();
     425        1196 :     sips_tr.release(); // managed by PJSIP now
     426        1196 :     return sip_tr;
     427        1196 : }
     428             : 
     429             : } // namespace jami

Generated by: LCOV version 1.14