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