Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 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 "account.h"
24 :
25 : #include "connectivity/sip_utils.h"
26 : #include "noncopyable.h"
27 : #include "im/message_engine.h"
28 : #include "sipaccountbase_config.h"
29 :
30 : #include <dhtnet/turn_cache.h>
31 : #include <dhtnet/ip_utils.h>
32 : #include <dhtnet/ice_options.h>
33 :
34 : #include <array>
35 : #include <deque>
36 : #include <map>
37 : #include <memory>
38 : #include <mutex>
39 : #include <vector>
40 :
41 : extern "C" {
42 : #include <pjsip/sip_types.h>
43 : #ifdef _WIN32
44 : typedef uint16_t in_port_t;
45 : #else
46 : #include <netinet/in.h> // For in_port_t support
47 : #endif
48 :
49 : struct pjsip_dialog;
50 : struct pjsip_inv_session;
51 : struct pjmedia_sdp_session;
52 : }
53 :
54 : static constexpr const char MIME_TYPE_TEXT_PLAIN[] {"text/plain"};
55 :
56 : namespace jami {
57 :
58 : class SipTransport;
59 : class Task;
60 :
61 : typedef std::vector<pj_ssl_cipher> CipherArray;
62 :
63 : class SIPVoIPLink;
64 : class SIPCall;
65 :
66 : /**
67 : * @file sipaccount.h
68 : * @brief A SIP Account specify SIP specific functions and object = SIPCall/SIPVoIPLink)
69 : */
70 :
71 : enum class MatchRank { NONE, PARTIAL, FULL };
72 :
73 : class SIPAccountBase : public Account
74 : {
75 : public:
76 : constexpr static unsigned MAX_PORT {65536};
77 : constexpr static unsigned HALF_MAX_PORT {MAX_PORT / 2};
78 :
79 : /**
80 : * Constructor
81 : * @param accountID The account identifier
82 : */
83 : SIPAccountBase(const std::string& accountID);
84 :
85 : virtual ~SIPAccountBase() noexcept;
86 :
87 2236 : const SipAccountBaseConfig& config() const
88 : {
89 2236 : return *static_cast<const SipAccountBaseConfig*>(&Account::config());
90 : }
91 :
92 : void loadConfig() override;
93 :
94 : /**
95 : * Create incoming SIPCall.
96 : * @param[in] from The origin of the call
97 : * @param mediaList A list of media
98 : * @param sipTr: SIP Transport
99 : * @return A shared pointer on the created call.
100 : */
101 : virtual std::shared_ptr<SIPCall> newIncomingCall(const std::string& from,
102 : const std::vector<libjami::MediaMap>& mediaList,
103 : const std::shared_ptr<SipTransport>& sipTr = {})
104 : = 0;
105 :
106 97 : virtual bool isStunEnabled() const { return false; }
107 :
108 0 : virtual pj_uint16_t getStunPort() const { return 0; };
109 :
110 0 : virtual std::string getDtmfType() const { return config().dtmfType; }
111 :
112 : /**
113 : * Determine if TLS is enabled for this account. TLS provides a secured channel for
114 : * SIP signalization. It is independent of the media encryption (as provided by SRTP).
115 : */
116 0 : virtual bool isTlsEnabled() const { return false; }
117 :
118 : /**
119 : * Create UAC attached dialog and invite session
120 : * @return true if success. false if failure and dlg and inv pointers
121 : * should not be considered as valid.
122 : */
123 : bool CreateClientDialogAndInvite(const pj_str_t* from,
124 : const pj_str_t* contact,
125 : const pj_str_t* to,
126 : const pj_str_t* target,
127 : const pjmedia_sdp_session* local_sdp,
128 : pjsip_dialog** dlg,
129 : pjsip_inv_session** inv);
130 :
131 : /**
132 : * Get the local interface name on which this account is bound.
133 : */
134 323 : const std::string& getLocalInterface() const { return config().interface; }
135 :
136 : /**
137 : * Get the public IP address set by the user for this account.
138 : * If this setting is not provided, the local bound adddress
139 : * will be used.
140 : * @return std::string The public IPv4 or IPv6 address formatted in standard notation.
141 : */
142 0 : std::string getPublishedAddress() const { return config().publishedIp; }
143 :
144 : virtual dhtnet::IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const;
145 :
146 : void setPublishedAddress(const dhtnet::IpAddr& ip_addr);
147 :
148 : /**
149 : * Get a flag which determine the usage in sip headers of either the local
150 : * IP address and port (_localAddress and localPort_) or to an address set
151 : * manually (_publishedAddress and publishedPort_).
152 : */
153 229 : bool getPublishedSameasLocal() const { return config().publishedSameasLocal; }
154 :
155 : virtual bool isSrtpEnabled() const = 0;
156 :
157 : virtual bool getSrtpFallback() const = 0;
158 :
159 : virtual std::string getToUri(const std::string& username) const = 0;
160 :
161 : /**
162 : * Socket port generators for media
163 : * Note: given ports are application wide, a port is unable to be given again
164 : * by any account instances until it's released by the static method
165 : * releasePort().
166 : */
167 : uint16_t generateAudioPort() const;
168 : #ifdef ENABLE_VIDEO
169 : uint16_t generateVideoPort() const;
170 : #endif
171 : static void releasePort(uint16_t port) noexcept;
172 :
173 : virtual dhtnet::IceTransportOptions getIceOptions() const noexcept;
174 :
175 : virtual void sendMessage(const std::string& to,
176 : const std::string& deviceId,
177 : const std::map<std::string, std::string>& payloads,
178 : uint64_t id,
179 : bool retryOnTimeout = true,
180 : bool onlyConnected = false)
181 : = 0;
182 :
183 23152 : virtual uint64_t sendTextMessage(const std::string& to,
184 : const std::string& deviceId,
185 : const std::map<std::string, std::string>& payloads,
186 : uint64_t refreshToken = 0,
187 : bool onlyConnected = false) override
188 : {
189 23152 : if (onlyConnected) {
190 0 : auto token = std::uniform_int_distribution<uint64_t> {1, JAMI_ID_MAX_VAL}(rand);
191 0 : sendMessage(to, deviceId, payloads, token, false, true);
192 0 : return token;
193 : }
194 23152 : return messageEngine_.sendMessage(to, deviceId, payloads, refreshToken);
195 : }
196 :
197 0 : im::MessageStatus getMessageStatus(uint64_t id) const override
198 : {
199 0 : return messageEngine_.getStatus(id);
200 : }
201 :
202 : virtual void onTextMessage(const std::string& id,
203 : const std::string& from,
204 : const std::string& deviceId,
205 : const std::map<std::string, std::string>& payloads);
206 :
207 : /* Returns true if the username and/or hostname match this account */
208 : virtual MatchRank matches(std::string_view username, std::string_view hostname) const = 0;
209 :
210 0 : void connectivityChanged() override {};
211 :
212 : virtual std::string getUserUri() const = 0;
213 :
214 : std::vector<libjami::Message> getLastMessages(const uint64_t& base_timestamp) override;
215 :
216 : // Build the list of medias to be included in the SDP (offer/answer)
217 : std::vector<MediaAttribute> createDefaultMediaList(bool addVideo, bool onHold = false);
218 :
219 : public: // overloaded methods
220 : virtual void flush() override;
221 :
222 : protected:
223 : /**
224 : * Retrieve volatile details such as recent registration errors
225 : * @return std::map< std::string, std::string > The account volatile details
226 : */
227 : virtual std::map<std::string, std::string> getVolatileAccountDetails() const override;
228 :
229 : virtual void setRegistrationState(RegistrationState state,
230 : int code = 0,
231 : const std::string& detail_str = {}) override;
232 :
233 : im::MessageEngine messageEngine_;
234 :
235 : /**
236 : * Voice over IP Link contains a listener thread and calls
237 : */
238 : SIPVoIPLink& link_;
239 :
240 : /**
241 : * Published IPv4/IPv6 addresses, used only if defined by the user in account
242 : * configuration
243 : *
244 : */
245 : dhtnet::IpAddr publishedIp_[2] {};
246 :
247 : pj_status_t transportStatus_ {PJSIP_SC_TRYING};
248 : std::string transportError_ {};
249 :
250 : static std::array<bool, HALF_MAX_PORT>& getPortsReservation() noexcept;
251 : static uint16_t acquirePort(uint16_t port);
252 : uint16_t getRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const;
253 : uint16_t acquireRandomEvenPort(const std::pair<uint16_t, uint16_t>& range) const;
254 :
255 : /**
256 : * The deamon can be launched without any client (or with a non ready client)
257 : * Like call and file transfer, a client should be able to retrieve current messages.
258 : * To avoid to explode the size in memory, this container should be limited.
259 : * We don't want to see monsters in memory.
260 : */
261 : std::mutex mutexLastMessages_;
262 : static constexpr size_t MAX_WAITING_MESSAGES_SIZE = 1000;
263 : std::deque<libjami::Message> lastMessages_;
264 :
265 : std::shared_ptr<dhtnet::TurnCache> turnCache_;
266 :
267 : private:
268 : NON_COPYABLE(SIPAccountBase);
269 : };
270 :
271 : } // namespace jami
|