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