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 :
18 : #include "sip/sipaccount.h"
19 :
20 : #ifdef HAVE_CONFIG_H
21 : #include "config.h"
22 : #endif
23 :
24 : #include "compiler_intrinsics.h"
25 :
26 : #include "vcard.h"
27 : #include "base64.h"
28 : #include "fileutils.h"
29 :
30 : #include "sdp.h"
31 : #include "sip/sipvoiplink.h"
32 : #include "sip/sipcall.h"
33 : #include "connectivity/sip_utils.h"
34 :
35 : #include "call_factory.h"
36 :
37 : #include "sip/sippresence.h"
38 :
39 : #pragma GCC diagnostic push
40 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
41 : #include <yaml-cpp/yaml.h>
42 : #pragma GCC diagnostic pop
43 :
44 : #include "account_schema.h"
45 : #include "config/yamlparser.h"
46 : #include "logger.h"
47 : #include "manager.h"
48 : #include "client/ring_signal.h"
49 : #include "jami/account_const.h"
50 :
51 : #ifdef ENABLE_VIDEO
52 : #include "libav_utils.h"
53 : #endif
54 :
55 : #include "system_codec_container.h"
56 :
57 : #include "string_utils.h"
58 :
59 : #include "im/instant_messaging.h"
60 :
61 : #include <dhtnet/ip_utils.h>
62 : #include <dhtnet/upnp/upnp_control.h>
63 :
64 : #include <opendht/crypto.h>
65 :
66 : #include <unistd.h>
67 :
68 : #include <algorithm>
69 : #include <array>
70 : #include <memory>
71 : #include <sstream>
72 : #include <cstdlib>
73 : #include <thread>
74 : #include <chrono>
75 : #include <ctime>
76 : #include <charconv>
77 :
78 : #ifdef _WIN32
79 : #include <lmcons.h>
80 : #else
81 : #include <pwd.h>
82 : #endif
83 :
84 : namespace jami {
85 :
86 : using sip_utils::CONST_PJ_STR;
87 :
88 : static constexpr unsigned REGISTRATION_FIRST_RETRY_INTERVAL = 60; // seconds
89 : static constexpr unsigned REGISTRATION_RETRY_INTERVAL = 300; // seconds
90 : static constexpr std::string_view VALID_TLS_PROTOS[] = {"Default"sv,
91 : "TLSv1.2"sv,
92 : "TLSv1.1"sv,
93 : "TLSv1"sv};
94 : static constexpr std::string_view PN_FCM = "fcm"sv;
95 : static constexpr std::string_view PN_APNS = "apns"sv;
96 :
97 : struct ctx
98 : {
99 0 : ctx(pjsip_auth_clt_sess* auth)
100 0 : : auth_sess(auth, &pjsip_auth_clt_deinit)
101 0 : {}
102 : std::weak_ptr<SIPAccount> acc;
103 : std::string to;
104 : uint64_t id;
105 : std::unique_ptr<pjsip_auth_clt_sess, decltype(&pjsip_auth_clt_deinit)> auth_sess;
106 : };
107 :
108 : static void
109 3 : registration_cb(pjsip_regc_cbparam* param)
110 : {
111 3 : if (!param) {
112 0 : JAMI_ERR("Registration callback parameter is null");
113 0 : return;
114 : }
115 :
116 3 : auto account = static_cast<SIPAccount*>(param->token);
117 3 : if (!account) {
118 0 : JAMI_ERR("Account doesn't exist in registration callback");
119 0 : return;
120 : }
121 :
122 3 : account->onRegister(param);
123 : }
124 :
125 24 : SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
126 : : SIPAccountBase(accountID)
127 24 : , ciphers_(100)
128 48 : , presence_(presenceEnabled ? new SIPPresence(this) : nullptr)
129 : {
130 24 : via_addr_.host.ptr = 0;
131 24 : via_addr_.host.slen = 0;
132 24 : via_addr_.port = 0;
133 24 : }
134 :
135 24 : SIPAccount::~SIPAccount() noexcept
136 : {
137 : // ensure that no registration callbacks survive past this point
138 : try {
139 24 : destroyRegistrationInfo();
140 24 : setTransport();
141 0 : } catch (...) {
142 0 : JAMI_ERR("Exception in SIPAccount destructor");
143 0 : }
144 :
145 24 : delete presence_;
146 24 : }
147 :
148 : void
149 0 : SIPAccount::updateProfile(const std::string& displayName,
150 : const std::string& avatar,
151 : const std::string& fileType,
152 : int32_t flag)
153 : {
154 0 : auto vCardPath = idPath_ / "profile.vcf";
155 :
156 0 : auto profile = getProfileVcard();
157 0 : if (profile.empty()) {
158 0 : profile = vCard::utils::initVcard();
159 : }
160 0 : profile["FN"] = displayName;
161 :
162 0 : if (!fileType.empty()) {
163 0 : const std::string& key = "PHOTO;ENCODING=BASE64;TYPE=" + fileType;
164 0 : if (flag == 0) {
165 0 : vCard::utils::removeByKey(profile, "PHOTO");
166 0 : const auto& avatarPath = std::filesystem::path(avatar);
167 0 : if (std::filesystem::exists(avatarPath)) {
168 : try {
169 0 : profile[key] = base64::encode(fileutils::loadFile(avatarPath));
170 0 : } catch (const std::exception& e) {
171 0 : JAMI_ERROR("Failed to load avatar: {}", e.what());
172 0 : }
173 0 : } else if (avatarPath.empty()) {
174 0 : vCard::utils::removeByKey(profile, "PHOTO");
175 0 : profile[key] = "";
176 : }
177 0 : } else if (flag == 1) {
178 0 : profile[key] = avatar;
179 : }
180 0 : }
181 :
182 : // nothing happens to the profile photo if the avatarPath is invalid
183 : // and not empty. So far it seems to be the best default behavior.
184 : try {
185 0 : auto tmpPath = vCardPath;
186 0 : tmpPath += ".tmp";
187 0 : std::ofstream file(tmpPath);
188 0 : if (file.is_open()) {
189 0 : file << vCard::utils::toString(profile);
190 0 : file.close();
191 0 : std::filesystem::rename(tmpPath, vCardPath);
192 0 : emitSignal<libjami::ConfigurationSignal::ProfileReceived>(getAccountID(),
193 : "",
194 0 : vCardPath.string());
195 : } else {
196 0 : JAMI_ERROR("Unable to open file for writing: {}", tmpPath);
197 : }
198 0 : } catch (const std::exception& e) {
199 0 : JAMI_ERROR("Error writing profile: {}", e.what());
200 0 : }
201 0 : }
202 :
203 : std::shared_ptr<SIPCall>
204 10 : SIPAccount::newIncomingCall(const std::string& from UNUSED,
205 : const std::vector<libjami::MediaMap>& mediaList,
206 : const std::shared_ptr<SipTransport>& transport)
207 : {
208 10 : auto call = Manager::instance().callFactory.newSipCall(shared(),
209 : Call::CallType::INCOMING,
210 20 : mediaList);
211 10 : call->setSipTransport(transport, getContactHeader());
212 10 : return call;
213 0 : }
214 :
215 : std::shared_ptr<Call>
216 10 : SIPAccount::newOutgoingCall(std::string_view toUrl, const std::vector<libjami::MediaMap>& mediaList)
217 : {
218 10 : std::string to;
219 : int family;
220 :
221 10 : JAMI_DBG() << *this << "Calling SIP peer" << toUrl;
222 :
223 10 : auto& manager = Manager::instance();
224 10 : std::shared_ptr<SIPCall> call;
225 :
226 : // SIP allows sending empty invites.
227 10 : if (not mediaList.empty() or isEmptyOffersEnabled()) {
228 10 : call = manager.callFactory.newSipCall(shared(), Call::CallType::OUTGOING, mediaList);
229 : } else {
230 0 : JAMI_WARN("Media list is empty, setting a default list");
231 0 : call = manager.callFactory.newSipCall(shared(),
232 : Call::CallType::OUTGOING,
233 0 : MediaAttribute::mediaAttributesToMediaMaps(
234 0 : createDefaultMediaList(isVideoEnabled())));
235 : }
236 :
237 10 : if (not call)
238 0 : throw std::runtime_error("Failed to create the call");
239 :
240 10 : if (isIP2IP()) {
241 9 : bool ipv6 = dhtnet::IpAddr::isIpv6(toUrl);
242 9 : to = ipv6 ? dhtnet::IpAddr(toUrl).toString(false, true) : toUrl;
243 9 : family = ipv6 ? pj_AF_INET6() : pj_AF_INET();
244 :
245 : // TODO: resolve remote host using SIPVoIPLink::resolveSrvName
246 : std::shared_ptr<SipTransport> t
247 9 : = isTlsEnabled()
248 0 : ? link_.sipTransportBroker->getTlsTransport(tlsListener_,
249 0 : dhtnet::IpAddr(
250 : sip_utils::getHostFromUri(to)))
251 9 : : transport_;
252 9 : setTransport(t);
253 9 : call->setSipTransport(t, getContactHeader());
254 :
255 9 : JAMI_DBG("New %s IP to IP call to %s", ipv6 ? "IPv6" : "IPv4", to.c_str());
256 9 : } else {
257 1 : to = toUrl;
258 1 : call->setSipTransport(transport_, getContactHeader());
259 : // Use the same address family as the SIP transport
260 1 : family = pjsip_transport_type_get_af(getTransportType());
261 :
262 3 : JAMI_LOG("UserAgent: New registered account call to {}", toUrl);
263 : }
264 :
265 10 : auto toUri = getToUri(to);
266 :
267 : // Do not init ICE yet if the media list is empty. This may occur
268 : // if we are sending an invite with no SDP offer.
269 10 : if (call->isIceEnabled() and not mediaList.empty()) {
270 8 : if (call->createIceMediaTransport(false)) {
271 8 : call->initIceMediaTransport(true);
272 : }
273 : }
274 :
275 10 : call->setPeerNumber(toUri);
276 10 : call->setPeerUri(toUri);
277 :
278 10 : const auto localAddress = dhtnet::ip_utils::getInterfaceAddr(getLocalInterface(), family);
279 :
280 10 : dhtnet::IpAddr addrSdp;
281 10 : if (getUPnPActive()) {
282 : /* use UPnP addr, or published addr if its set */
283 0 : addrSdp = getPublishedSameasLocal() ? getUPnPIpAddress() : getPublishedIpAddress();
284 : } else {
285 10 : addrSdp = isStunEnabled() or (not getPublishedSameasLocal()) ? getPublishedIpAddress()
286 : : localAddress;
287 : }
288 :
289 : /* Fallback on local address */
290 10 : if (not addrSdp)
291 0 : addrSdp = localAddress;
292 :
293 : // Building the local SDP offer
294 10 : auto& sdp = call->getSDP();
295 :
296 10 : if (getPublishedSameasLocal())
297 10 : sdp.setPublishedIP(addrSdp);
298 : else
299 0 : sdp.setPublishedIP(getPublishedAddress());
300 :
301 : // TODO. We should not dot his here. Move it to SIPCall.
302 10 : const bool created = sdp.createOffer(
303 20 : MediaAttribute::buildMediaAttributesList(mediaList, isSrtpEnabled()));
304 :
305 10 : if (created) {
306 10 : std::weak_ptr<SIPCall> weak_call = call;
307 10 : manager.scheduler().run([this, weak_call] {
308 10 : if (auto call = weak_call.lock()) {
309 10 : if (not SIPStartCall(call)) {
310 0 : JAMI_ERR("Unable to send outgoing INVITE request for new call");
311 0 : call->onFailure();
312 : }
313 10 : }
314 10 : return false;
315 : });
316 10 : } else {
317 0 : throw VoipLinkException("Unable to send outgoing INVITE request for new call");
318 : }
319 :
320 20 : return call;
321 10 : }
322 :
323 : void
324 0 : SIPAccount::onTransportStateChanged(pjsip_transport_state state,
325 : const pjsip_transport_state_info* info)
326 : {
327 0 : pj_status_t currentStatus = transportStatus_;
328 0 : JAMI_DEBUG("Transport state changed to {:s} for account {:s}!",
329 : SipTransport::stateToStr(state),
330 : accountID_);
331 0 : if (!SipTransport::isAlive(state)) {
332 0 : if (info) {
333 0 : transportStatus_ = info->status;
334 0 : transportError_ = sip_utils::sip_strerror(info->status);
335 0 : JAMI_ERROR("Transport disconnected: {:s}", transportError_);
336 : } else {
337 : // This is already the generic error used by PJSIP.
338 0 : transportStatus_ = PJSIP_SC_SERVICE_UNAVAILABLE;
339 0 : transportError_ = "";
340 : }
341 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_TSX_TRANSPORT_ERROR);
342 0 : setTransport();
343 : } else {
344 : // The status can be '0', this is the same as OK
345 0 : transportStatus_ = info && info->status ? info->status : PJSIP_SC_OK;
346 0 : transportError_ = "";
347 : }
348 :
349 : // Notify the client of the new transport state
350 0 : if (currentStatus != transportStatus_)
351 0 : emitSignal<libjami::ConfigurationSignal::VolatileDetailsChanged>(accountID_,
352 0 : getVolatileAccountDetails());
353 0 : }
354 :
355 : void
356 86 : SIPAccount::setTransport(const std::shared_ptr<SipTransport>& t)
357 : {
358 86 : if (t == transport_)
359 34 : return;
360 52 : if (transport_) {
361 75 : JAMI_DEBUG("Removing old transport [{}] from account", fmt::ptr(transport_.get()));
362 : // NOTE: do not call destroyRegistrationInfo() there as we must call the registration
363 : // callback if needed
364 25 : if (regc_)
365 3 : pjsip_regc_release_transport(regc_);
366 25 : transport_->removeStateListener(reinterpret_cast<uintptr_t>(this));
367 : }
368 :
369 52 : transport_ = t;
370 156 : JAMI_DEBUG("Set new transport [{}]", fmt::ptr(transport_.get()));
371 :
372 52 : if (transport_) {
373 54 : transport_->addStateListener(reinterpret_cast<uintptr_t>(this),
374 0 : std::bind(&SIPAccount::onTransportStateChanged,
375 27 : this,
376 : std::placeholders::_1,
377 : std::placeholders::_2));
378 : // Update contact address and header
379 27 : if (not initContactAddress()) {
380 0 : JAMI_DEBUG("Unable to register: invalid address");
381 0 : return;
382 : }
383 27 : updateContactHeader();
384 : }
385 : }
386 :
387 : pjsip_tpselector
388 8 : SIPAccount::getTransportSelector()
389 : {
390 8 : if (!transport_)
391 0 : return SIPVoIPLink::getTransportSelector(nullptr);
392 8 : return SIPVoIPLink::getTransportSelector(transport_->get());
393 : }
394 :
395 : bool
396 10 : SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call)
397 : {
398 : // Add Ice headers to local SDP if ice transport exist
399 10 : call->addLocalIceAttributes();
400 :
401 10 : const std::string& toUri(call->getPeerNumber()); // expecting a fully well formed sip uri
402 10 : pj_str_t pjTo = sip_utils::CONST_PJ_STR(toUri);
403 :
404 : // Create the from header
405 10 : std::string from(getFromUri());
406 10 : pj_str_t pjFrom = sip_utils::CONST_PJ_STR(from);
407 :
408 10 : auto transport = call->getTransport();
409 10 : if (!transport) {
410 0 : JAMI_ERROR("Unable to start call without transport");
411 0 : return false;
412 : }
413 :
414 10 : std::string contact = getContactHeader();
415 30 : JAMI_DEBUG("Contact header: {:s} / {:s} → {:s}", contact, from, toUri);
416 :
417 10 : pj_str_t pjContact = sip_utils::CONST_PJ_STR(contact);
418 10 : auto local_sdp = isEmptyOffersEnabled() ? nullptr : call->getSDP().getLocalSdpSession();
419 :
420 10 : pjsip_dialog* dialog {nullptr};
421 10 : pjsip_inv_session* inv {nullptr};
422 10 : if (!CreateClientDialogAndInvite(&pjFrom, &pjContact, &pjTo, nullptr, local_sdp, &dialog, &inv))
423 0 : return false;
424 :
425 10 : inv->mod_data[link_.getModId()] = call.get();
426 10 : call->setInviteSession(inv);
427 :
428 10 : updateDialogViaSentBy(dialog);
429 :
430 10 : if (hasServiceRoute())
431 0 : pjsip_dlg_set_route_set(dialog,
432 0 : sip_utils::createRouteSet(getServiceRoute(),
433 0 : call->inviteSession_->pool));
434 :
435 10 : if (hasCredentials()
436 10 : and pjsip_auth_clt_set_credentials(&dialog->auth_sess, getCredentialCount(), getCredInfo())
437 : != PJ_SUCCESS) {
438 0 : JAMI_ERROR("Unable to initialize credentials for invite session authentication");
439 0 : return false;
440 : }
441 :
442 : pjsip_tx_data* tdata;
443 :
444 10 : if (pjsip_inv_invite(call->inviteSession_.get(), &tdata) != PJ_SUCCESS) {
445 0 : JAMI_ERROR("Unable to initialize invite messager for this call");
446 0 : return false;
447 : }
448 :
449 10 : const pjsip_tpselector tp_sel = link_.getTransportSelector(transport->get());
450 10 : if (pjsip_dlg_set_transport(dialog, &tp_sel) != PJ_SUCCESS) {
451 0 : JAMI_ERROR("Unable to associate transport for invite session dialog");
452 0 : return false;
453 : }
454 :
455 : // Add user-agent header
456 10 : sip_utils::addUserAgentHeader(getUserAgentName(), tdata);
457 :
458 10 : if (pjsip_inv_send_msg(call->inviteSession_.get(), tdata) != PJ_SUCCESS) {
459 0 : JAMI_ERROR("Unable to send invite message for this call");
460 0 : return false;
461 : }
462 :
463 10 : call->setState(Call::CallState::ACTIVE, Call::ConnectionState::PROGRESSING);
464 :
465 10 : return true;
466 10 : }
467 :
468 : void
469 0 : SIPAccount::usePublishedAddressPortInVIA()
470 : {
471 0 : publishedIpStr_ = getPublishedIpAddress().toString();
472 0 : via_addr_.host.ptr = (char*) publishedIpStr_.c_str();
473 0 : via_addr_.host.slen = publishedIpStr_.size();
474 0 : via_addr_.port = publishedPortUsed_;
475 0 : }
476 :
477 : void
478 0 : SIPAccount::useUPnPAddressPortInVIA()
479 : {
480 0 : upnpIpAddr_ = getUPnPIpAddress().toString();
481 0 : via_addr_.host.ptr = (char*) upnpIpAddr_.c_str();
482 0 : via_addr_.host.slen = upnpIpAddr_.size();
483 0 : via_addr_.port = publishedPortUsed_;
484 0 : }
485 :
486 : template<typename T>
487 : static void
488 : validate(std::string& member, const std::string& param, const T& valid)
489 : {
490 : const auto begin = std::begin(valid);
491 : const auto end = std::end(valid);
492 : if (find(begin, end, param) != end)
493 : member = param;
494 : else
495 : JAMI_ERROR("Invalid parameter \"{:s}\"", param);
496 : }
497 :
498 : std::map<std::string, std::string>
499 54 : SIPAccount::getVolatileAccountDetails() const
500 : {
501 54 : auto a = SIPAccountBase::getVolatileAccountDetails();
502 54 : a.emplace(Conf::CONFIG_ACCOUNT_REGISTRATION_STATE_CODE,
503 108 : std::to_string(registrationStateDetailed_.first));
504 54 : a.emplace(Conf::CONFIG_ACCOUNT_REGISTRATION_STATE_DESC, registrationStateDetailed_.second);
505 54 : a.emplace(libjami::Account::VolatileProperties::InstantMessaging::OFF_CALL, TRUE_STR);
506 :
507 54 : if (presence_) {
508 54 : a.emplace(Conf::CONFIG_PRESENCE_STATUS, presence_->isOnline() ? TRUE_STR : FALSE_STR);
509 54 : a.emplace(Conf::CONFIG_PRESENCE_NOTE, presence_->getNote());
510 : }
511 :
512 54 : if (transport_ and transport_->isSecure() and transport_->isConnected()) {
513 0 : const auto& tlsInfos = transport_->getTlsInfos();
514 0 : auto cipher = pj_ssl_cipher_name(tlsInfos.cipher);
515 0 : if (tlsInfos.cipher and not cipher)
516 0 : JAMI_WARN("Unknown cipher: %d", tlsInfos.cipher);
517 0 : a.emplace(libjami::TlsTransport::TLS_CIPHER, cipher ? cipher : "");
518 0 : a.emplace(libjami::TlsTransport::TLS_PEER_CERT, tlsInfos.peerCert->toString());
519 0 : auto ca = tlsInfos.peerCert->issuer;
520 0 : unsigned n = 0;
521 0 : while (ca) {
522 0 : std::ostringstream name_str;
523 0 : name_str << libjami::TlsTransport::TLS_PEER_CA_ << n++;
524 0 : a.emplace(name_str.str(), ca->toString());
525 0 : ca = ca->issuer;
526 0 : }
527 0 : a.emplace(libjami::TlsTransport::TLS_PEER_CA_NUM, std::to_string(n));
528 0 : }
529 :
530 54 : return a;
531 0 : }
532 :
533 : bool
534 4 : SIPAccount::mapPortUPnP()
535 : {
536 : dhtnet::upnp::Mapping map(dhtnet::upnp::PortType::UDP,
537 8 : config().publishedPort,
538 4 : config().localPort);
539 4 : map.setNotifyCallback([w = weak()](dhtnet::upnp::Mapping::sharedPtr_t mapRes) {
540 3 : if (auto accPtr = w.lock()) {
541 3 : auto oldPort = static_cast<in_port_t>(accPtr->publishedPortUsed_);
542 3 : bool success = mapRes->getState() == dhtnet::upnp::MappingState::OPEN
543 3 : or mapRes->getState() == dhtnet::upnp::MappingState::IN_PROGRESS;
544 3 : auto newPort = success ? mapRes->getExternalPort() : accPtr->config().publishedPort;
545 3 : if (not success and not accPtr->isRegistered()) {
546 6 : JAMI_WARNING(
547 : "[Account {:s}] Failed to open port {}: registering SIP account anyway",
548 : accPtr->getAccountID(),
549 : oldPort);
550 2 : accPtr->doRegister1_();
551 2 : return;
552 : }
553 2 : if ((oldPort != newPort)
554 1 : or (accPtr->getRegistrationState() != RegistrationState::REGISTERED)) {
555 0 : if (not accPtr->isRegistered())
556 0 : JAMI_WARNING("[Account {:s}] SIP port {} opened: registering SIP account",
557 : accPtr->getAccountID(),
558 : newPort);
559 : else
560 0 : JAMI_WARNING(
561 : "[Account {:s}] SIP port changed to {}: re-registering SIP account",
562 : accPtr->getAccountID(),
563 : newPort);
564 0 : accPtr->publishedPortUsed_ = newPort;
565 : } else {
566 1 : accPtr->connectivityChanged();
567 : }
568 :
569 1 : accPtr->doRegister1_();
570 3 : }
571 : });
572 :
573 4 : auto mapRes = upnpCtrl_->reserveMapping(map);
574 4 : if (mapRes and mapRes->getState() == dhtnet::upnp::MappingState::OPEN) {
575 0 : return true;
576 : }
577 :
578 4 : return false;
579 4 : }
580 :
581 : bool
582 0 : SIPAccount::setPushNotificationToken(const std::string& pushDeviceToken)
583 : {
584 0 : JAMI_WARNING("[SIP Account {}] setPushNotificationToken: {}", getAccountID(), pushDeviceToken);
585 0 : if (SIPAccountBase::setPushNotificationToken(pushDeviceToken)) {
586 0 : if (config().enabled) {
587 0 : doUnregister();
588 0 : doRegister();
589 : }
590 0 : return true;
591 : }
592 0 : return false;
593 : }
594 :
595 : bool
596 0 : SIPAccount::setPushNotificationConfig(const std::map<std::string, std::string>& data)
597 : {
598 0 : if (SIPAccountBase::setPushNotificationConfig(data)) {
599 0 : if (config().enabled) {
600 0 : doUnregister();
601 0 : doRegister();
602 : }
603 0 : return true;
604 : }
605 0 : return false;
606 : }
607 :
608 : void
609 0 : SIPAccount::pushNotificationReceived(const std::string& from,
610 : const std::map<std::string, std::string>&)
611 : {
612 0 : JAMI_WARNING("[SIP Account {:s}] pushNotificationReceived: {:s}", getAccountID(), from);
613 :
614 0 : if (config().enabled) {
615 0 : doUnregister();
616 0 : doRegister();
617 : }
618 0 : }
619 :
620 : void
621 25 : SIPAccount::doRegister()
622 : {
623 25 : if (not isUsable()) {
624 0 : JAMI_WARN("Account must be enabled and active to register, ignoring");
625 0 : return;
626 : }
627 :
628 75 : JAMI_DEBUG("doRegister {:s}", config_->hostname);
629 :
630 : /* if UPnP is enabled, then wait for IGD to complete registration */
631 25 : if (upnpCtrl_) {
632 4 : JAMI_DBG("UPnP: waiting for IGD to register SIP account");
633 4 : setRegistrationState(RegistrationState::TRYING);
634 4 : if (not mapPortUPnP()) {
635 4 : JAMI_DBG("UPnP: UPNP request failed, try to register SIP account anyway");
636 4 : doRegister1_();
637 : }
638 : } else {
639 21 : doRegister1_();
640 : }
641 : }
642 :
643 : void
644 28 : SIPAccount::doRegister1_()
645 : {
646 : {
647 28 : std::lock_guard lock(configurationMutex_);
648 28 : if (isIP2IP()) {
649 23 : doRegister2_();
650 23 : return;
651 : }
652 28 : }
653 :
654 10 : link_.resolveSrvName(hasServiceRoute() ? getServiceRoute() : config().hostname,
655 5 : config().tlsEnable ? PJSIP_TRANSPORT_TLS : PJSIP_TRANSPORT_UDP,
656 5 : [w = weak()](std::vector<dhtnet::IpAddr> host_ips) {
657 5 : if (auto acc = w.lock()) {
658 : std::lock_guard lock(
659 5 : acc->configurationMutex_);
660 5 : if (host_ips.empty()) {
661 0 : JAMI_ERR("Unable to resolve hostname for registration.");
662 0 : acc->setRegistrationState(RegistrationState::ERROR_GENERIC,
663 : PJSIP_SC_NOT_FOUND);
664 0 : return;
665 : }
666 5 : acc->hostIp_ = host_ips[0];
667 5 : acc->doRegister2_();
668 10 : }
669 : });
670 : }
671 :
672 : void
673 28 : SIPAccount::doRegister2_()
674 : {
675 28 : if (not isIP2IP() and not hostIp_) {
676 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND);
677 0 : JAMI_ERROR("Hostname not resolved.");
678 23 : return;
679 : }
680 :
681 28 : dhtnet::IpAddr bindAddress = createBindingAddress();
682 28 : if (not bindAddress) {
683 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND);
684 0 : JAMI_ERROR("Unable to compute address to bind.");
685 0 : return;
686 : }
687 :
688 28 : bool ipv6 = bindAddress.isIpv6();
689 56 : transportType_ = config().tlsEnable ? (ipv6 ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS)
690 28 : : (ipv6 ? PJSIP_TRANSPORT_UDP6 : PJSIP_TRANSPORT_UDP);
691 :
692 : // Init TLS settings if the user wants to use TLS
693 28 : if (config().tlsEnable) {
694 0 : JAMI_DEBUG("TLS is enabled for account {}", accountID_);
695 :
696 : // Dropping current calls already using the transport is currently required
697 : // with TLS.
698 0 : hangupCalls();
699 0 : initTlsConfiguration();
700 :
701 0 : if (!tlsListener_) {
702 0 : tlsListener_ = link_.sipTransportBroker->getTlsListener(bindAddress, getTlsSetting());
703 0 : if (!tlsListener_) {
704 0 : setRegistrationState(RegistrationState::ERROR_GENERIC);
705 0 : JAMI_ERROR("Error creating TLS listener.");
706 0 : return;
707 : }
708 : }
709 : } else {
710 28 : tlsListener_.reset();
711 : }
712 :
713 : // In our definition of the ip2ip profile (aka Direct IP Calls),
714 : // no registration should be performed
715 28 : if (isIP2IP()) {
716 : // If we use Tls for IP2IP, transports will be created on connection.
717 23 : if (!config().tlsEnable) {
718 23 : setTransport(link_.sipTransportBroker->getUdpTransport(bindAddress));
719 : }
720 23 : setRegistrationState(RegistrationState::REGISTERED);
721 23 : return;
722 : }
723 :
724 : try {
725 15 : JAMI_WARNING("Creating transport");
726 5 : transport_.reset();
727 5 : if (isTlsEnabled()) {
728 0 : setTransport(link_.sipTransportBroker->getTlsTransport(tlsListener_,
729 0 : hostIp_,
730 0 : config().tlsServerName.empty()
731 0 : ? config().hostname
732 0 : : config().tlsServerName));
733 : } else {
734 5 : setTransport(link_.sipTransportBroker->getUdpTransport(bindAddress));
735 : }
736 5 : if (!transport_)
737 0 : throw VoipLinkException("Unable to create transport");
738 :
739 5 : sendRegister();
740 0 : } catch (const VoipLinkException& e) {
741 0 : JAMI_ERR("%s", e.what());
742 0 : setRegistrationState(RegistrationState::ERROR_GENERIC);
743 0 : return;
744 0 : }
745 :
746 5 : if (presence_ and presence_->isEnabled()) {
747 0 : presence_->subscribeClient(getFromUri(), true); // self presence subscription
748 0 : presence_->sendPresence(true, ""); // attempt to publish whatever the status is.
749 : }
750 : }
751 :
752 : void
753 25 : SIPAccount::doUnregister(bool /* forceShutdownConnections */)
754 : {
755 25 : std::unique_lock<std::recursive_mutex> lock(configurationMutex_);
756 :
757 25 : tlsListener_.reset();
758 :
759 25 : if (!isIP2IP()) {
760 : try {
761 3 : sendUnregister();
762 0 : } catch (const VoipLinkException& e) {
763 0 : JAMI_ERR("doUnregister %s", e.what());
764 0 : }
765 : }
766 :
767 25 : if (transport_)
768 25 : setTransport();
769 25 : resetAutoRegistration();
770 25 : }
771 :
772 : void
773 1 : SIPAccount::connectivityChanged()
774 : {
775 1 : if (not isUsable()) {
776 : // Nothing to do
777 0 : return;
778 : }
779 :
780 1 : doUnregister();
781 1 : if (isUsable())
782 1 : doRegister();
783 : }
784 :
785 : void
786 5 : SIPAccount::sendRegister()
787 : {
788 5 : if (not isUsable()) {
789 0 : JAMI_WARNING("[Account {}] Must be enabled and active to register, ignoring", accountID_);
790 0 : return;
791 : }
792 :
793 5 : bRegister_ = true;
794 5 : setRegistrationState(RegistrationState::TRYING);
795 :
796 5 : pjsip_regc* regc = nullptr;
797 5 : if (pjsip_regc_create(link_.getEndpoint(), (void*) this, ®istration_cb, ®c) != PJ_SUCCESS)
798 0 : throw VoipLinkException("UserAgent: Unable to create regc structure.");
799 :
800 5 : std::string srvUri(getServerUri());
801 5 : pj_str_t pjSrv {(char*) srvUri.data(), (pj_ssize_t) srvUri.size()};
802 :
803 : // Generate the FROM header
804 5 : std::string from(getFromUri());
805 5 : pj_str_t pjFrom(sip_utils::CONST_PJ_STR(from));
806 :
807 : // Get the received header
808 5 : const std::string& received(getReceivedParameter());
809 :
810 5 : std::string contact = getContactHeader();
811 :
812 15 : JAMI_LOG("[Account {}] Using contact header {} in registration", accountID_, contact);
813 :
814 5 : if (transport_) {
815 5 : if (getUPnPActive() or not getPublishedSameasLocal()
816 10 : or (not received.empty() and received != getPublishedAddress())) {
817 0 : pjsip_host_port* via = getViaAddr();
818 0 : JAMI_LOG("Setting VIA sent-by to {:s}:{:d}",
819 : sip_utils::as_view(via->host),
820 : via->port);
821 :
822 0 : if (pjsip_regc_set_via_sent_by(regc, via, transport_->get()) != PJ_SUCCESS)
823 0 : throw VoipLinkException("Unable to set the \"sent-by\" field");
824 5 : } else if (isStunEnabled()) {
825 0 : if (pjsip_regc_set_via_sent_by(regc, getViaAddr(), transport_->get()) != PJ_SUCCESS)
826 0 : throw VoipLinkException("Unable to set the \"sent-by\" field");
827 : }
828 : }
829 :
830 5 : pj_status_t status = PJ_SUCCESS;
831 5 : pj_str_t pjContact = sip_utils::CONST_PJ_STR(contact);
832 :
833 5 : if ((status
834 5 : = pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, getRegistrationExpire()))
835 5 : != PJ_SUCCESS) {
836 0 : JAMI_ERR("pjsip_regc_init failed with error %d: %s",
837 : status,
838 : sip_utils::sip_strerror(status).c_str());
839 0 : throw VoipLinkException("Unable to initialize account registration structure");
840 : }
841 :
842 5 : if (hasServiceRoute())
843 0 : pjsip_regc_set_route_set(regc,
844 0 : sip_utils::createRouteSet(getServiceRoute(), link_.getPool()));
845 :
846 5 : pjsip_regc_set_credentials(regc, getCredentialCount(), getCredInfo());
847 :
848 : pjsip_hdr hdr_list;
849 5 : pj_list_init(&hdr_list);
850 5 : auto pjUserAgent = CONST_PJ_STR(getUserAgentName());
851 5 : constexpr pj_str_t STR_USER_AGENT = CONST_PJ_STR("User-Agent");
852 :
853 5 : pjsip_generic_string_hdr* h = pjsip_generic_string_hdr_create(link_.getPool(),
854 : &STR_USER_AGENT,
855 : &pjUserAgent);
856 5 : pj_list_push_back(&hdr_list, (pjsip_hdr*) h);
857 5 : pjsip_regc_add_headers(regc, &hdr_list);
858 :
859 : pjsip_tx_data* tdata;
860 :
861 5 : if (pjsip_regc_register(regc, isRegistrationRefreshEnabled(), &tdata) != PJ_SUCCESS)
862 0 : throw VoipLinkException("Unable to initialize transaction data for account registration");
863 :
864 5 : const pjsip_tpselector tp_sel = getTransportSelector();
865 5 : if (pjsip_regc_set_transport(regc, &tp_sel) != PJ_SUCCESS)
866 0 : throw VoipLinkException("Unable to set transport");
867 :
868 5 : if (tp_sel.u.transport)
869 5 : setUpTransmissionData(tdata, tp_sel.u.transport->key.type);
870 :
871 : // pjsip_regc_send increment the transport ref count by one,
872 5 : if ((status = pjsip_regc_send(regc, tdata)) != PJ_SUCCESS) {
873 0 : JAMI_ERROR("pjsip_regc_send failed with error {:d}: {}",
874 : status,
875 : sip_utils::sip_strerror(status));
876 0 : throw VoipLinkException("Unable to send account registration request");
877 : }
878 :
879 5 : setRegistrationInfo(regc);
880 5 : }
881 :
882 : void
883 8 : SIPAccount::setUpTransmissionData(pjsip_tx_data* tdata, long transportKeyType)
884 : {
885 8 : if (hostIp_) {
886 8 : auto ai = &tdata->dest_info;
887 8 : ai->name = pj_strdup3(tdata->pool, config().hostname.c_str());
888 8 : ai->addr.count = 1;
889 8 : ai->addr.entry[0].type = (pjsip_transport_type_e) transportKeyType;
890 8 : pj_memcpy(&ai->addr.entry[0].addr, hostIp_.pjPtr(), sizeof(pj_sockaddr));
891 8 : ai->addr.entry[0].addr_len = hostIp_.getLength();
892 8 : ai->cur_addr = 0;
893 : }
894 8 : }
895 :
896 : void
897 3 : SIPAccount::onRegister(pjsip_regc_cbparam* param)
898 : {
899 3 : if (param->regc != getRegistrationInfo())
900 0 : return;
901 :
902 3 : if (param->status != PJ_SUCCESS) {
903 0 : JAMI_ERROR("[Account {}] SIP registration error {:d}",
904 : accountID_, param->status);
905 0 : destroyRegistrationInfo();
906 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, param->code);
907 3 : } else if (param->code < 0 || param->code >= 300) {
908 0 : JAMI_ERROR("[Account {}] SIP registration failed, status={:d} ({:s})",
909 : accountID_, param->code,
910 : sip_utils::as_view(param->reason));
911 0 : destroyRegistrationInfo();
912 0 : switch (param->code) {
913 0 : case PJSIP_SC_FORBIDDEN:
914 0 : setRegistrationState(RegistrationState::ERROR_AUTH, param->code);
915 0 : break;
916 0 : case PJSIP_SC_NOT_FOUND:
917 0 : setRegistrationState(RegistrationState::ERROR_HOST, param->code);
918 0 : break;
919 0 : case PJSIP_SC_REQUEST_TIMEOUT:
920 0 : setRegistrationState(RegistrationState::ERROR_HOST, param->code);
921 0 : break;
922 0 : case PJSIP_SC_SERVICE_UNAVAILABLE:
923 0 : setRegistrationState(RegistrationState::ERROR_SERVICE_UNAVAILABLE, param->code);
924 0 : break;
925 0 : default:
926 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, param->code);
927 : }
928 3 : } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
929 : // Update auto registration flag
930 3 : resetAutoRegistration();
931 :
932 3 : if (param->expiration < 1) {
933 0 : destroyRegistrationInfo();
934 0 : JAMI_DBG("Unregistration success");
935 0 : setRegistrationState(RegistrationState::UNREGISTERED, param->code);
936 : } else {
937 : /* TODO Check and update SIP outbound status first, since the result
938 : * will determine if we should update re-registration
939 : */
940 : // update_rfc5626_status(acc, param->rdata);
941 :
942 3 : if (config().allowIPAutoRewrite and checkNATAddress(param, link_.getPool()))
943 3 : JAMI_WARN("New contact: %s", getContactHeader().c_str());
944 :
945 : /* TODO Check and update Service-Route header */
946 3 : if (hasServiceRoute())
947 0 : pjsip_regc_set_route_set(param->regc,
948 0 : sip_utils::createRouteSet(getServiceRoute(),
949 0 : link_.getPool()));
950 :
951 3 : setRegistrationState(RegistrationState::REGISTERED, param->code);
952 : }
953 : }
954 :
955 : /* Check if we need to auto retry registration. Basically, registration
956 : * failure codes triggering auto-retry are those of temporal failures
957 : * considered to be recoverable in relatively short term.
958 : */
959 3 : switch (param->code) {
960 0 : case PJSIP_SC_REQUEST_TIMEOUT:
961 : case PJSIP_SC_INTERNAL_SERVER_ERROR:
962 : case PJSIP_SC_BAD_GATEWAY:
963 : case PJSIP_SC_SERVICE_UNAVAILABLE:
964 : case PJSIP_SC_SERVER_TIMEOUT:
965 0 : scheduleReregistration();
966 0 : break;
967 :
968 3 : default:
969 : /* Global failure */
970 3 : if (PJSIP_IS_STATUS_IN_CLASS(param->code, 600))
971 0 : scheduleReregistration();
972 : }
973 :
974 3 : if (param->expiration != config().registrationExpire) {
975 0 : JAMI_DBG("Registrar returned EXPIRE value [%u s] different from the requested [%u s]",
976 : param->expiration,
977 : config().registrationExpire);
978 : // NOTE: We don't alter the EXPIRE set by the user even if the registrar
979 : // returned a different value. PJSIP lib will set the proper timer for
980 : // the refresh, if the auto-regisration is enabled.
981 : }
982 : }
983 :
984 : void
985 3 : SIPAccount::sendUnregister()
986 : {
987 : // This may occurs if account failed to register and is in state INVALID
988 3 : if (!isRegistered()) {
989 0 : setRegistrationState(RegistrationState::UNREGISTERED);
990 0 : return;
991 : }
992 :
993 3 : bRegister_ = false;
994 3 : pjsip_regc* regc = getRegistrationInfo();
995 3 : if (!regc)
996 0 : throw VoipLinkException("Registration structure is NULL");
997 :
998 3 : pjsip_tx_data* tdata = nullptr;
999 3 : if (pjsip_regc_unregister(regc, &tdata) != PJ_SUCCESS)
1000 0 : throw VoipLinkException("Unable to unregister SIP account");
1001 :
1002 3 : const pjsip_tpselector tp_sel = getTransportSelector();
1003 3 : if (pjsip_regc_set_transport(regc, &tp_sel) != PJ_SUCCESS)
1004 0 : throw VoipLinkException("Unable to set transport");
1005 :
1006 3 : if (tp_sel.u.transport)
1007 3 : setUpTransmissionData(tdata, tp_sel.u.transport->key.type);
1008 :
1009 : pj_status_t status;
1010 3 : if ((status = pjsip_regc_send(regc, tdata)) != PJ_SUCCESS) {
1011 0 : JAMI_ERR("pjsip_regc_send failed with error %d: %s",
1012 : status,
1013 : sip_utils::sip_strerror(status).c_str());
1014 0 : throw VoipLinkException("Unable to send request to unregister SIP account");
1015 : }
1016 : }
1017 :
1018 : pj_uint32_t
1019 0 : SIPAccount::tlsProtocolFromString(const std::string& method)
1020 : {
1021 0 : if (method == "Default")
1022 0 : return PJSIP_SSL_DEFAULT_PROTO;
1023 0 : if (method == "TLSv1.2")
1024 0 : return PJ_SSL_SOCK_PROTO_TLS1_2;
1025 0 : if (method == "TLSv1.1")
1026 0 : return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1;
1027 0 : if (method == "TLSv1")
1028 0 : return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1 | PJ_SSL_SOCK_PROTO_TLS1;
1029 0 : return PJSIP_SSL_DEFAULT_PROTO;
1030 : }
1031 :
1032 : /**
1033 : * PJSIP aborts if our cipher list exceeds 1000 characters
1034 : */
1035 : void
1036 0 : SIPAccount::trimCiphers()
1037 : {
1038 0 : size_t sum = 0;
1039 0 : unsigned count = 0;
1040 : static const size_t MAX_CIPHERS_STRLEN = 1000;
1041 0 : for (const auto& item : ciphers_) {
1042 0 : sum += strlen(pj_ssl_cipher_name(item));
1043 0 : if (sum > MAX_CIPHERS_STRLEN)
1044 0 : break;
1045 0 : ++count;
1046 : }
1047 0 : ciphers_.resize(count);
1048 0 : }
1049 :
1050 : void
1051 0 : SIPAccount::initTlsConfiguration()
1052 : {
1053 0 : pjsip_tls_setting_default(&tlsSetting_);
1054 0 : const auto& conf = config();
1055 0 : tlsSetting_.proto = tlsProtocolFromString(conf.tlsMethod);
1056 :
1057 : // Determine the cipher list supported on this machine
1058 0 : CipherArray avail_ciphers(256);
1059 0 : unsigned cipherNum = avail_ciphers.size();
1060 0 : if (pj_ssl_cipher_get_availables(&avail_ciphers.front(), &cipherNum) != PJ_SUCCESS)
1061 0 : JAMI_ERR("Unable to determine cipher list on this system");
1062 0 : avail_ciphers.resize(cipherNum);
1063 :
1064 0 : ciphers_.clear();
1065 0 : std::string_view stream(conf.tlsCiphers), item;
1066 0 : while (jami::getline(stream, item, ' ')) {
1067 0 : std::string cipher(item);
1068 0 : auto item_cid = pj_ssl_cipher_id(cipher.c_str());
1069 0 : if (item_cid != PJ_TLS_UNKNOWN_CIPHER) {
1070 0 : JAMI_WARN("Valid cipher: %s", cipher.c_str());
1071 0 : ciphers_.push_back(item_cid);
1072 : } else
1073 0 : JAMI_ERR("Invalid cipher: %s", cipher.c_str());
1074 0 : }
1075 :
1076 0 : ciphers_.erase(std::remove_if(ciphers_.begin(),
1077 : ciphers_.end(),
1078 0 : [&](pj_ssl_cipher c) {
1079 0 : return std::find(avail_ciphers.cbegin(),
1080 : avail_ciphers.cend(),
1081 : c)
1082 0 : == avail_ciphers.cend();
1083 : }),
1084 0 : ciphers_.end());
1085 :
1086 0 : trimCiphers();
1087 :
1088 0 : tlsSetting_.ca_list_file = CONST_PJ_STR(conf.tlsCaListFile);
1089 0 : tlsSetting_.cert_file = CONST_PJ_STR(conf.tlsCaListFile);
1090 0 : tlsSetting_.privkey_file = CONST_PJ_STR(conf.tlsPrivateKeyFile);
1091 0 : tlsSetting_.password = CONST_PJ_STR(conf.tlsPassword);
1092 :
1093 0 : JAMI_DBG("Using %zu ciphers", ciphers_.size());
1094 0 : tlsSetting_.ciphers_num = ciphers_.size();
1095 0 : if (tlsSetting_.ciphers_num > 0) {
1096 0 : tlsSetting_.ciphers = &ciphers_.front();
1097 : }
1098 :
1099 0 : tlsSetting_.verify_server = conf.tlsVerifyServer;
1100 0 : tlsSetting_.verify_client = conf.tlsVerifyClient;
1101 0 : tlsSetting_.require_client_cert = conf.tlsRequireClientCertificate;
1102 0 : pjsip_cfg()->endpt.disable_secure_dlg_check = conf.tlsDisableSecureDlgCheck;
1103 0 : tlsSetting_.timeout.sec = conf.tlsNegotiationTimeout;
1104 :
1105 0 : tlsSetting_.qos_type = PJ_QOS_TYPE_BEST_EFFORT;
1106 0 : tlsSetting_.qos_ignore_error = PJ_TRUE;
1107 0 : }
1108 :
1109 : void
1110 24 : SIPAccount::initStunConfiguration()
1111 : {
1112 24 : std::string_view stunServer(config().stunServer);
1113 24 : auto pos = stunServer.find(':');
1114 24 : if (pos == std::string_view::npos) {
1115 24 : stunServerName_ = sip_utils::CONST_PJ_STR(stunServer);
1116 24 : stunPort_ = PJ_STUN_PORT;
1117 : } else {
1118 0 : stunServerName_ = sip_utils::CONST_PJ_STR(stunServer.substr(0, pos));
1119 0 : auto serverPort = stunServer.substr(pos + 1);
1120 0 : stunPort_ = to_int<uint16_t>(serverPort);
1121 : }
1122 24 : }
1123 :
1124 : void
1125 24 : SIPAccount::loadConfig()
1126 : {
1127 24 : SIPAccountBase::loadConfig();
1128 24 : setCredentials(config().credentials);
1129 24 : enablePresence(config().presenceEnabled);
1130 24 : initStunConfiguration();
1131 24 : if (config().tlsEnable) {
1132 0 : initTlsConfiguration();
1133 0 : transportType_ = PJSIP_TRANSPORT_TLS;
1134 : } else
1135 24 : transportType_ = PJSIP_TRANSPORT_UDP;
1136 24 : if (registrationState_ == RegistrationState::UNLOADED)
1137 24 : setRegistrationState(RegistrationState::UNREGISTERED);
1138 24 : }
1139 :
1140 : bool
1141 33 : SIPAccount::fullMatch(std::string_view username, std::string_view hostname) const
1142 : {
1143 33 : return userMatch(username) and hostnameMatch(hostname);
1144 : }
1145 :
1146 : bool
1147 57 : SIPAccount::userMatch(std::string_view username) const
1148 : {
1149 57 : return !username.empty() and username == config().username;
1150 : }
1151 :
1152 : bool
1153 39 : SIPAccount::hostnameMatch(std::string_view hostname) const
1154 : {
1155 39 : if (hostname == config().hostname)
1156 9 : return true;
1157 30 : const auto a = dhtnet::ip_utils::getAddrList(hostname);
1158 30 : const auto b = dhtnet::ip_utils::getAddrList(config().hostname);
1159 30 : return dhtnet::ip_utils::haveCommonAddr(a, b);
1160 30 : }
1161 :
1162 : bool
1163 18 : SIPAccount::proxyMatch(std::string_view hostname) const
1164 : {
1165 18 : if (hostname == config().serviceRoute)
1166 0 : return true;
1167 18 : const auto a = dhtnet::ip_utils::getAddrList(hostname);
1168 18 : const auto b = dhtnet::ip_utils::getAddrList(config().hostname);
1169 18 : return dhtnet::ip_utils::haveCommonAddr(a, b);
1170 18 : }
1171 :
1172 : std::string
1173 3 : SIPAccount::getLoginName()
1174 : {
1175 : #ifndef _WIN32
1176 3 : struct passwd* user_info = getpwuid(getuid());
1177 3 : return user_info ? user_info->pw_name : "";
1178 : #else
1179 : DWORD size = UNLEN + 1;
1180 : TCHAR username[UNLEN + 1];
1181 : std::string uname;
1182 : if (GetUserName((TCHAR*) username, &size)) {
1183 : uname = jami::to_string(username);
1184 : }
1185 : return uname;
1186 : #endif
1187 : }
1188 :
1189 : std::string
1190 15 : SIPAccount::getFromUri() const
1191 : {
1192 15 : std::string scheme;
1193 15 : std::string transport;
1194 :
1195 : // Get login name if username is not specified
1196 15 : const auto& conf = config();
1197 15 : std::string username(conf.username.empty() ? getLoginName() : conf.username);
1198 15 : std::string hostname(conf.hostname);
1199 :
1200 : // UDP does not require the transport specification
1201 15 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1202 0 : scheme = "sips:";
1203 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1204 : } else
1205 15 : scheme = "sip:";
1206 :
1207 : // Get machine hostname if not provided
1208 15 : if (hostname.empty()) {
1209 9 : hostname = sip_utils::as_view(*pj_gethostname());
1210 : }
1211 :
1212 15 : if (dhtnet::IpAddr::isIpv6(hostname))
1213 0 : hostname = dhtnet::IpAddr(hostname).toString(false, true);
1214 :
1215 30 : std::string uri = "<" + scheme + username + "@" + hostname + transport + ">";
1216 15 : if (not conf.displayName.empty())
1217 30 : return "\"" + conf.displayName + "\" " + uri;
1218 0 : return uri;
1219 15 : }
1220 :
1221 : std::string
1222 21 : SIPAccount::getToUri(const std::string& username) const
1223 : {
1224 21 : std::string scheme;
1225 21 : std::string transport;
1226 21 : std::string hostname;
1227 :
1228 : // UDP does not require the transport specification
1229 21 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1230 0 : scheme = "sips:";
1231 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1232 : } else
1233 21 : scheme = "sip:";
1234 :
1235 : // Check if scheme is already specified
1236 21 : if (username.find("sip") != std::string::npos)
1237 1 : scheme = "";
1238 :
1239 : // Check if hostname is already specified
1240 21 : if (username.find('@') == std::string::npos)
1241 4 : hostname = config().hostname;
1242 :
1243 21 : if (not hostname.empty() and dhtnet::IpAddr::isIpv6(hostname))
1244 0 : hostname = dhtnet::IpAddr(hostname).toString(false, true);
1245 :
1246 21 : auto ltSymbol = username.find('<') == std::string::npos ? "<" : "";
1247 21 : auto gtSymbol = username.find('>') == std::string::npos ? ">" : "";
1248 :
1249 42 : return ltSymbol + scheme + username + (hostname.empty() ? "" : "@") + hostname + transport
1250 42 : + gtSymbol;
1251 21 : }
1252 :
1253 : std::string
1254 5 : SIPAccount::getServerUri() const
1255 : {
1256 5 : std::string scheme;
1257 5 : std::string transport;
1258 :
1259 : // UDP does not require the transport specification
1260 5 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1261 0 : scheme = "sips:";
1262 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1263 : } else {
1264 5 : scheme = "sip:";
1265 : }
1266 :
1267 5 : std::string host;
1268 5 : if (dhtnet::IpAddr::isIpv6(config().hostname))
1269 0 : host = dhtnet::IpAddr(config().hostname).toString(false, true);
1270 : else
1271 5 : host = config().hostname;
1272 :
1273 15 : return "<" + scheme + host + transport + ">";
1274 5 : }
1275 :
1276 : dhtnet::IpAddr
1277 3 : SIPAccount::getContactAddress() const
1278 : {
1279 3 : std::lock_guard lock(contactMutex_);
1280 3 : return contactAddress_;
1281 3 : }
1282 :
1283 : std::string
1284 41 : SIPAccount::getContactHeader() const
1285 : {
1286 41 : std::lock_guard lock(contactMutex_);
1287 82 : return contactHeader_;
1288 41 : }
1289 :
1290 : void
1291 27 : SIPAccount::updateContactHeader()
1292 : {
1293 27 : std::lock_guard lock(contactMutex_);
1294 :
1295 27 : if (not transport_ or not transport_->get()) {
1296 0 : JAMI_ERR("Transport not created yet");
1297 0 : return;
1298 : }
1299 :
1300 27 : if (not contactAddress_) {
1301 0 : JAMI_ERR("Invalid contact address: %s", contactAddress_.toString(true).c_str());
1302 0 : return;
1303 : }
1304 :
1305 54 : auto contactHdr = printContactHeader(config().username,
1306 27 : config().displayName,
1307 0 : contactAddress_.toString(false, true),
1308 54 : contactAddress_.getPort(),
1309 27 : PJSIP_TRANSPORT_IS_SECURE(transport_->get()),
1310 81 : config().deviceKey);
1311 :
1312 27 : contactHeader_ = std::move(contactHdr);
1313 27 : }
1314 :
1315 : bool
1316 27 : SIPAccount::initContactAddress()
1317 : {
1318 : // This method tries to determine the address to be used in the
1319 : // contact header using the available information (current transport,
1320 : // UPNP, STUN, …). The contact address may be updated after the
1321 : // registration using information sent by the registrar in the SIP
1322 : // messages (see checkNATAddress).
1323 :
1324 27 : if (not transport_ or not transport_->get()) {
1325 0 : JAMI_ERR("Transport not created yet");
1326 0 : return {};
1327 : }
1328 :
1329 : // The transport type must be specified, in our case START_OTHER refers to stun transport
1330 27 : pjsip_transport_type_e transportType = transportType_;
1331 :
1332 27 : if (transportType == PJSIP_TRANSPORT_START_OTHER)
1333 0 : transportType = PJSIP_TRANSPORT_UDP;
1334 :
1335 27 : std::string address;
1336 : pj_uint16_t port;
1337 :
1338 : // Init the address to the local address.
1339 27 : link_.findLocalAddressFromTransport(transport_->get(),
1340 : transportType,
1341 27 : config().hostname,
1342 : address,
1343 : port);
1344 :
1345 27 : if (getUPnPActive() and getUPnPIpAddress()) {
1346 0 : address = getUPnPIpAddress().toString();
1347 0 : port = publishedPortUsed_;
1348 0 : useUPnPAddressPortInVIA();
1349 0 : JAMI_DBG("Using UPnP address %s and port %d", address.c_str(), port);
1350 27 : } else if (not config().publishedSameasLocal) {
1351 0 : address = getPublishedIpAddress().toString();
1352 0 : port = config().publishedPort;
1353 0 : JAMI_DBG("Using published address %s and port %d", address.c_str(), port);
1354 27 : } else if (config().stunEnabled) {
1355 0 : auto success = link_.findLocalAddressFromSTUN(transport_->get(),
1356 : &stunServerName_,
1357 0 : stunPort_,
1358 : address,
1359 : port);
1360 0 : if (not success)
1361 0 : emitSignal<libjami::ConfigurationSignal::StunStatusFailed>(getAccountID());
1362 0 : setPublishedAddress({address});
1363 0 : publishedPortUsed_ = port;
1364 0 : usePublishedAddressPortInVIA();
1365 : } else {
1366 27 : if (!receivedParameter_.empty()) {
1367 0 : address = receivedParameter_;
1368 0 : JAMI_DBG("Using received address %s", address.c_str());
1369 : }
1370 :
1371 27 : if (rPort_ > 0) {
1372 0 : port = rPort_;
1373 0 : JAMI_DBG("Using received port %d", port);
1374 : }
1375 : }
1376 :
1377 27 : std::lock_guard lock(contactMutex_);
1378 27 : contactAddress_ = dhtnet::IpAddr(address);
1379 27 : contactAddress_.setPort(port);
1380 :
1381 27 : return contactAddress_;
1382 27 : }
1383 :
1384 : std::string
1385 30 : SIPAccount::printContactHeader(const std::string& username,
1386 : const std::string& displayName,
1387 : const std::string& address,
1388 : pj_uint16_t port,
1389 : bool secure,
1390 : const std::string& deviceKey)
1391 : {
1392 : // This method generates SIP contact header field, with push
1393 : // notification parameters if any.
1394 : // Example without push notification:
1395 : // John Doe<sips:jdoe@10.10.10.10:5060;transport=tls>
1396 : // Example with push notification:
1397 : // John Doe<sips:jdoe@10.10.10.10:5060;transport=tls;pn-provider=XXX;pn-param=YYY;pn-prid=ZZZ>
1398 :
1399 59 : std::string quotedDisplayName = displayName.empty() ? "" : "\"" + displayName + "\" ";
1400 :
1401 30 : std::ostringstream contact;
1402 30 : auto scheme = secure ? "sips" : "sip";
1403 30 : auto transport = secure ? ";transport=tls" : "";
1404 :
1405 : contact << quotedDisplayName << "<" << scheme << ":" << username
1406 30 : << (username.empty() ? "" : "@") << address << ":" << port << transport;
1407 :
1408 30 : if (not deviceKey.empty()) {
1409 : contact
1410 : #if defined(__ANDROID__)
1411 : << ";pn-provider=" << PN_FCM
1412 : #elif defined(__Apple__)
1413 : << ";pn-provider=" << PN_APNS
1414 : #endif
1415 : << ";pn-param="
1416 0 : << ";pn-prid=" << deviceKey;
1417 : }
1418 30 : contact << ">";
1419 :
1420 60 : return contact.str();
1421 30 : }
1422 :
1423 : pjsip_host_port
1424 0 : SIPAccount::getHostPortFromSTUN(pj_pool_t* pool)
1425 : {
1426 0 : std::string addr;
1427 : pj_uint16_t port;
1428 0 : auto success = link_.findLocalAddressFromSTUN(transport_ ? transport_->get() : nullptr,
1429 : &stunServerName_,
1430 0 : stunPort_,
1431 : addr,
1432 : port);
1433 0 : if (not success)
1434 0 : emitSignal<libjami::ConfigurationSignal::StunStatusFailed>(getAccountID());
1435 : pjsip_host_port result;
1436 0 : pj_strdup2(pool, &result.host, addr.c_str());
1437 0 : result.port = port;
1438 0 : return result;
1439 0 : }
1440 :
1441 : const std::vector<std::string>&
1442 0 : SIPAccount::getSupportedTlsCiphers()
1443 : {
1444 : // Currently, both OpenSSL and GNUTLS implementations are static
1445 : // reloading this for each account is unnecessary
1446 0 : static std::vector<std::string> availCiphers {};
1447 :
1448 : // LIMITATION Assume the size might change, if there aren't any ciphers,
1449 : // this will cause the cache to be repopulated at each call for nothing.
1450 0 : if (availCiphers.empty()) {
1451 0 : unsigned cipherNum = 256;
1452 0 : CipherArray avail_ciphers(cipherNum);
1453 0 : if (pj_ssl_cipher_get_availables(&avail_ciphers.front(), &cipherNum) != PJ_SUCCESS)
1454 0 : JAMI_ERR("Unable to determine cipher list on this system");
1455 0 : avail_ciphers.resize(cipherNum);
1456 0 : availCiphers.reserve(cipherNum);
1457 0 : for (const auto& item : avail_ciphers) {
1458 0 : if (item > 0) // 0 doesn't have a name
1459 0 : availCiphers.push_back(pj_ssl_cipher_name(item));
1460 : }
1461 0 : }
1462 0 : return availCiphers;
1463 : }
1464 :
1465 : const std::vector<std::string>&
1466 0 : SIPAccount::getSupportedTlsProtocols()
1467 : {
1468 : static std::vector<std::string> availProtos {VALID_TLS_PROTOS,
1469 0 : VALID_TLS_PROTOS + std::size(VALID_TLS_PROTOS)};
1470 0 : return availProtos;
1471 : }
1472 :
1473 : void
1474 24 : SIPAccount::setCredentials(const std::vector<SipAccountConfig::Credentials>& creds)
1475 : {
1476 24 : cred_.clear();
1477 24 : cred_.reserve(creds.size());
1478 24 : bool md5HashingEnabled = Manager::instance().preferences.getMd5Hash();
1479 :
1480 48 : for (auto& c : creds) {
1481 24 : cred_.emplace_back(
1482 48 : pjsip_cred_info {/*.realm = */ CONST_PJ_STR(c.realm),
1483 : /*.scheme = */ CONST_PJ_STR("digest"),
1484 24 : /*.username = */ CONST_PJ_STR(c.username),
1485 : /*.data_type = */
1486 24 : (md5HashingEnabled ? PJSIP_CRED_DATA_DIGEST
1487 : : PJSIP_CRED_DATA_PLAIN_PASSWD),
1488 : /*.data = */
1489 24 : CONST_PJ_STR(md5HashingEnabled ? c.password_h : c.password),
1490 : /*.ext = */ {}});
1491 : }
1492 24 : }
1493 :
1494 : void
1495 59 : SIPAccount::setRegistrationState(RegistrationState state,
1496 : int details_code,
1497 : const std::string& /*detail_str*/)
1498 : {
1499 59 : std::string details_str;
1500 59 : const pj_str_t* description = pjsip_get_status_text(details_code);
1501 59 : if (description)
1502 59 : details_str = sip_utils::as_view(*description);
1503 59 : registrationStateDetailed_ = {details_code, details_str};
1504 59 : SIPAccountBase::setRegistrationState(state, details_code, details_str);
1505 59 : }
1506 :
1507 : bool
1508 182 : SIPAccount::isIP2IP() const
1509 : {
1510 182 : return config().hostname.empty();
1511 : }
1512 :
1513 : SIPPresence*
1514 0 : SIPAccount::getPresence() const
1515 : {
1516 0 : return presence_;
1517 : }
1518 :
1519 : /**
1520 : * Enable the presence module
1521 : */
1522 : void
1523 24 : SIPAccount::enablePresence(const bool& enabled)
1524 : {
1525 24 : if (!presence_) {
1526 0 : JAMI_ERR("Presence not initialized");
1527 0 : return;
1528 : }
1529 :
1530 72 : JAMI_LOG("[Account {}] Presence enabled: {}.", accountID_, enabled ? TRUE_STR : FALSE_STR);
1531 :
1532 24 : presence_->enable(enabled);
1533 : }
1534 :
1535 : /**
1536 : * Set the presence (PUBLISH/SUBSCRIBE) support flags
1537 : * and process the change.
1538 : */
1539 : void
1540 0 : SIPAccount::supportPresence(int function, bool enabled)
1541 : {
1542 0 : if (!presence_) {
1543 0 : JAMI_ERR("Presence not initialized");
1544 0 : return;
1545 : }
1546 :
1547 0 : if (presence_->isSupported(function) == enabled)
1548 0 : return;
1549 :
1550 0 : JAMI_LOG("[Account {}] Presence support ({}: {}).",
1551 : accountID_,
1552 : function == PRESENCE_FUNCTION_PUBLISH ? "publish" : "subscribe",
1553 : enabled ? TRUE_STR : FALSE_STR);
1554 0 : presence_->support(function, enabled);
1555 :
1556 : // force presence to disable when nothing is supported
1557 0 : if (not presence_->isSupported(PRESENCE_FUNCTION_PUBLISH)
1558 0 : and not presence_->isSupported(PRESENCE_FUNCTION_SUBSCRIBE))
1559 0 : enablePresence(false);
1560 :
1561 0 : Manager::instance().saveConfig();
1562 : // FIXME: bad signal used here, we need a global config changed signal.
1563 0 : emitSignal<libjami::ConfigurationSignal::AccountsChanged>();
1564 : }
1565 :
1566 : MatchRank
1567 33 : SIPAccount::matches(std::string_view userName, std::string_view server) const
1568 : {
1569 33 : if (fullMatch(userName, server)) {
1570 18 : JAMI_LOG("Matching account ID in request is a fullmatch {:s}@{:s}",
1571 : userName,
1572 : server);
1573 6 : return MatchRank::FULL;
1574 27 : } else if (hostnameMatch(server)) {
1575 9 : JAMI_LOG("Matching account ID in request with hostname {:s}", server);
1576 3 : return MatchRank::PARTIAL;
1577 24 : } else if (userMatch(userName)) {
1578 18 : JAMI_LOG("Matching account ID in request with username {:s}", userName);
1579 6 : return MatchRank::PARTIAL;
1580 18 : } else if (proxyMatch(server)) {
1581 0 : JAMI_LOG("Matching account ID in request with proxy {:s}", server);
1582 0 : return MatchRank::PARTIAL;
1583 : } else {
1584 18 : return MatchRank::NONE;
1585 : }
1586 : }
1587 :
1588 : void
1589 27 : SIPAccount::destroyRegistrationInfo()
1590 : {
1591 27 : if (!regc_)
1592 22 : return;
1593 5 : pjsip_regc_destroy(regc_);
1594 5 : regc_ = nullptr;
1595 : }
1596 :
1597 : void
1598 28 : SIPAccount::resetAutoRegistration()
1599 : {
1600 28 : auto_rereg_.active = PJ_FALSE;
1601 28 : auto_rereg_.attempt_cnt = 0;
1602 28 : if (auto_rereg_.timer.user_data) {
1603 0 : delete ((std::weak_ptr<SIPAccount>*) auto_rereg_.timer.user_data);
1604 0 : auto_rereg_.timer.user_data = nullptr;
1605 : }
1606 28 : }
1607 :
1608 : bool
1609 3 : SIPAccount::checkNATAddress(pjsip_regc_cbparam* param, pj_pool_t* pool)
1610 : {
1611 9 : JAMI_LOG("[Account {}] Checking IP route after the registration", accountID_);
1612 :
1613 3 : pjsip_transport* tp = param->rdata->tp_info.transport;
1614 :
1615 : /* Get the received and rport info */
1616 3 : pjsip_via_hdr* via = param->rdata->msg_info.via;
1617 3 : int rport = 0;
1618 3 : if (via->rport_param < 1) {
1619 : /* Remote doesn't support rport */
1620 0 : rport = via->sent_by.port;
1621 0 : if (rport == 0) {
1622 : pjsip_transport_type_e tp_type;
1623 0 : tp_type = (pjsip_transport_type_e) tp->key.type;
1624 0 : rport = pjsip_transport_get_default_port_for_type(tp_type);
1625 : }
1626 : } else {
1627 3 : rport = via->rport_param;
1628 : }
1629 :
1630 3 : const pj_str_t* via_addr = via->recvd_param.slen != 0 ? &via->recvd_param : &via->sent_by.host;
1631 3 : std::string via_addrstr(sip_utils::as_view(*via_addr));
1632 : /* Enclose IPv6 address in square brackets */
1633 3 : if (dhtnet::IpAddr::isIpv6(via_addrstr))
1634 0 : via_addrstr = dhtnet::IpAddr(via_addrstr).toString(false, true);
1635 :
1636 3 : JAMI_DBG("Checking received VIA address: %s", via_addrstr.c_str());
1637 :
1638 3 : if (via_addr_.host.slen == 0 or via_tp_ != tp) {
1639 2 : if (pj_strcmp(&via_addr_.host, via_addr))
1640 2 : pj_strdup(pool, &via_addr_.host, via_addr);
1641 :
1642 : // Update Via header
1643 2 : via_addr_.port = rport;
1644 2 : via_tp_ = tp;
1645 2 : pjsip_regc_set_via_sent_by(regc_, &via_addr_, via_tp_);
1646 : }
1647 :
1648 : // Set published Ip address
1649 3 : setPublishedAddress(dhtnet::IpAddr(via_addrstr));
1650 :
1651 : /* Compare received and rport with the URI in our registration */
1652 3 : dhtnet::IpAddr contact_addr = getContactAddress();
1653 :
1654 : // TODO. Why note save the port in contact URI/header?
1655 3 : if (contact_addr.getPort() == 0) {
1656 : pjsip_transport_type_e tp_type;
1657 0 : tp_type = (pjsip_transport_type_e) tp->key.type;
1658 0 : contact_addr.setPort(pjsip_transport_get_default_port_for_type(tp_type));
1659 : }
1660 :
1661 : /* Convert IP address strings into sockaddr for comparison.
1662 : * (http://trac.pjsip.org/repos/ticket/863)
1663 : */
1664 3 : bool matched = false;
1665 3 : dhtnet::IpAddr recv_addr {};
1666 3 : auto status = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, via_addr, recv_addr.pjPtr());
1667 3 : recv_addr.setPort(rport);
1668 3 : if (status == PJ_SUCCESS) {
1669 : // Compare the addresses as sockaddr according to the ticket above
1670 3 : matched = contact_addr == recv_addr;
1671 : } else {
1672 : // Compare the addresses as string, as before
1673 0 : auto pjContactAddr = sip_utils::CONST_PJ_STR(contact_addr.toString());
1674 0 : matched = (contact_addr.getPort() == rport and pj_stricmp(&pjContactAddr, via_addr) == 0);
1675 : }
1676 :
1677 3 : if (matched) {
1678 : // Address doesn't change
1679 0 : return false;
1680 : }
1681 :
1682 : /* Get server IP address */
1683 3 : dhtnet::IpAddr srv_ip = {std::string_view(param->rdata->pkt_info.src_name)};
1684 :
1685 : /* At this point we've detected that the address as seen by registrar.
1686 : * has changed.
1687 : */
1688 :
1689 : /* Do not switch if both Contact and server's IP address are
1690 : * public but response contains private IP. A NAT in the middle
1691 : * might have messed up with the SIP packets. See:
1692 : * http://trac.pjsip.org/repos/ticket/643
1693 : *
1694 : * This exception can be disabled by setting allow_contact_rewrite
1695 : * to 2. In this case, the switch will always be done whenever there
1696 : * is difference in the IP address in the response.
1697 : */
1698 3 : if (not contact_addr.isPrivate() and not srv_ip.isPrivate() and recv_addr.isPrivate()) {
1699 : /* Don't switch */
1700 0 : return false;
1701 : }
1702 :
1703 : /* Also don't switch if only the port number part is different, and
1704 : * the Via received address is private.
1705 : * See http://trac.pjsip.org/repos/ticket/864
1706 : */
1707 3 : if (contact_addr == recv_addr and recv_addr.isPrivate()) {
1708 : /* Don't switch */
1709 0 : return false;
1710 : }
1711 :
1712 3 : JAMI_WARN("[account %s] Contact address changed: "
1713 : "(%s → %s:%d). Updating registration.",
1714 : accountID_.c_str(),
1715 : contact_addr.toString(true).c_str(),
1716 : via_addrstr.data(),
1717 : rport);
1718 :
1719 : /*
1720 : * Build new Contact header
1721 : */
1722 : {
1723 6 : auto tempContact = printContactHeader(config().username,
1724 3 : config().displayName,
1725 : via_addrstr,
1726 : rport,
1727 3 : PJSIP_TRANSPORT_IS_SECURE(tp),
1728 6 : config().deviceKey);
1729 :
1730 3 : if (tempContact.empty()) {
1731 0 : JAMI_ERR("Invalid contact header");
1732 0 : return false;
1733 : }
1734 :
1735 : // Update
1736 3 : std::lock_guard lock(contactMutex_);
1737 3 : contactHeader_ = std::move(tempContact);
1738 3 : }
1739 :
1740 3 : if (regc_ != nullptr) {
1741 3 : auto contactHdr = getContactHeader();
1742 3 : auto pjContact = sip_utils::CONST_PJ_STR(contactHdr);
1743 3 : pjsip_regc_update_contact(regc_, 1, &pjContact);
1744 :
1745 : /* Perform new registration at the next registration cycle */
1746 3 : }
1747 :
1748 3 : return true;
1749 3 : }
1750 :
1751 : /* Auto re-registration timeout callback */
1752 : void
1753 0 : SIPAccount::autoReregTimerCb()
1754 : {
1755 : /* Check if the re-registration timer is still valid, e.g: while waiting
1756 : * timeout timer application might have deleted the account or disabled
1757 : * the auto-reregistration.
1758 : */
1759 0 : if (not auto_rereg_.active)
1760 0 : return;
1761 :
1762 : /* Start re-registration */
1763 0 : ++auto_rereg_.attempt_cnt;
1764 : try {
1765 : // If attempt_count was 0, we should call doRegister to reset transports if needed.
1766 0 : if (auto_rereg_.attempt_cnt == 1)
1767 0 : doRegister();
1768 : else
1769 0 : sendRegister();
1770 0 : } catch (const VoipLinkException& e) {
1771 0 : JAMI_ERR("Exception during SIP registration: %s", e.what());
1772 0 : scheduleReregistration();
1773 0 : }
1774 : }
1775 :
1776 : /* Schedule reregistration for specified account. Note that the first
1777 : * re-registration after a registration failure will be done immediately.
1778 : * Also note that this function should be called within PJSUA mutex.
1779 : */
1780 : void
1781 0 : SIPAccount::scheduleReregistration()
1782 : {
1783 0 : if (!isUsable())
1784 0 : return;
1785 :
1786 : /* Cancel any re-registration timer */
1787 0 : if (auto_rereg_.timer.id) {
1788 0 : auto_rereg_.timer.id = PJ_FALSE;
1789 0 : pjsip_endpt_cancel_timer(link_.getEndpoint(), &auto_rereg_.timer);
1790 : }
1791 :
1792 : /* Update re-registration flag */
1793 0 : auto_rereg_.active = PJ_TRUE;
1794 :
1795 : /* Set up timer for reregistration */
1796 0 : auto_rereg_.timer.cb = [](pj_timer_heap_t* /*th*/, pj_timer_entry* te) {
1797 0 : if (auto sipAccount = static_cast<std::weak_ptr<SIPAccount>*>(te->user_data)->lock())
1798 0 : sipAccount->autoReregTimerCb();
1799 0 : };
1800 0 : if (not auto_rereg_.timer.user_data)
1801 0 : auto_rereg_.timer.user_data = new std::weak_ptr<SIPAccount>(weak());
1802 :
1803 : /* Reregistration attempt. The first attempt will be done sooner */
1804 : pj_time_val delay;
1805 0 : delay.sec = auto_rereg_.attempt_cnt ? REGISTRATION_RETRY_INTERVAL
1806 : : REGISTRATION_FIRST_RETRY_INTERVAL;
1807 0 : delay.msec = 0;
1808 :
1809 : /* Randomize interval by ±10 secs */
1810 0 : if (delay.sec >= 10) {
1811 0 : delay.msec = delay10ZeroDist_(rand);
1812 : } else {
1813 0 : delay.sec = 0;
1814 0 : delay.msec = delay10PosDist_(rand);
1815 : }
1816 :
1817 0 : pj_time_val_normalize(&delay);
1818 :
1819 0 : JAMI_WARNING("Scheduling re-registration attempt in {:d} second(s)…", delay.sec);
1820 0 : auto_rereg_.timer.id = PJ_TRUE;
1821 0 : if (pjsip_endpt_schedule_timer(link_.getEndpoint(), &auto_rereg_.timer, &delay) != PJ_SUCCESS)
1822 0 : auto_rereg_.timer.id = PJ_FALSE;
1823 : }
1824 :
1825 : void
1826 10 : SIPAccount::updateDialogViaSentBy(pjsip_dialog* dlg)
1827 : {
1828 10 : if (config().allowIPAutoRewrite && via_addr_.host.slen > 0)
1829 1 : pjsip_dlg_set_via_sent_by(dlg, &via_addr_, via_tp_);
1830 10 : }
1831 :
1832 : #if 0
1833 : /**
1834 : * Create Accept header for MESSAGE.
1835 : */
1836 : static pjsip_accept_hdr* im_create_accept(pj_pool_t *pool)
1837 : {
1838 : /* Create Accept header. */
1839 : pjsip_accept_hdr *accept;
1840 :
1841 : accept = pjsip_accept_hdr_create(pool);
1842 : accept->values[0] = CONST_PJ_STR("text/plain");
1843 : accept->values[1] = CONST_PJ_STR("application/im-iscomposing+xml");
1844 : accept->count = 2;
1845 :
1846 : return accept;
1847 : }
1848 : #endif
1849 :
1850 : void
1851 0 : SIPAccount::sendMessage(const std::string& to,
1852 : const std::string&,
1853 : const std::map<std::string, std::string>& payloads,
1854 : uint64_t id,
1855 : bool,
1856 : bool)
1857 : {
1858 0 : if (to.empty() or payloads.empty()) {
1859 0 : JAMI_WARN("No sender or payload");
1860 0 : messageEngine_.onMessageSent(to, id, false);
1861 0 : return;
1862 : }
1863 :
1864 0 : auto toUri = getToUri(to);
1865 :
1866 0 : constexpr pjsip_method msg_method = {PJSIP_OTHER_METHOD,
1867 : CONST_PJ_STR(sip_utils::SIP_METHODS::MESSAGE)};
1868 0 : std::string from(getFromUri());
1869 0 : pj_str_t pjFrom = sip_utils::CONST_PJ_STR(from);
1870 0 : pj_str_t pjTo = sip_utils::CONST_PJ_STR(toUri);
1871 :
1872 : /* Create request. */
1873 : pjsip_tx_data* tdata;
1874 0 : pj_status_t status = pjsip_endpt_create_request(link_.getEndpoint(),
1875 : &msg_method,
1876 : &pjTo,
1877 : &pjFrom,
1878 : &pjTo,
1879 : nullptr,
1880 : nullptr,
1881 : -1,
1882 : nullptr,
1883 : &tdata);
1884 0 : if (status != PJ_SUCCESS) {
1885 0 : JAMI_ERROR("Unable to create request: {:s}", sip_utils::sip_strerror(status));
1886 0 : messageEngine_.onMessageSent(to, id, false);
1887 0 : return;
1888 : }
1889 :
1890 : /* Add Date Header. */
1891 : pj_str_t date_str;
1892 0 : constexpr auto key = CONST_PJ_STR("Date");
1893 : pjsip_hdr* hdr;
1894 0 : auto time = std::time(nullptr);
1895 0 : auto date = std::ctime(&time);
1896 : // the erase-remove idiom for a Cstring, removes _all_ new lines with in date
1897 0 : *std::remove(date, date + strlen(date), '\n') = '\0';
1898 :
1899 : // Add Header
1900 : hdr = reinterpret_cast<pjsip_hdr*>(
1901 0 : pjsip_date_hdr_create(tdata->pool, &key, pj_cstr(&date_str, date)));
1902 0 : pjsip_msg_add_hdr(tdata->msg, hdr);
1903 :
1904 : // Add user-agent header
1905 0 : sip_utils::addUserAgentHeader(getUserAgentName(), tdata);
1906 :
1907 : // Set input token into callback
1908 0 : std::unique_ptr<ctx> t {new ctx(new pjsip_auth_clt_sess)};
1909 0 : t->acc = shared();
1910 0 : t->to = to;
1911 0 : t->id = id;
1912 :
1913 : /* Initialize Auth header. */
1914 0 : status = pjsip_auth_clt_init(t->auth_sess.get(), link_.getEndpoint(), tdata->pool, 0);
1915 :
1916 0 : if (status != PJ_SUCCESS) {
1917 0 : JAMI_ERROR("Unable to initialize auth session: {:s}", sip_utils::sip_strerror(status));
1918 0 : messageEngine_.onMessageSent(to, id, false);
1919 0 : return;
1920 : }
1921 :
1922 0 : status = pjsip_auth_clt_set_credentials(t->auth_sess.get(), getCredentialCount(), getCredInfo());
1923 :
1924 0 : if (status != PJ_SUCCESS) {
1925 0 : JAMI_ERROR("Unable to set auth session data: {:s}", sip_utils::sip_strerror(status));
1926 0 : messageEngine_.onMessageSent(to, id, false);
1927 0 : return;
1928 : }
1929 :
1930 0 : const pjsip_tpselector tp_sel = getTransportSelector();
1931 0 : status = pjsip_tx_data_set_transport(tdata, &tp_sel);
1932 :
1933 0 : if (status != PJ_SUCCESS) {
1934 0 : JAMI_ERROR("Unable to set transport: {:s}", sip_utils::sip_strerror(status));
1935 0 : messageEngine_.onMessageSent(to, id, false);
1936 0 : return;
1937 : }
1938 :
1939 0 : im::fillPJSIPMessageBody(*tdata, payloads);
1940 :
1941 : // Send message request with callback SendMessageOnComplete
1942 0 : status = pjsip_endpt_send_request(link_.getEndpoint(), tdata, -1, t.release(), &onComplete);
1943 :
1944 0 : if (status != PJ_SUCCESS) {
1945 0 : JAMI_ERROR("Unable to send request: {:s}", sip_utils::sip_strerror(status));
1946 0 : messageEngine_.onMessageSent(to, id, false);
1947 0 : return;
1948 : }
1949 0 : }
1950 :
1951 : void
1952 0 : SIPAccount::onComplete(void* token, pjsip_event* event)
1953 : {
1954 0 : std::unique_ptr<ctx> c {(ctx*) token};
1955 : int code;
1956 : pj_status_t status;
1957 0 : pj_assert(event->type == PJSIP_EVENT_TSX_STATE);
1958 0 : code = event->body.tsx_state.tsx->status_code;
1959 :
1960 0 : auto acc = c->acc.lock();
1961 0 : if (not acc)
1962 0 : return;
1963 :
1964 : // Check if Authorization Header if needed (request rejected by server)
1965 0 : if (code == PJSIP_SC_UNAUTHORIZED || code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) {
1966 0 : JAMI_INFO("Authorization needed for SMS message - Resending");
1967 : pjsip_tx_data* new_request;
1968 :
1969 : // Add Authorization Header into msg
1970 0 : status = pjsip_auth_clt_reinit_req(c->auth_sess.get(),
1971 0 : event->body.tsx_state.src.rdata,
1972 0 : event->body.tsx_state.tsx->last_tx,
1973 : &new_request);
1974 :
1975 0 : if (status == PJ_SUCCESS) {
1976 : // Increment Cseq number by one manually
1977 : pjsip_cseq_hdr* cseq_hdr;
1978 0 : cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(new_request->msg, PJSIP_H_CSEQ, NULL);
1979 0 : cseq_hdr->cseq += 1;
1980 :
1981 : // Resend request
1982 0 : auto to = c->to;
1983 0 : auto id = c->id;
1984 0 : status = pjsip_endpt_send_request(acc->link_.getEndpoint(),
1985 : new_request,
1986 : -1,
1987 0 : c.release(),
1988 : &onComplete);
1989 :
1990 0 : if (status != PJ_SUCCESS) {
1991 0 : JAMI_ERROR("Unable to send request: {:s}", sip_utils::sip_strerror(status));
1992 0 : acc->messageEngine_.onMessageSent(to, id, false);
1993 : }
1994 0 : return;
1995 0 : } else {
1996 0 : JAMI_ERROR("Unable to add Authorization Header into msg");
1997 0 : acc->messageEngine_.onMessageSent(c->to, c->id, false);
1998 0 : return;
1999 : }
2000 : }
2001 0 : acc->messageEngine_.onMessageSent(c->to,
2002 0 : c->id,
2003 0 : event && event->body.tsx_state.tsx
2004 0 : && (event->body.tsx_state.tsx->status_code == PJSIP_SC_OK
2005 0 : || event->body.tsx_state.tsx->status_code
2006 : == PJSIP_SC_ACCEPTED));
2007 0 : }
2008 :
2009 : std::string
2010 0 : SIPAccount::getUserUri() const
2011 : {
2012 0 : return getFromUri();
2013 : }
2014 :
2015 : dhtnet::IpAddr
2016 28 : SIPAccount::createBindingAddress()
2017 : {
2018 28 : auto family = hostIp_ ? hostIp_.getFamily() : PJ_AF_INET;
2019 28 : const auto& conf = config();
2020 :
2021 28 : dhtnet::IpAddr ret = conf.bindAddress.empty() ? (
2022 28 : conf.interface == dhtnet::ip_utils::DEFAULT_INTERFACE
2023 0 : || conf.interface.empty()
2024 28 : ? dhtnet::ip_utils::getAnyHostAddr(family)
2025 0 : : dhtnet::ip_utils::getInterfaceAddr(getLocalInterface(), family))
2026 28 : : dhtnet::IpAddr(conf.bindAddress, family);
2027 :
2028 28 : if (ret.getPort() == 0) {
2029 28 : ret.setPort(conf.tlsEnable ? conf.tlsListenerPort : conf.localPort);
2030 : }
2031 :
2032 28 : return ret;
2033 : }
2034 :
2035 : void
2036 24 : SIPAccount::setActiveCodecs(const std::vector<unsigned>& list)
2037 : {
2038 24 : Account::setActiveCodecs(list);
2039 24 : if (!hasActiveCodec(MEDIA_AUDIO)) {
2040 72 : JAMI_WARNING("All audio codecs disabled, enabling all");
2041 24 : setAllCodecsActive(MEDIA_AUDIO, true);
2042 : }
2043 24 : if (!hasActiveCodec(MEDIA_VIDEO)) {
2044 72 : JAMI_WARNING("All video codecs disabled, enabling all");
2045 24 : setAllCodecsActive(MEDIA_VIDEO, true);
2046 : }
2047 24 : config_->activeCodecs = getActiveCodecs(MEDIA_ALL);
2048 24 : }
2049 :
2050 : } // namespace jami
|