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 : #pragma once 18 : 19 : #include <dhtnet/ip_utils.h> 20 : #ifdef HAVE_CONFIG_H 21 : #include "config.h" 22 : #endif 23 : 24 : #include "noncopyable.h" 25 : #include "logger.h" 26 : 27 : #include <pjsip.h> 28 : #include <pjnath/stun_config.h> 29 : 30 : #include <functional> 31 : #include <mutex> 32 : #include <map> 33 : #include <string> 34 : #include <memory> 35 : 36 : // OpenDHT 37 : namespace dht { 38 : namespace crypto { 39 : struct Certificate; 40 : } 41 : } // namespace dht 42 : 43 : namespace dhtnet { 44 : class ChannelSocket; 45 : } // namespace dhtnet 46 : 47 : namespace jami { 48 : class SIPAccountBase; 49 : using onShutdownCb = std::function<void(void)>; 50 : 51 : struct TlsListener 52 : { 53 : TlsListener() {} 54 0 : TlsListener(pjsip_tpfactory* f) 55 0 : : listener(f) 56 0 : {} 57 0 : virtual ~TlsListener() 58 0 : { 59 0 : JAMI_DBG("Destroying listener"); 60 0 : listener->destroy(listener); 61 0 : } 62 0 : pjsip_tpfactory* get() { return listener; } 63 : 64 : private: 65 : NON_COPYABLE(TlsListener); 66 : pjsip_tpfactory* listener {nullptr}; 67 : }; 68 : 69 : struct TlsInfos 70 : { 71 : pj_ssl_cipher cipher {PJ_TLS_UNKNOWN_CIPHER}; 72 : pj_ssl_sock_proto proto {PJ_SSL_SOCK_PROTO_DEFAULT}; 73 : pj_ssl_cert_verify_flag_t verifyStatus {}; 74 : std::shared_ptr<dht::crypto::Certificate> peerCert {}; 75 : }; 76 : 77 : using SipTransportStateCallback = std::function<void(pjsip_transport_state, const pjsip_transport_state_info*)>; 78 : 79 : /** 80 : * SIP transport wraps pjsip_transport. 81 : */ 82 : class SipTransport 83 : { 84 : public: 85 : SipTransport(pjsip_transport*); 86 : SipTransport(pjsip_transport*, const std::shared_ptr<TlsListener>&); 87 : // If the SipTransport is a channeled transport, we are already connected to the peer, 88 : // so, we can directly set tlsInfos_.peerCert and avoid any copy 89 : SipTransport(pjsip_transport* t, const std::shared_ptr<dht::crypto::Certificate>& peerCertficate); 90 : 91 : ~SipTransport(); 92 : 93 : static const char* stateToStr(pjsip_transport_state state); 94 : 95 : void stateCallback(pjsip_transport_state state, const pjsip_transport_state_info* info); 96 : 97 796 : pjsip_transport* get() { return transport_.get(); } 98 : 99 : void addStateListener(uintptr_t lid, const SipTransportStateCallback& cb); 100 : bool removeStateListener(uintptr_t lid); 101 : 102 570 : bool isSecure() const { return PJSIP_TRANSPORT_IS_SECURE(transport_); } 103 : 104 139 : const TlsInfos& getTlsInfos() const { return tlsInfos_; } 105 : 106 : static bool isAlive(pjsip_transport_state state); 107 : 108 : /** Only makes sense for connection-oriented transports */ 109 0 : bool isConnected() const noexcept { return connected_; } 110 : 111 174 : inline void setDeviceId(const std::string& deviceId) { deviceId_ = deviceId; } 112 209 : inline std::string_view deviceId() const { return deviceId_; } 113 174 : inline void setAccount(const std::shared_ptr<SIPAccountBase>& account) { account_ = account; } 114 105 : inline const std::weak_ptr<SIPAccountBase>& getAccount() const { return account_; } 115 : 116 : uint16_t getTlsMtu(); 117 : 118 : private: 119 : NON_COPYABLE(SipTransport); 120 : 121 : static void deleteTransport(pjsip_transport* t); 122 : struct TransportDeleter 123 : { 124 198 : void operator()(pjsip_transport* t) const noexcept { deleteTransport(t); } 125 : }; 126 : 127 : std::unique_ptr<pjsip_transport, TransportDeleter> transport_; 128 : std::shared_ptr<TlsListener> tlsListener_; 129 : std::mutex stateListenersMutex_; 130 : std::map<uintptr_t, SipTransportStateCallback> stateListeners_; 131 : std::weak_ptr<SIPAccountBase> account_ {}; 132 : 133 : bool connected_ {false}; 134 : std::string deviceId_ {}; 135 : TlsInfos tlsInfos_; 136 : }; 137 : 138 : class IceTransport; 139 : namespace tls { 140 : struct TlsParams; 141 : }; 142 : 143 : /** 144 : * Manages the transports and receive callbacks from PJSIP 145 : */ 146 : class SipTransportBroker 147 : { 148 : public: 149 : SipTransportBroker(pjsip_endpoint* endpt); 150 : ~SipTransportBroker(); 151 : 152 : std::shared_ptr<SipTransport> getUdpTransport(const dhtnet::IpAddr&); 153 : 154 : std::shared_ptr<TlsListener> getTlsListener(const dhtnet::IpAddr&, const pjsip_tls_setting*); 155 : 156 : std::shared_ptr<SipTransport> getTlsTransport(const std::shared_ptr<TlsListener>&, 157 : const dhtnet::IpAddr& remote, 158 : const std::string& remote_name = {}); 159 : 160 : std::shared_ptr<SipTransport> addTransport(pjsip_transport*); 161 : 162 : std::shared_ptr<SipTransport> getChanneledTransport(const std::shared_ptr<SIPAccountBase>& account, 163 : const std::shared_ptr<dhtnet::ChannelSocket>& socket, 164 : onShutdownCb&& cb); 165 : 166 : /** 167 : * Start graceful shutdown procedure for all transports 168 : */ 169 : void shutdown(); 170 : 171 : void transportStateChanged(pjsip_transport*, pjsip_transport_state, const pjsip_transport_state_info*); 172 : 173 : private: 174 : NON_COPYABLE(SipTransportBroker); 175 : 176 : /** 177 : * Create SIP UDP transport from account's setting 178 : * @param account The account for which a transport must be created. 179 : * @param IP protocol version to use, can be pj_AF_INET() or pj_AF_INET6() 180 : * @return a pointer to the new transport 181 : */ 182 : std::shared_ptr<SipTransport> createUdpTransport(const dhtnet::IpAddr&); 183 : 184 : /** 185 : * List of transports so we can bubble the events up. 186 : */ 187 : std::map<pjsip_transport*, std::weak_ptr<SipTransport>> transports_ {}; 188 : std::mutex transportMapMutex_ {}; 189 : 190 : /** 191 : * Transports are stored in this map in order to retrieve them in case 192 : * several accounts would share the same port number. 193 : */ 194 : std::map<dhtnet::IpAddr, pjsip_transport*> udpTransports_; 195 : 196 : pjsip_endpoint* endpt_; 197 : std::atomic_bool isDestroying_ {false}; 198 : }; 199 : 200 : } // namespace jami