LCOV - code coverage report
Current view: top level - src/jamidht - channeled_transport.cpp (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 90.0 % 120 108
Test Date: 2026-06-13 09:18:46 Functions: 77.3 % 22 17

            Line data    Source code
       1              : /*
       2              :  *  Copyright (C) 2004-2026 Savoir-faire Linux Inc.
       3              :  *
       4              :  *  This program is free software: you can redistribute it and/or modify
       5              :  *  it under the terms of the GNU General Public License as published by
       6              :  *  the Free Software Foundation, either version 3 of the License, or
       7              :  *  (at your option) any later version.
       8              :  *
       9              :  *  This program is distributed in the hope that it will be useful,
      10              :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12              :  *  GNU General Public License for more details.
      13              :  *
      14              :  *  You should have received a copy of the GNU General Public License
      15              :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16              :  */
      17              : 
      18              : #include "channeled_transport.h"
      19              : 
      20              : #include "logger.h"
      21              : #include <dhtnet/multiplexed_socket.h>
      22              : #include "connectivity/sip_utils.h"
      23              : 
      24              : #include <pjsip/sip_transport.h>
      25              : #include <pjsip/sip_endpoint.h>
      26              : #include <pj/compat/socket.h>
      27              : #include <pj/lock.h>
      28              : 
      29              : namespace jami {
      30              : namespace tls {
      31              : 
      32          173 : ChanneledSIPTransport::ChanneledSIPTransport(pjsip_endpoint* endpt,
      33              :                                              const std::shared_ptr<dhtnet::ChannelSocket>& socket,
      34          173 :                                              onShutdownCb&& cb)
      35          174 :     : socket_(socket)
      36          174 :     , shutdownCb_(std::move(cb))
      37          174 :     , trData_()
      38          174 :     , pool_ {nullptr}
      39          521 :     , rxPool_(nullptr)
      40              : {
      41          174 :     local_ = socket->getLocalAddress();
      42          174 :     remote_ = socket->getRemoteAddress();
      43          174 :     int tp_type = local_.isIpv6() ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS;
      44              : 
      45          696 :     JAMI_LOG("ChanneledSIPTransport@{} tr={}", fmt::ptr(this), fmt::ptr(&trData_.base));
      46              : 
      47              :     // Init memory
      48          174 :     trData_.self = this; // up-link for PJSIP callbacks
      49              : 
      50          174 :     pool_ = sip_utils::smart_alloc_pool(endpt, "channeled.pool", sip_utils::POOL_TP_INIT, sip_utils::POOL_TP_INC);
      51              : 
      52          174 :     auto& base = trData_.base;
      53          174 :     std::memset(&base, 0, sizeof(base));
      54              : 
      55          174 :     pj_ansi_snprintf(base.obj_name, PJ_MAX_OBJ_NAME, "chan%p", &base);
      56          174 :     base.endpt = endpt;
      57          174 :     base.tpmgr = pjsip_endpt_get_tpmgr(endpt);
      58          174 :     base.pool = pool_.get();
      59              : 
      60          174 :     if (pj_atomic_create(pool_.get(), 0, &base.ref_cnt) != PJ_SUCCESS)
      61            0 :         throw std::runtime_error("Unable to create PJSIP atomic.");
      62              : 
      63          174 :     if (pj_lock_create_recursive_mutex(pool_.get(), "chan", &base.lock) != PJ_SUCCESS)
      64            0 :         throw std::runtime_error("Unable to create PJSIP mutex.");
      65              : 
      66          174 :     if (not local_) {
      67            0 :         JAMI_ERROR("Invalid local address");
      68            0 :         throw std::runtime_error("Invalid local address");
      69              :     }
      70          174 :     if (not remote_) {
      71            0 :         JAMI_ERROR("Invalid remote address");
      72            0 :         throw std::runtime_error("Invalid remote address");
      73              :     }
      74              : 
      75          174 :     pj_sockaddr_cp(&base.key.rem_addr, remote_.pjPtr());
      76          174 :     base.key.type = tp_type;
      77          174 :     auto reg_type = static_cast<pjsip_transport_type_e>(tp_type);
      78          174 :     base.type_name = const_cast<char*>(pjsip_transport_get_type_name(reg_type));
      79          174 :     base.flag = pjsip_transport_get_flag_from_type(reg_type);
      80          174 :     base.info = static_cast<char*>(pj_pool_alloc(pool_.get(), sip_utils::TRANSPORT_INFO_LENGTH));
      81              : 
      82          174 :     auto remote_addr = remote_.toString();
      83          174 :     pj_ansi_snprintf(base.info, sip_utils::TRANSPORT_INFO_LENGTH, "%s to %s", base.type_name, remote_addr.c_str());
      84          174 :     base.addr_len = remote_.getLength();
      85          174 :     base.dir = PJSIP_TP_DIR_NONE;
      86              : 
      87              :     // Set initial local address
      88          174 :     pj_sockaddr_cp(&base.local_addr, local_.pjPtr());
      89              : 
      90          174 :     sip_utils::sockaddr_to_host_port(pool_.get(), &base.local_name, &base.local_addr);
      91          174 :     sip_utils::sockaddr_to_host_port(pool_.get(), &base.remote_name, remote_.pjPtr());
      92              : 
      93              :     // Init transport callbacks
      94          174 :     base.send_msg = [](pjsip_transport* transport,
      95              :                        pjsip_tx_data* tdata,
      96              :                        const pj_sockaddr_t* rem_addr,
      97              :                        int addr_len,
      98              :                        void* token,
      99              :                        pjsip_transport_callback callback) -> pj_status_t {
     100         1695 :         auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self);
     101         1695 :         return this_->send(tdata, rem_addr, addr_len, token, callback);
     102              :     };
     103          174 :     base.do_shutdown = [](pjsip_transport* transport) -> pj_status_t {
     104            2 :         auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self);
     105            8 :         JAMI_LOG("ChanneledSIPTransport@{} tr={} rc={:d}: shutdown",
     106              :                  fmt::ptr(this_),
     107              :                  fmt::ptr(transport),
     108              :                  pj_atomic_get(transport->ref_cnt));
     109            2 :         if (this_->socket_)
     110            2 :             this_->socket_->shutdown();
     111            2 :         return PJ_SUCCESS;
     112              :     };
     113          174 :     base.destroy = [](pjsip_transport* transport) -> pj_status_t {
     114          174 :         auto* this_ = reinterpret_cast<ChanneledSIPTransport*>(reinterpret_cast<TransportData*>(transport)->self);
     115          174 :         delete this_;
     116          174 :         return PJ_SUCCESS;
     117              :     };
     118              : 
     119              :     // Init rdata_
     120          174 :     std::memset(&rdata_, 0, sizeof(pjsip_rx_data));
     121          174 :     rxPool_ = sip_utils::smart_alloc_pool(endpt, "channeled.rxPool", PJSIP_POOL_RDATA_LEN, PJSIP_POOL_RDATA_LEN);
     122          174 :     rdata_.tp_info.pool = rxPool_.get();
     123          174 :     rdata_.tp_info.transport = &base;
     124          174 :     rdata_.tp_info.tp_data = this;
     125          174 :     rdata_.tp_info.op_key.rdata = &rdata_;
     126          174 :     pj_ioqueue_op_key_init(&rdata_.tp_info.op_key.op_key, sizeof(pj_ioqueue_op_key_t));
     127          174 :     rdata_.pkt_info.src_addr = base.key.rem_addr;
     128          174 :     rdata_.pkt_info.src_addr_len = sizeof(rdata_.pkt_info.src_addr);
     129          174 :     auto rem_addr = &base.key.rem_addr;
     130          174 :     pj_sockaddr_print(rem_addr, rdata_.pkt_info.src_name, sizeof(rdata_.pkt_info.src_name), 0);
     131          174 :     rdata_.pkt_info.src_port = pj_sockaddr_get_port(rem_addr);
     132              : 
     133              :     // Register callbacks
     134          174 :     if (pjsip_transport_register(base.tpmgr, &base) != PJ_SUCCESS)
     135            0 :         throw std::runtime_error("Unable to register PJSIP transport.");
     136          174 : }
     137              : 
     138              : void
     139          174 : ChanneledSIPTransport::start()
     140              : {
     141              :     // Link to Channel Socket
     142          174 :     socket_->setOnRecv([this](const uint8_t* buf, size_t len) {
     143         1693 :         pj_gettimeofday(&rdata_.pkt_info.timestamp);
     144         1694 :         size_t remaining {len};
     145         3388 :         while (remaining) {
     146              :             // Build rdata
     147         1694 :             size_t added = std::min(remaining, (size_t) PJSIP_MAX_PKT_LEN - (size_t) rdata_.pkt_info.len);
     148         1694 :             std::copy_n(buf, added, rdata_.pkt_info.packet + rdata_.pkt_info.len);
     149         1695 :             rdata_.pkt_info.len += added;
     150         1695 :             buf += added;
     151         1695 :             remaining -= added;
     152              : 
     153              :             // Consume packet
     154         1695 :             auto eaten = pjsip_tpmgr_receive_packet(trData_.base.tpmgr, &rdata_);
     155         1695 :             if (eaten == rdata_.pkt_info.len) {
     156         1695 :                 rdata_.pkt_info.len = 0;
     157            0 :             } else if (eaten > 0) {
     158            0 :                 memmove(rdata_.pkt_info.packet, rdata_.pkt_info.packet + eaten, eaten);
     159            0 :                 rdata_.pkt_info.len -= eaten;
     160              :             }
     161         1695 :             pj_pool_reset(rdata_.tp_info.pool);
     162              :         }
     163         1694 :         return len;
     164              :     });
     165          174 :     socket_->onShutdown([this](const std::error_code& ec) {
     166          174 :         disconnected_ = true;
     167          174 :         if (auto state_cb = pjsip_tpmgr_get_state_cb(trData_.base.tpmgr)) {
     168              :             // JAMI_LOG("[SIPS] process disconnect event");
     169              :             pjsip_transport_state_info state_info;
     170          174 :             std::memset(&state_info, 0, sizeof(state_info));
     171          174 :             state_info.status = ec ? PJ_STATUS_FROM_OS(ec.value()) : PJ_SUCCESS;
     172          174 :             (*state_cb)(&trData_.base, PJSIP_TP_STATE_DISCONNECTED, &state_info);
     173              :         }
     174          174 :         shutdownCb_();
     175          174 :     });
     176          174 : }
     177              : 
     178          348 : ChanneledSIPTransport::~ChanneledSIPTransport()
     179              : {
     180          174 :     auto base = getTransportBase();
     181              : 
     182              :     // Here, we reset callbacks in ChannelSocket to avoid to call it after destruction
     183              :     // ChanneledSIPTransport is managed by pjsip, so we don't have any weak_ptr available
     184          174 :     socket_->setOnRecv([](const uint8_t*, size_t len) { return len; });
     185          348 :     socket_->onShutdown([](const std::error_code&) {});
     186              :     // Stop low-level transport first
     187          174 :     socket_->shutdown();
     188          174 :     socket_.reset();
     189              : 
     190              :     // If delete not trigged by pjsip_transport_destroy (happen if objet not given to pjsip)
     191          174 :     if (not base->is_shutdown and not base->is_destroying)
     192            0 :         pjsip_transport_shutdown(base);
     193              : 
     194          174 :     pj_lock_destroy(base->lock);
     195          174 :     pj_atomic_destroy(base->ref_cnt);
     196          696 :     JAMI_LOG("~ChanneledSIPTransport@{} tr={}", fmt::ptr(this), fmt::ptr(&trData_.base));
     197          348 : }
     198              : 
     199              : pj_status_t
     200         1695 : ChanneledSIPTransport::send(
     201              :     pjsip_tx_data* tdata, const pj_sockaddr_t* rem_addr, int addr_len, void*, pjsip_transport_callback)
     202              : {
     203              :     // Sanity check
     204         1695 :     PJ_ASSERT_RETURN(tdata, PJ_EINVAL);
     205              : 
     206              :     // Check that there's no pending operation associated with the tdata
     207         1695 :     PJ_ASSERT_RETURN(tdata->op_key.tdata == nullptr, PJSIP_EPENDINGTX);
     208              : 
     209              :     // Check the address is supported
     210         1695 :     PJ_ASSERT_RETURN(rem_addr and (addr_len == sizeof(pj_sockaddr_in) or addr_len == sizeof(pj_sockaddr_in6)),
     211              :                      PJ_EINVAL);
     212              : 
     213              :     // Check in we are able to send it in synchronous way first
     214         1695 :     std::size_t size = tdata->buf.cur - tdata->buf.start;
     215         1695 :     if (socket_) {
     216         1694 :         std::error_code ec;
     217         1695 :         socket_->write(reinterpret_cast<const uint8_t*>(tdata->buf.start), size, ec);
     218         1695 :         if (!ec)
     219         1695 :             return PJ_SUCCESS;
     220              :     }
     221            0 :     return PJ_EINVAL;
     222              : }
     223              : 
     224              : } // namespace tls
     225              : } // namespace jami
        

Generated by: LCOV version 2.0-1