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 "sip/sipaccountbase.h"
24 : #include "sip/siptransport.h"
25 : #include "noncopyable.h"
26 : #include "sipaccount_config.h"
27 :
28 : #include <pjsip/sip_transport_tls.h>
29 : #include <pjsip/sip_types.h>
30 : #include <pjsip-ua/sip_regc.h>
31 :
32 : #include <vector>
33 : #include <map>
34 :
35 : namespace jami {
36 :
37 : typedef std::vector<pj_ssl_cipher> CipherArray;
38 :
39 : class SIPPresence;
40 : class SIPCall;
41 :
42 : /**
43 : * @file sipaccount.h
44 : * @brief A SIP Account specify SIP specific functions and object = SIPCall/SIPVoIPLink)
45 : */
46 : class SIPAccount : public SIPAccountBase
47 : {
48 : public:
49 : constexpr static auto ACCOUNT_TYPE = ACCOUNT_TYPE_SIP;
50 :
51 20 : std::shared_ptr<SIPAccount> shared() { return std::static_pointer_cast<SIPAccount>(shared_from_this()); }
52 : std::shared_ptr<SIPAccount const> shared() const
53 : {
54 : return std::static_pointer_cast<SIPAccount const>(shared_from_this());
55 : }
56 9 : std::weak_ptr<SIPAccount> weak() { return std::static_pointer_cast<SIPAccount>(shared_from_this()); }
57 : std::weak_ptr<SIPAccount const> weak() const
58 : {
59 : return std::static_pointer_cast<SIPAccount const>(shared_from_this());
60 : }
61 :
62 : /**
63 : * Constructor
64 : * @param accountID The account identifier
65 : */
66 : SIPAccount(const std::string& accountID, bool presenceEnabled);
67 :
68 : ~SIPAccount() noexcept;
69 :
70 909 : const SipAccountConfig& config() const { return *static_cast<const SipAccountConfig*>(&Account::config()); }
71 :
72 24 : std::unique_ptr<AccountConfig> buildConfig() const override
73 : {
74 24 : return std::make_unique<SipAccountConfig>(getAccountID());
75 : }
76 21 : inline void editConfig(std::function<void(SipAccountConfig& conf)>&& edit)
77 : {
78 42 : Account::editConfig([&](AccountConfig& conf) { edit(*static_cast<SipAccountConfig*>(&conf)); });
79 21 : }
80 :
81 36 : std::string_view getAccountType() const override { return ACCOUNT_TYPE; }
82 :
83 : pjsip_host_port getHostPortFromSTUN(pj_pool_t* pool);
84 :
85 : void updateDialogViaSentBy(pjsip_dialog* dlg);
86 :
87 : void resetAutoRegistration();
88 :
89 : /**
90 : * Update NAT address, Via and Contact header from the REGISTER response
91 : * @param param pjsip reg cbparam
92 : * @param pool
93 : * @return update status
94 : */
95 : bool checkNATAddress(pjsip_regc_cbparam* param, pj_pool_t* pool);
96 :
97 : /**
98 : * Returns true if this is the IP2IP account
99 : */
100 : bool isIP2IP() const override;
101 :
102 : /**
103 : * Retrieve volatile details such as recent registration errors
104 : * @return std::map< std::string, std::string > The account volatile details
105 : */
106 : virtual std::map<std::string, std::string> getVolatileAccountDetails() const override;
107 :
108 : /**
109 : * Return the TLS settings, mainly used to return security information to
110 : * a client application
111 : */
112 : std::map<std::string, std::string> getTlsSettings() const;
113 :
114 : /**
115 : * Actually useless, since config loading is done in init()
116 : */
117 : void loadConfig() override;
118 :
119 : /**
120 : * updates SIP account profile
121 : */
122 : void updateProfile(const std::string& displayName,
123 : const std::string& avatar,
124 : const std::string& fileType,
125 : int32_t flag) override;
126 :
127 : /**
128 : * Initialize the SIP voip link with the account parameters and send registration
129 : */
130 : void doRegister() override;
131 :
132 : /**
133 : * Send unregistration.
134 : */
135 : void doUnregister(bool forceShutdownConnections = false) override;
136 :
137 : /**
138 : * Build and send SIP registration request
139 : */
140 : void sendRegister();
141 :
142 : /**
143 : * Build and send SIP unregistration request
144 : * @param destroy_transport If true, attempt to destroy the transport.
145 : */
146 : void sendUnregister();
147 :
148 15 : const pjsip_cred_info* getCredInfo() const { return cred_.data(); }
149 :
150 : /**
151 : * Get the number of credentials defined for
152 : * this account.
153 : * @param none
154 : * @return int The number of credentials set for this account.
155 : */
156 15 : unsigned getCredentialCount() const { return config().credentials.size(); }
157 :
158 10 : bool hasCredentials() const { return not config().credentials.empty(); }
159 :
160 0 : std::vector<std::map<std::string, std::string>> getCredentials() const { return config().getCredentials(); }
161 :
162 : virtual void setRegistrationState(RegistrationState state,
163 : int code = 0,
164 : const std::string& detail_str = {}) override;
165 :
166 : /**
167 : * A client sendings a REGISTER request MAY suggest an expiration
168 : * interval that indicates how long the client would like the
169 : * registration to be valid.
170 : *
171 : * @return the expiration value.
172 : */
173 5 : unsigned getRegistrationExpire() const
174 : {
175 5 : unsigned re = config().registrationExpire;
176 5 : return re ? re : PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
177 : }
178 :
179 : /**
180 : * Registration flag
181 : */
182 6 : bool isRegistered() const { return bRegister_; }
183 :
184 : /**
185 : * Get the registration structure that is used
186 : * for PJSIP in the registration process.
187 : * Settings are loaded from configuration file.
188 : * @return pjsip_regc* A pointer to the registration structure
189 : */
190 6 : pjsip_regc* getRegistrationInfo() { return regc_; }
191 :
192 : /**
193 : * Set the registration structure that is used
194 : * for PJSIP in the registration process;
195 : * @pram A pointer to the new registration structure
196 : * @return void
197 : */
198 5 : void setRegistrationInfo(pjsip_regc* regc)
199 : {
200 5 : if (regc_)
201 3 : destroyRegistrationInfo();
202 5 : regc_ = regc;
203 5 : }
204 :
205 : void destroyRegistrationInfo();
206 :
207 : /**
208 : * Get the port on which the transport/listener should use, or is
209 : * actually using.
210 : * @return pj_uint16 The port used for that account
211 : */
212 : uint16_t getLocalPort() const { return config().localPort; }
213 :
214 21 : void setLocalPort(uint16_t port)
215 : {
216 21 : editConfig([&](SipAccountConfig& config) { config.localPort = port; });
217 21 : }
218 :
219 : /**
220 : * @return pjsip_tls_setting structure, filled from the configuration
221 : * file, that can be used directly by PJSIP to initialize
222 : * TLS transport.
223 : */
224 0 : pjsip_tls_setting* getTlsSetting() { return &tlsSetting_; }
225 :
226 : /**
227 : * Get the local port for TLS listener.
228 : * @return pj_uint16 The port used for that account
229 : */
230 : pj_uint16_t getTlsListenerPort() const { return config().tlsListenerPort; }
231 :
232 : pj_str_t getStunServerName() const { return stunServerName_; }
233 :
234 : static const std::vector<std::string>& getSupportedTlsCiphers();
235 : static const std::vector<std::string>& getSupportedTlsProtocols();
236 :
237 : /**
238 : * @return pj_uint8_t structure, filled from the configuration
239 : * file, that can be used directly by PJSIP to initialize
240 : * an alternate UDP transport.
241 : */
242 0 : pj_uint16_t getStunPort() const override { return stunPort_; }
243 :
244 : /**
245 : * @return bool Tells if current transport for that
246 : * account is set to OTHER.
247 : */
248 25 : bool isStunEnabled() const override { return config().stunEnabled; }
249 :
250 : /**
251 : * @return pj_str_t , filled from the configuration
252 : * file, that can be used directly by PJSIP to initialize
253 : * an alternate UDP transport.
254 : */
255 : std::string getStunServer() const { return config().stunServer; }
256 :
257 : /**
258 : * @return pj_str_t "From" uri based on account information.
259 : * From RFC3261: "The To header field first and foremost specifies the desired
260 : * logical" recipient of the request, or the address-of-record of the
261 : * user or resource that is the target of this request. [...] As such, it is
262 : * very important that the From URI not contain IP addresses or the FQDN
263 : * of the host on which the UA is running, since these are not logical
264 : * names."
265 : */
266 : std::string getFromUri() const override;
267 :
268 : /**
269 : * This method adds the correct scheme, hostname and append
270 : * the ;transport= parameter at the end of the uri, in accordance with RFC3261.
271 : * It is expected that "port" is present in the internal hostname_.
272 : *
273 : * @return pj_str_t "To" uri based on @param username
274 : * @param username A string formatted as : "username"
275 : */
276 : std::string getToUri(const std::string& username) const override;
277 :
278 : /**
279 : * In the current version, "srv" uri is obtained in the preformatted
280 : * way: hostname:port. This method adds the correct scheme and append
281 : * the ;transport= parameter at the end of the uri, in accordance with RFC3261.
282 : *
283 : * @return pj_str_t "server" uri based on @param hostPort
284 : * @param hostPort A string formatted as : "hostname:port"
285 : */
286 : std::string getServerUri() const;
287 :
288 : /**
289 : * Get the contact address
290 : * @return The current contact address
291 : */
292 : dhtnet::IpAddr getContactAddress() const;
293 : /**
294 : * Get the contact header
295 : * @return The current contact header
296 : */
297 : std::string getContactHeader() const;
298 :
299 0 : std::string getServiceRoute() const { return config().serviceRoute; }
300 :
301 23 : bool hasServiceRoute() const { return not config().serviceRoute.empty(); }
302 :
303 14 : virtual bool isTlsEnabled() const override { return config().tlsEnable; }
304 :
305 0 : virtual bool getSrtpFallback() const override { return config().srtpFallback; }
306 :
307 : void setReceivedParameter(const std::string& received)
308 : {
309 : receivedParameter_ = received;
310 : via_addr_.host = sip_utils::CONST_PJ_STR(receivedParameter_);
311 : }
312 :
313 5 : const std::string& getReceivedParameter() const { return receivedParameter_; }
314 :
315 0 : pjsip_host_port* getViaAddr() { return &via_addr_; }
316 :
317 : int getRPort() const
318 : {
319 : if (rPort_ == -1)
320 : return config().localPort;
321 : else
322 : return rPort_;
323 : }
324 :
325 : void setRPort(int rPort)
326 : {
327 : rPort_ = rPort;
328 : via_addr_.port = rPort;
329 : }
330 :
331 5 : bool isRegistrationRefreshEnabled() const { return config().registrationRefreshEnabled; }
332 :
333 : void setTransport(const std::shared_ptr<SipTransport>& = nullptr);
334 :
335 0 : virtual inline std::shared_ptr<SipTransport> getTransport() { return transport_; }
336 :
337 1 : inline pjsip_transport_type_e getTransportType() const { return transportType_; }
338 :
339 : /**
340 : * Shortcut for SipTransport::getTransportSelector(account.getTransport()).
341 : */
342 : pjsip_tpselector getTransportSelector();
343 :
344 : /* Returns true if the username and/or hostname match this account */
345 : MatchRank matches(std::string_view username, std::string_view hostname) const override;
346 :
347 : /**
348 : * Presence management
349 : */
350 : SIPPresence* getPresence() const;
351 :
352 : /**
353 : * Activate the module.
354 : * @param function Publish or subscribe to enable
355 : * @param enable Flag
356 : */
357 : void enablePresence(const bool& enable);
358 : /**
359 : * Activate the publish/subscribe.
360 : * @param enable Flag
361 : */
362 : void supportPresence(int function, bool enable);
363 :
364 : /**
365 : * Create outgoing SIPCall.
366 : * @param[in] toUrl the address to call
367 : * @param[in] mediaList list of medias
368 : * @return a shared pointer on the created call.
369 : */
370 : std::shared_ptr<Call> newOutgoingCall(std::string_view toUrl,
371 : const std::vector<libjami::MediaMap>& mediaList) override;
372 :
373 : /**
374 : * Create incoming SIPCall.
375 : * @param[in] from The origin of the call
376 : * @param mediaList A list of media
377 : * @param sipTr: SIP Transport
378 : * @return A shared pointer on the created call.
379 : */
380 : std::shared_ptr<SIPCall> newIncomingCall(const std::string& from,
381 : const std::vector<libjami::MediaMap>& mediaList,
382 : const std::shared_ptr<SipTransport>& sipTr = {}) override;
383 :
384 : void onRegister(pjsip_regc_cbparam* param);
385 :
386 : virtual void sendMessage(const std::string& to,
387 : const std::string& deviceId,
388 : const std::map<std::string, std::string>& payloads,
389 : uint64_t id,
390 : bool retryOnTimeout = true,
391 : bool onlyConnected = false) override;
392 :
393 : void connectivityChanged() override;
394 :
395 : std::string getUserUri() const override;
396 :
397 : /**
398 : * Create the Ip address that the transport uses
399 : * @return IpAddr created
400 : */
401 : dhtnet::IpAddr createBindingAddress();
402 :
403 : void setActiveCodecs(const std::vector<unsigned>& list) override;
404 32 : bool isSrtpEnabled() const override { return config().srtpKeyExchange != KeyExchangeProtocol::NONE; }
405 :
406 : bool setPushNotificationToken(const std::string& pushDeviceToken = "") override;
407 : bool setPushNotificationConfig(const std::map<std::string, std::string>& data) override;
408 :
409 : /**
410 : * To be called by clients with relevant data when a push notification is received.
411 : */
412 : void pushNotificationReceived(const std::string& from, const std::map<std::string, std::string>& data);
413 :
414 : private:
415 : void doRegister1_();
416 : void doRegister2_();
417 :
418 : // Initialize the address to be used in contact header. Might
419 : // be updated (as the contact header)after the registration.
420 : bool initContactAddress();
421 : void updateContactHeader();
422 :
423 : void setCredentials(const std::vector<SipAccountConfig::Credentials>& creds);
424 :
425 : void setUpTransmissionData(pjsip_tx_data* tdata, long transportKeyType);
426 :
427 : NON_COPYABLE(SIPAccount);
428 :
429 : std::shared_ptr<Call> newRegisteredAccountCall(const std::string& id, const std::string& toUrl);
430 :
431 : /**
432 : * Start a SIP Call
433 : * @param call The current call
434 : * @return true if all is correct
435 : */
436 : bool SIPStartCall(std::shared_ptr<SIPCall>& call);
437 :
438 : void usePublishedAddressPortInVIA();
439 : void useUPnPAddressPortInVIA();
440 : bool fullMatch(std::string_view username, std::string_view hostname) const;
441 : bool userMatch(std::string_view username) const;
442 : bool hostnameMatch(std::string_view hostname) const;
443 : bool proxyMatch(std::string_view hostname) const;
444 :
445 : /**
446 : * Callback called by the transport layer when the registration
447 : * transport state changes.
448 : */
449 : virtual void onTransportStateChanged(pjsip_transport_state state, const pjsip_transport_state_info* info);
450 :
451 : struct
452 : {
453 : pj_bool_t active {false}; /**< Flag of reregister status. */
454 : pj_timer_entry timer {}; /**< Timer for reregistration. */
455 : unsigned attempt_cnt {0}; /**< Attempt counter. */
456 : } auto_rereg_ {}; /**< Reregister/reconnect data. */
457 :
458 : std::uniform_int_distribution<int> delay10ZeroDist_ {-10000, 10000};
459 : std::uniform_int_distribution<unsigned int> delay10PosDist_ {0, 10000};
460 :
461 : void scheduleReregistration();
462 : void autoReregTimerCb();
463 :
464 : std::shared_ptr<SipTransport> transport_ {};
465 :
466 : std::shared_ptr<TlsListener> tlsListener_ {};
467 :
468 : /**
469 : * Transport type used for this sip account. Currently supported types:
470 : * PJSIP_TRANSPORT_UNSPECIFIED
471 : * PJSIP_TRANSPORT_UDP
472 : * PJSIP_TRANSPORT_TLS
473 : */
474 : pjsip_transport_type_e transportType_ {PJSIP_TRANSPORT_UNSPECIFIED};
475 :
476 : /**
477 : * Maps a string description of the SSL method
478 : * to the corresponding enum value in pjsip_ssl_method.
479 : * @param method The string representation
480 : * @return pjsip_ssl_method The corresponding value in the enum
481 : */
482 : static pj_uint32_t tlsProtocolFromString(const std::string& method);
483 :
484 : /**
485 : * Initializes tls settings from configuration file.
486 : */
487 : void initTlsConfiguration();
488 :
489 : /**
490 : * PJSIP aborts if the string length of our cipher list is too
491 : * great, so this function forces our cipher list to fit this constraint.
492 : */
493 : void trimCiphers();
494 :
495 : /**
496 : * Initializes STUN config from the config file
497 : */
498 : void initStunConfiguration();
499 :
500 : /**
501 : * If username is not provided, as it happens for Direct ip calls,
502 : * fetch the Real Name field of the user that is currently
503 : * running this program.
504 : * @return std::string The login name under which the software is running.
505 : */
506 : static std::string getLoginName();
507 :
508 : /**
509 : * Maps require port via UPnP
510 : */
511 : bool mapPortUPnP();
512 :
513 : /**
514 : * Print contact header in certain format
515 : */
516 : static std::string printContactHeader(const std::string& username,
517 : const std::string& displayName,
518 : const std::string& address,
519 : pj_uint16_t port,
520 : bool secure,
521 : const std::string& deviceKey = {});
522 :
523 : /**
524 : * Resolved IP of hostname_ (for registration)
525 : */
526 : dhtnet::IpAddr hostIp_;
527 :
528 : /**
529 : * The pjsip client registration information
530 : */
531 : pjsip_regc* regc_ {nullptr};
532 :
533 : /**
534 : * To check if the account is registered
535 : */
536 : bool bRegister_;
537 :
538 : /**
539 : * Credential information stored for further registration.
540 : * Points to credentials_ members.
541 : */
542 : std::vector<pjsip_cred_info> cred_;
543 :
544 : /**
545 : * The TLS settings, used only if tls is chosen as a sip transport.
546 : */
547 : pjsip_tls_setting tlsSetting_;
548 :
549 : /**
550 : * Allocate a vector to be used by pjsip to store the supported ciphers on this system.
551 : */
552 : CipherArray ciphers_;
553 :
554 : /**
555 : * The STUN server name (hostname)
556 : */
557 : pj_str_t stunServerName_ {nullptr, 0};
558 :
559 : /**
560 : * The STUN server port
561 : */
562 : pj_uint16_t stunPort_ {PJ_STUN_PORT};
563 :
564 : /**
565 : * Send Request Callback
566 : */
567 : static void onComplete(void* token, pjsip_event* event);
568 :
569 : /**
570 : * Details about the registration state.
571 : * This is a protocol Code:Description pair.
572 : */
573 : std::pair<int, std::string> registrationStateDetailed_;
574 :
575 : /**
576 : * Optional: "received" parameter from VIA header
577 : */
578 : std::string receivedParameter_;
579 :
580 : /**
581 : * Optional: "rport" parameter from VIA header
582 : */
583 : int rPort_ {-1};
584 :
585 : /**
586 : * Optional: via_addr construct from received parameters
587 : */
588 : pjsip_host_port via_addr_;
589 :
590 : // This is used at runtime . Mainly by SIPAccount::usePublishedAddressPortInVIA()
591 : std::string publishedIpStr_ {};
592 :
593 : /**
594 : * Temporary storage for getUPnPIpAddress().toString()
595 : * Used only by useUPnPAddressPortInVIA().
596 : */
597 : std::string upnpIpAddr_;
598 :
599 : mutable std::mutex contactMutex_;
600 : // Contact header
601 : std::string contactHeader_;
602 : // Contact address (the address part of a SIP URI)
603 : dhtnet::IpAddr contactAddress_ {};
604 : pjsip_transport* via_tp_ {nullptr};
605 :
606 : /**
607 : * Presence data structure
608 : */
609 : SIPPresence* presence_;
610 :
611 : /**
612 : * SIP port actually used,
613 : * this holds the actual port used for SIP, which may not be the port
614 : * selected in the configuration in the case that UPnP is used and the
615 : * configured port is already used by another client
616 : */
617 : pj_uint16_t publishedPortUsed_ {sip_utils::DEFAULT_SIP_PORT};
618 : };
619 :
620 : } // namespace jami
|