Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
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([&](bool /* transport_free */) { doRegister(); });
588 0 : return true;
589 : }
590 0 : return false;
591 : }
592 :
593 : bool
594 0 : SIPAccount::setPushNotificationConfig(const std::map<std::string, std::string>& data)
595 : {
596 0 : if (SIPAccountBase::setPushNotificationConfig(data)) {
597 0 : if (config().enabled)
598 0 : doUnregister([&](bool /* transport_free */) { doRegister(); });
599 0 : return true;
600 : }
601 0 : return false;
602 : }
603 :
604 : void
605 0 : SIPAccount::pushNotificationReceived(const std::string& from,
606 : const std::map<std::string, std::string>&)
607 : {
608 0 : JAMI_WARNING("[SIP Account {:s}] pushNotificationReceived: {:s}", getAccountID(), from);
609 :
610 0 : if (config().enabled)
611 0 : doUnregister([&](bool /* transport_free */) { doRegister(); });
612 0 : }
613 :
614 : void
615 25 : SIPAccount::doRegister()
616 : {
617 25 : if (not isUsable()) {
618 0 : JAMI_WARN("Account must be enabled and active to register, ignoring");
619 0 : return;
620 : }
621 :
622 75 : JAMI_DEBUG("doRegister {:s}", config_->hostname);
623 :
624 : /* if UPnP is enabled, then wait for IGD to complete registration */
625 25 : if (upnpCtrl_) {
626 4 : JAMI_DBG("UPnP: waiting for IGD to register SIP account");
627 4 : setRegistrationState(RegistrationState::TRYING);
628 4 : if (not mapPortUPnP()) {
629 4 : JAMI_DBG("UPnP: UPNP request failed, try to register SIP account anyway");
630 4 : doRegister1_();
631 : }
632 : } else {
633 21 : doRegister1_();
634 : }
635 : }
636 :
637 : void
638 28 : SIPAccount::doRegister1_()
639 : {
640 : {
641 28 : std::lock_guard lock(configurationMutex_);
642 28 : if (isIP2IP()) {
643 23 : doRegister2_();
644 23 : return;
645 : }
646 28 : }
647 :
648 10 : link_.resolveSrvName(hasServiceRoute() ? getServiceRoute() : config().hostname,
649 5 : config().tlsEnable ? PJSIP_TRANSPORT_TLS : PJSIP_TRANSPORT_UDP,
650 5 : [w = weak()](std::vector<dhtnet::IpAddr> host_ips) {
651 5 : if (auto acc = w.lock()) {
652 : std::lock_guard lock(
653 5 : acc->configurationMutex_);
654 5 : if (host_ips.empty()) {
655 0 : JAMI_ERR("Unable to resolve hostname for registration.");
656 0 : acc->setRegistrationState(RegistrationState::ERROR_GENERIC,
657 : PJSIP_SC_NOT_FOUND);
658 0 : return;
659 : }
660 5 : acc->hostIp_ = host_ips[0];
661 5 : acc->doRegister2_();
662 10 : }
663 : });
664 : }
665 :
666 : void
667 28 : SIPAccount::doRegister2_()
668 : {
669 28 : if (not isIP2IP() and not hostIp_) {
670 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND);
671 0 : JAMI_ERROR("Hostname not resolved.");
672 23 : return;
673 : }
674 :
675 28 : dhtnet::IpAddr bindAddress = createBindingAddress();
676 28 : if (not bindAddress) {
677 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, PJSIP_SC_NOT_FOUND);
678 0 : JAMI_ERROR("Unable to compute address to bind.");
679 0 : return;
680 : }
681 :
682 28 : bool ipv6 = bindAddress.isIpv6();
683 56 : transportType_ = config().tlsEnable ? (ipv6 ? PJSIP_TRANSPORT_TLS6 : PJSIP_TRANSPORT_TLS)
684 28 : : (ipv6 ? PJSIP_TRANSPORT_UDP6 : PJSIP_TRANSPORT_UDP);
685 :
686 : // Init TLS settings if the user wants to use TLS
687 28 : if (config().tlsEnable) {
688 0 : JAMI_DEBUG("TLS is enabled for account {}", accountID_);
689 :
690 : // Dropping current calls already using the transport is currently required
691 : // with TLS.
692 0 : hangupCalls();
693 0 : initTlsConfiguration();
694 :
695 0 : if (!tlsListener_) {
696 0 : tlsListener_ = link_.sipTransportBroker->getTlsListener(bindAddress, getTlsSetting());
697 0 : if (!tlsListener_) {
698 0 : setRegistrationState(RegistrationState::ERROR_GENERIC);
699 0 : JAMI_ERROR("Error creating TLS listener.");
700 0 : return;
701 : }
702 : }
703 : } else {
704 28 : tlsListener_.reset();
705 : }
706 :
707 : // In our definition of the ip2ip profile (aka Direct IP Calls),
708 : // no registration should be performed
709 28 : if (isIP2IP()) {
710 : // If we use Tls for IP2IP, transports will be created on connection.
711 23 : if (!config().tlsEnable) {
712 23 : setTransport(link_.sipTransportBroker->getUdpTransport(bindAddress));
713 : }
714 23 : setRegistrationState(RegistrationState::REGISTERED);
715 23 : return;
716 : }
717 :
718 : try {
719 15 : JAMI_WARNING("Creating transport");
720 5 : transport_.reset();
721 5 : if (isTlsEnabled()) {
722 0 : setTransport(link_.sipTransportBroker->getTlsTransport(tlsListener_,
723 0 : hostIp_,
724 0 : config().tlsServerName.empty()
725 0 : ? config().hostname
726 0 : : config().tlsServerName));
727 : } else {
728 5 : setTransport(link_.sipTransportBroker->getUdpTransport(bindAddress));
729 : }
730 5 : if (!transport_)
731 0 : throw VoipLinkException("Unable to create transport");
732 :
733 5 : sendRegister();
734 0 : } catch (const VoipLinkException& e) {
735 0 : JAMI_ERR("%s", e.what());
736 0 : setRegistrationState(RegistrationState::ERROR_GENERIC);
737 0 : return;
738 0 : }
739 :
740 5 : if (presence_ and presence_->isEnabled()) {
741 0 : presence_->subscribeClient(getFromUri(), true); // self presence subscription
742 0 : presence_->sendPresence(true, ""); // attempt to publish whatever the status is.
743 : }
744 : }
745 :
746 : void
747 25 : SIPAccount::doUnregister(std::function<void(bool)> released_cb)
748 : {
749 25 : std::unique_lock<std::recursive_mutex> lock(configurationMutex_);
750 :
751 25 : tlsListener_.reset();
752 :
753 25 : if (!isIP2IP()) {
754 : try {
755 3 : sendUnregister();
756 0 : } catch (const VoipLinkException& e) {
757 0 : JAMI_ERR("doUnregister %s", e.what());
758 0 : }
759 : }
760 :
761 25 : if (transport_)
762 25 : setTransport();
763 25 : resetAutoRegistration();
764 :
765 25 : lock.unlock();
766 25 : if (released_cb)
767 1 : released_cb(not isIP2IP());
768 25 : }
769 :
770 : void
771 1 : SIPAccount::connectivityChanged()
772 : {
773 1 : if (not isUsable()) {
774 : // Nothing to do
775 0 : return;
776 : }
777 :
778 1 : doUnregister([acc = shared()](bool /* transport_free */) {
779 1 : if (acc->isUsable())
780 1 : acc->doRegister();
781 1 : });
782 : }
783 :
784 : void
785 5 : SIPAccount::sendRegister()
786 : {
787 5 : if (not isUsable()) {
788 0 : JAMI_WARNING("[Account {}] Must be enabled and active to register, ignoring", accountID_);
789 0 : return;
790 : }
791 :
792 5 : bRegister_ = true;
793 5 : setRegistrationState(RegistrationState::TRYING);
794 :
795 5 : pjsip_regc* regc = nullptr;
796 5 : if (pjsip_regc_create(link_.getEndpoint(), (void*) this, ®istration_cb, ®c) != PJ_SUCCESS)
797 0 : throw VoipLinkException("UserAgent: Unable to create regc structure.");
798 :
799 5 : std::string srvUri(getServerUri());
800 5 : pj_str_t pjSrv {(char*) srvUri.data(), (pj_ssize_t) srvUri.size()};
801 :
802 : // Generate the FROM header
803 5 : std::string from(getFromUri());
804 5 : pj_str_t pjFrom(sip_utils::CONST_PJ_STR(from));
805 :
806 : // Get the received header
807 5 : const std::string& received(getReceivedParameter());
808 :
809 5 : std::string contact = getContactHeader();
810 :
811 15 : JAMI_LOG("[Account {}] Using contact header {} in registration", accountID_, contact);
812 :
813 5 : if (transport_) {
814 5 : if (getUPnPActive() or not getPublishedSameasLocal()
815 10 : or (not received.empty() and received != getPublishedAddress())) {
816 0 : pjsip_host_port* via = getViaAddr();
817 0 : JAMI_LOG("Setting VIA sent-by to {:s}:{:d}",
818 : sip_utils::as_view(via->host),
819 : via->port);
820 :
821 0 : if (pjsip_regc_set_via_sent_by(regc, via, transport_->get()) != PJ_SUCCESS)
822 0 : throw VoipLinkException("Unable to set the \"sent-by\" field");
823 5 : } else if (isStunEnabled()) {
824 0 : if (pjsip_regc_set_via_sent_by(regc, getViaAddr(), transport_->get()) != PJ_SUCCESS)
825 0 : throw VoipLinkException("Unable to set the \"sent-by\" field");
826 : }
827 : }
828 :
829 5 : pj_status_t status = PJ_SUCCESS;
830 5 : pj_str_t pjContact = sip_utils::CONST_PJ_STR(contact);
831 :
832 5 : if ((status
833 5 : = pjsip_regc_init(regc, &pjSrv, &pjFrom, &pjFrom, 1, &pjContact, getRegistrationExpire()))
834 5 : != PJ_SUCCESS) {
835 0 : JAMI_ERR("pjsip_regc_init failed with error %d: %s",
836 : status,
837 : sip_utils::sip_strerror(status).c_str());
838 0 : throw VoipLinkException("Unable to initialize account registration structure");
839 : }
840 :
841 5 : if (hasServiceRoute())
842 0 : pjsip_regc_set_route_set(regc,
843 0 : sip_utils::createRouteSet(getServiceRoute(), link_.getPool()));
844 :
845 5 : pjsip_regc_set_credentials(regc, getCredentialCount(), getCredInfo());
846 :
847 : pjsip_hdr hdr_list;
848 5 : pj_list_init(&hdr_list);
849 5 : auto pjUserAgent = CONST_PJ_STR(getUserAgentName());
850 5 : constexpr pj_str_t STR_USER_AGENT = CONST_PJ_STR("User-Agent");
851 :
852 5 : pjsip_generic_string_hdr* h = pjsip_generic_string_hdr_create(link_.getPool(),
853 : &STR_USER_AGENT,
854 : &pjUserAgent);
855 5 : pj_list_push_back(&hdr_list, (pjsip_hdr*) h);
856 5 : pjsip_regc_add_headers(regc, &hdr_list);
857 :
858 : pjsip_tx_data* tdata;
859 :
860 5 : if (pjsip_regc_register(regc, isRegistrationRefreshEnabled(), &tdata) != PJ_SUCCESS)
861 0 : throw VoipLinkException("Unable to initialize transaction data for account registration");
862 :
863 5 : const pjsip_tpselector tp_sel = getTransportSelector();
864 5 : if (pjsip_regc_set_transport(regc, &tp_sel) != PJ_SUCCESS)
865 0 : throw VoipLinkException("Unable to set transport");
866 :
867 5 : if (tp_sel.u.transport)
868 5 : setUpTransmissionData(tdata, tp_sel.u.transport->key.type);
869 :
870 : // pjsip_regc_send increment the transport ref count by one,
871 5 : if ((status = pjsip_regc_send(regc, tdata)) != PJ_SUCCESS) {
872 0 : JAMI_ERROR("pjsip_regc_send failed with error {:d}: {}",
873 : status,
874 : sip_utils::sip_strerror(status));
875 0 : throw VoipLinkException("Unable to send account registration request");
876 : }
877 :
878 5 : setRegistrationInfo(regc);
879 5 : }
880 :
881 : void
882 8 : SIPAccount::setUpTransmissionData(pjsip_tx_data* tdata, long transportKeyType)
883 : {
884 8 : if (hostIp_) {
885 8 : auto ai = &tdata->dest_info;
886 8 : ai->name = pj_strdup3(tdata->pool, config().hostname.c_str());
887 8 : ai->addr.count = 1;
888 8 : ai->addr.entry[0].type = (pjsip_transport_type_e) transportKeyType;
889 8 : pj_memcpy(&ai->addr.entry[0].addr, hostIp_.pjPtr(), sizeof(pj_sockaddr));
890 8 : ai->addr.entry[0].addr_len = hostIp_.getLength();
891 8 : ai->cur_addr = 0;
892 : }
893 8 : }
894 :
895 : void
896 3 : SIPAccount::onRegister(pjsip_regc_cbparam* param)
897 : {
898 3 : if (param->regc != getRegistrationInfo())
899 0 : return;
900 :
901 3 : if (param->status != PJ_SUCCESS) {
902 0 : JAMI_ERROR("[Account {}] SIP registration error {:d}",
903 : accountID_, param->status);
904 0 : destroyRegistrationInfo();
905 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, param->code);
906 3 : } else if (param->code < 0 || param->code >= 300) {
907 0 : JAMI_ERROR("[Account {}] SIP registration failed, status={:d} ({:s})",
908 : accountID_, param->code,
909 : sip_utils::as_view(param->reason));
910 0 : destroyRegistrationInfo();
911 0 : switch (param->code) {
912 0 : case PJSIP_SC_FORBIDDEN:
913 0 : setRegistrationState(RegistrationState::ERROR_AUTH, param->code);
914 0 : break;
915 0 : case PJSIP_SC_NOT_FOUND:
916 0 : setRegistrationState(RegistrationState::ERROR_HOST, param->code);
917 0 : break;
918 0 : case PJSIP_SC_REQUEST_TIMEOUT:
919 0 : setRegistrationState(RegistrationState::ERROR_HOST, param->code);
920 0 : break;
921 0 : case PJSIP_SC_SERVICE_UNAVAILABLE:
922 0 : setRegistrationState(RegistrationState::ERROR_SERVICE_UNAVAILABLE, param->code);
923 0 : break;
924 0 : default:
925 0 : setRegistrationState(RegistrationState::ERROR_GENERIC, param->code);
926 : }
927 3 : } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
928 : // Update auto registration flag
929 3 : resetAutoRegistration();
930 :
931 3 : if (param->expiration < 1) {
932 0 : destroyRegistrationInfo();
933 0 : JAMI_DBG("Unregistration success");
934 0 : setRegistrationState(RegistrationState::UNREGISTERED, param->code);
935 : } else {
936 : /* TODO Check and update SIP outbound status first, since the result
937 : * will determine if we should update re-registration
938 : */
939 : // update_rfc5626_status(acc, param->rdata);
940 :
941 3 : if (config().allowIPAutoRewrite and checkNATAddress(param, link_.getPool()))
942 3 : JAMI_WARN("New contact: %s", getContactHeader().c_str());
943 :
944 : /* TODO Check and update Service-Route header */
945 3 : if (hasServiceRoute())
946 0 : pjsip_regc_set_route_set(param->regc,
947 0 : sip_utils::createRouteSet(getServiceRoute(),
948 0 : link_.getPool()));
949 :
950 3 : setRegistrationState(RegistrationState::REGISTERED, param->code);
951 : }
952 : }
953 :
954 : /* Check if we need to auto retry registration. Basically, registration
955 : * failure codes triggering auto-retry are those of temporal failures
956 : * considered to be recoverable in relatively short term.
957 : */
958 3 : switch (param->code) {
959 0 : case PJSIP_SC_REQUEST_TIMEOUT:
960 : case PJSIP_SC_INTERNAL_SERVER_ERROR:
961 : case PJSIP_SC_BAD_GATEWAY:
962 : case PJSIP_SC_SERVICE_UNAVAILABLE:
963 : case PJSIP_SC_SERVER_TIMEOUT:
964 0 : scheduleReregistration();
965 0 : break;
966 :
967 3 : default:
968 : /* Global failure */
969 3 : if (PJSIP_IS_STATUS_IN_CLASS(param->code, 600))
970 0 : scheduleReregistration();
971 : }
972 :
973 3 : if (param->expiration != config().registrationExpire) {
974 0 : JAMI_DBG("Registrar returned EXPIRE value [%u s] different from the requested [%u s]",
975 : param->expiration,
976 : config().registrationExpire);
977 : // NOTE: We don't alter the EXPIRE set by the user even if the registrar
978 : // returned a different value. PJSIP lib will set the proper timer for
979 : // the refresh, if the auto-regisration is enabled.
980 : }
981 : }
982 :
983 : void
984 3 : SIPAccount::sendUnregister()
985 : {
986 : // This may occurs if account failed to register and is in state INVALID
987 3 : if (!isRegistered()) {
988 0 : setRegistrationState(RegistrationState::UNREGISTERED);
989 0 : return;
990 : }
991 :
992 3 : bRegister_ = false;
993 3 : pjsip_regc* regc = getRegistrationInfo();
994 3 : if (!regc)
995 0 : throw VoipLinkException("Registration structure is NULL");
996 :
997 3 : pjsip_tx_data* tdata = nullptr;
998 3 : if (pjsip_regc_unregister(regc, &tdata) != PJ_SUCCESS)
999 0 : throw VoipLinkException("Unable to unregister SIP account");
1000 :
1001 3 : const pjsip_tpselector tp_sel = getTransportSelector();
1002 3 : if (pjsip_regc_set_transport(regc, &tp_sel) != PJ_SUCCESS)
1003 0 : throw VoipLinkException("Unable to set transport");
1004 :
1005 3 : if (tp_sel.u.transport)
1006 3 : setUpTransmissionData(tdata, tp_sel.u.transport->key.type);
1007 :
1008 : pj_status_t status;
1009 3 : if ((status = pjsip_regc_send(regc, tdata)) != PJ_SUCCESS) {
1010 0 : JAMI_ERR("pjsip_regc_send failed with error %d: %s",
1011 : status,
1012 : sip_utils::sip_strerror(status).c_str());
1013 0 : throw VoipLinkException("Unable to send request to unregister SIP account");
1014 : }
1015 : }
1016 :
1017 : pj_uint32_t
1018 0 : SIPAccount::tlsProtocolFromString(const std::string& method)
1019 : {
1020 0 : if (method == "Default")
1021 0 : return PJSIP_SSL_DEFAULT_PROTO;
1022 0 : if (method == "TLSv1.2")
1023 0 : return PJ_SSL_SOCK_PROTO_TLS1_2;
1024 0 : if (method == "TLSv1.1")
1025 0 : return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1;
1026 0 : if (method == "TLSv1")
1027 0 : return PJ_SSL_SOCK_PROTO_TLS1_2 | PJ_SSL_SOCK_PROTO_TLS1_1 | PJ_SSL_SOCK_PROTO_TLS1;
1028 0 : return PJSIP_SSL_DEFAULT_PROTO;
1029 : }
1030 :
1031 : /**
1032 : * PJSIP aborts if our cipher list exceeds 1000 characters
1033 : */
1034 : void
1035 0 : SIPAccount::trimCiphers()
1036 : {
1037 0 : size_t sum = 0;
1038 0 : unsigned count = 0;
1039 : static const size_t MAX_CIPHERS_STRLEN = 1000;
1040 0 : for (const auto& item : ciphers_) {
1041 0 : sum += strlen(pj_ssl_cipher_name(item));
1042 0 : if (sum > MAX_CIPHERS_STRLEN)
1043 0 : break;
1044 0 : ++count;
1045 : }
1046 0 : ciphers_.resize(count);
1047 0 : }
1048 :
1049 : void
1050 0 : SIPAccount::initTlsConfiguration()
1051 : {
1052 0 : pjsip_tls_setting_default(&tlsSetting_);
1053 0 : const auto& conf = config();
1054 0 : tlsSetting_.proto = tlsProtocolFromString(conf.tlsMethod);
1055 :
1056 : // Determine the cipher list supported on this machine
1057 0 : CipherArray avail_ciphers(256);
1058 0 : unsigned cipherNum = avail_ciphers.size();
1059 0 : if (pj_ssl_cipher_get_availables(&avail_ciphers.front(), &cipherNum) != PJ_SUCCESS)
1060 0 : JAMI_ERR("Unable to determine cipher list on this system");
1061 0 : avail_ciphers.resize(cipherNum);
1062 :
1063 0 : ciphers_.clear();
1064 0 : std::string_view stream(conf.tlsCiphers), item;
1065 0 : while (jami::getline(stream, item, ' ')) {
1066 0 : std::string cipher(item);
1067 0 : auto item_cid = pj_ssl_cipher_id(cipher.c_str());
1068 0 : if (item_cid != PJ_TLS_UNKNOWN_CIPHER) {
1069 0 : JAMI_WARN("Valid cipher: %s", cipher.c_str());
1070 0 : ciphers_.push_back(item_cid);
1071 : } else
1072 0 : JAMI_ERR("Invalid cipher: %s", cipher.c_str());
1073 0 : }
1074 :
1075 0 : ciphers_.erase(std::remove_if(ciphers_.begin(),
1076 : ciphers_.end(),
1077 0 : [&](pj_ssl_cipher c) {
1078 0 : return std::find(avail_ciphers.cbegin(),
1079 : avail_ciphers.cend(),
1080 : c)
1081 0 : == avail_ciphers.cend();
1082 : }),
1083 0 : ciphers_.end());
1084 :
1085 0 : trimCiphers();
1086 :
1087 0 : tlsSetting_.ca_list_file = CONST_PJ_STR(conf.tlsCaListFile);
1088 0 : tlsSetting_.cert_file = CONST_PJ_STR(conf.tlsCaListFile);
1089 0 : tlsSetting_.privkey_file = CONST_PJ_STR(conf.tlsPrivateKeyFile);
1090 0 : tlsSetting_.password = CONST_PJ_STR(conf.tlsPassword);
1091 :
1092 0 : JAMI_DBG("Using %zu ciphers", ciphers_.size());
1093 0 : tlsSetting_.ciphers_num = ciphers_.size();
1094 0 : if (tlsSetting_.ciphers_num > 0) {
1095 0 : tlsSetting_.ciphers = &ciphers_.front();
1096 : }
1097 :
1098 0 : tlsSetting_.verify_server = conf.tlsVerifyServer;
1099 0 : tlsSetting_.verify_client = conf.tlsVerifyClient;
1100 0 : tlsSetting_.require_client_cert = conf.tlsRequireClientCertificate;
1101 0 : pjsip_cfg()->endpt.disable_secure_dlg_check = conf.tlsDisableSecureDlgCheck;
1102 0 : tlsSetting_.timeout.sec = conf.tlsNegotiationTimeout;
1103 :
1104 0 : tlsSetting_.qos_type = PJ_QOS_TYPE_BEST_EFFORT;
1105 0 : tlsSetting_.qos_ignore_error = PJ_TRUE;
1106 0 : }
1107 :
1108 : void
1109 24 : SIPAccount::initStunConfiguration()
1110 : {
1111 24 : std::string_view stunServer(config().stunServer);
1112 24 : auto pos = stunServer.find(':');
1113 24 : if (pos == std::string_view::npos) {
1114 24 : stunServerName_ = sip_utils::CONST_PJ_STR(stunServer);
1115 24 : stunPort_ = PJ_STUN_PORT;
1116 : } else {
1117 0 : stunServerName_ = sip_utils::CONST_PJ_STR(stunServer.substr(0, pos));
1118 0 : auto serverPort = stunServer.substr(pos + 1);
1119 0 : stunPort_ = to_int<uint16_t>(serverPort);
1120 : }
1121 24 : }
1122 :
1123 : void
1124 24 : SIPAccount::loadConfig()
1125 : {
1126 24 : SIPAccountBase::loadConfig();
1127 24 : setCredentials(config().credentials);
1128 24 : enablePresence(config().presenceEnabled);
1129 24 : initStunConfiguration();
1130 24 : if (config().tlsEnable) {
1131 0 : initTlsConfiguration();
1132 0 : transportType_ = PJSIP_TRANSPORT_TLS;
1133 : } else
1134 24 : transportType_ = PJSIP_TRANSPORT_UDP;
1135 24 : if (registrationState_ == RegistrationState::UNLOADED)
1136 24 : setRegistrationState(RegistrationState::UNREGISTERED);
1137 24 : }
1138 :
1139 : bool
1140 33 : SIPAccount::fullMatch(std::string_view username, std::string_view hostname) const
1141 : {
1142 33 : return userMatch(username) and hostnameMatch(hostname);
1143 : }
1144 :
1145 : bool
1146 57 : SIPAccount::userMatch(std::string_view username) const
1147 : {
1148 57 : return !username.empty() and username == config().username;
1149 : }
1150 :
1151 : bool
1152 39 : SIPAccount::hostnameMatch(std::string_view hostname) const
1153 : {
1154 39 : if (hostname == config().hostname)
1155 9 : return true;
1156 30 : const auto a = dhtnet::ip_utils::getAddrList(hostname);
1157 30 : const auto b = dhtnet::ip_utils::getAddrList(config().hostname);
1158 30 : return dhtnet::ip_utils::haveCommonAddr(a, b);
1159 30 : }
1160 :
1161 : bool
1162 18 : SIPAccount::proxyMatch(std::string_view hostname) const
1163 : {
1164 18 : if (hostname == config().serviceRoute)
1165 0 : return true;
1166 18 : const auto a = dhtnet::ip_utils::getAddrList(hostname);
1167 18 : const auto b = dhtnet::ip_utils::getAddrList(config().hostname);
1168 18 : return dhtnet::ip_utils::haveCommonAddr(a, b);
1169 18 : }
1170 :
1171 : std::string
1172 3 : SIPAccount::getLoginName()
1173 : {
1174 : #ifndef _WIN32
1175 3 : struct passwd* user_info = getpwuid(getuid());
1176 3 : return user_info ? user_info->pw_name : "";
1177 : #else
1178 : DWORD size = UNLEN + 1;
1179 : TCHAR username[UNLEN + 1];
1180 : std::string uname;
1181 : if (GetUserName((TCHAR*) username, &size)) {
1182 : uname = jami::to_string(username);
1183 : }
1184 : return uname;
1185 : #endif
1186 : }
1187 :
1188 : std::string
1189 15 : SIPAccount::getFromUri() const
1190 : {
1191 15 : std::string scheme;
1192 15 : std::string transport;
1193 :
1194 : // Get login name if username is not specified
1195 15 : const auto& conf = config();
1196 15 : std::string username(conf.username.empty() ? getLoginName() : conf.username);
1197 15 : std::string hostname(conf.hostname);
1198 :
1199 : // UDP does not require the transport specification
1200 15 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1201 0 : scheme = "sips:";
1202 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1203 : } else
1204 15 : scheme = "sip:";
1205 :
1206 : // Get machine hostname if not provided
1207 15 : if (hostname.empty()) {
1208 9 : hostname = sip_utils::as_view(*pj_gethostname());
1209 : }
1210 :
1211 15 : if (dhtnet::IpAddr::isIpv6(hostname))
1212 0 : hostname = dhtnet::IpAddr(hostname).toString(false, true);
1213 :
1214 30 : std::string uri = "<" + scheme + username + "@" + hostname + transport + ">";
1215 15 : if (not conf.displayName.empty())
1216 30 : return "\"" + conf.displayName + "\" " + uri;
1217 0 : return uri;
1218 15 : }
1219 :
1220 : std::string
1221 21 : SIPAccount::getToUri(const std::string& username) const
1222 : {
1223 21 : std::string scheme;
1224 21 : std::string transport;
1225 21 : std::string hostname;
1226 :
1227 : // UDP does not require the transport specification
1228 21 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1229 0 : scheme = "sips:";
1230 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1231 : } else
1232 21 : scheme = "sip:";
1233 :
1234 : // Check if scheme is already specified
1235 21 : if (username.find("sip") != std::string::npos)
1236 1 : scheme = "";
1237 :
1238 : // Check if hostname is already specified
1239 21 : if (username.find('@') == std::string::npos)
1240 4 : hostname = config().hostname;
1241 :
1242 21 : if (not hostname.empty() and dhtnet::IpAddr::isIpv6(hostname))
1243 0 : hostname = dhtnet::IpAddr(hostname).toString(false, true);
1244 :
1245 21 : auto ltSymbol = username.find('<') == std::string::npos ? "<" : "";
1246 21 : auto gtSymbol = username.find('>') == std::string::npos ? ">" : "";
1247 :
1248 42 : return ltSymbol + scheme + username + (hostname.empty() ? "" : "@") + hostname + transport
1249 42 : + gtSymbol;
1250 21 : }
1251 :
1252 : std::string
1253 5 : SIPAccount::getServerUri() const
1254 : {
1255 5 : std::string scheme;
1256 5 : std::string transport;
1257 :
1258 : // UDP does not require the transport specification
1259 5 : if (transportType_ == PJSIP_TRANSPORT_TLS || transportType_ == PJSIP_TRANSPORT_TLS6) {
1260 0 : scheme = "sips:";
1261 0 : transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType_));
1262 : } else {
1263 5 : scheme = "sip:";
1264 : }
1265 :
1266 5 : std::string host;
1267 5 : if (dhtnet::IpAddr::isIpv6(config().hostname))
1268 0 : host = dhtnet::IpAddr(config().hostname).toString(false, true);
1269 : else
1270 5 : host = config().hostname;
1271 :
1272 15 : return "<" + scheme + host + transport + ">";
1273 5 : }
1274 :
1275 : dhtnet::IpAddr
1276 3 : SIPAccount::getContactAddress() const
1277 : {
1278 3 : std::lock_guard lock(contactMutex_);
1279 3 : return contactAddress_;
1280 3 : }
1281 :
1282 : std::string
1283 41 : SIPAccount::getContactHeader() const
1284 : {
1285 41 : std::lock_guard lock(contactMutex_);
1286 82 : return contactHeader_;
1287 41 : }
1288 :
1289 : void
1290 27 : SIPAccount::updateContactHeader()
1291 : {
1292 27 : std::lock_guard lock(contactMutex_);
1293 :
1294 27 : if (not transport_ or not transport_->get()) {
1295 0 : JAMI_ERR("Transport not created yet");
1296 0 : return;
1297 : }
1298 :
1299 27 : if (not contactAddress_) {
1300 0 : JAMI_ERR("Invalid contact address: %s", contactAddress_.toString(true).c_str());
1301 0 : return;
1302 : }
1303 :
1304 54 : auto contactHdr = printContactHeader(config().username,
1305 27 : config().displayName,
1306 0 : contactAddress_.toString(false, true),
1307 54 : contactAddress_.getPort(),
1308 27 : PJSIP_TRANSPORT_IS_SECURE(transport_->get()),
1309 81 : config().deviceKey);
1310 :
1311 27 : contactHeader_ = std::move(contactHdr);
1312 27 : }
1313 :
1314 : bool
1315 27 : SIPAccount::initContactAddress()
1316 : {
1317 : // This method tries to determine the address to be used in the
1318 : // contact header using the available information (current transport,
1319 : // UPNP, STUN, …). The contact address may be updated after the
1320 : // registration using information sent by the registrar in the SIP
1321 : // messages (see checkNATAddress).
1322 :
1323 27 : if (not transport_ or not transport_->get()) {
1324 0 : JAMI_ERR("Transport not created yet");
1325 0 : return {};
1326 : }
1327 :
1328 : // The transport type must be specified, in our case START_OTHER refers to stun transport
1329 27 : pjsip_transport_type_e transportType = transportType_;
1330 :
1331 27 : if (transportType == PJSIP_TRANSPORT_START_OTHER)
1332 0 : transportType = PJSIP_TRANSPORT_UDP;
1333 :
1334 27 : std::string address;
1335 : pj_uint16_t port;
1336 :
1337 : // Init the address to the local address.
1338 27 : link_.findLocalAddressFromTransport(transport_->get(),
1339 : transportType,
1340 27 : config().hostname,
1341 : address,
1342 : port);
1343 :
1344 27 : if (getUPnPActive() and getUPnPIpAddress()) {
1345 0 : address = getUPnPIpAddress().toString();
1346 0 : port = publishedPortUsed_;
1347 0 : useUPnPAddressPortInVIA();
1348 0 : JAMI_DBG("Using UPnP address %s and port %d", address.c_str(), port);
1349 27 : } else if (not config().publishedSameasLocal) {
1350 0 : address = getPublishedIpAddress().toString();
1351 0 : port = config().publishedPort;
1352 0 : JAMI_DBG("Using published address %s and port %d", address.c_str(), port);
1353 27 : } else if (config().stunEnabled) {
1354 0 : auto success = link_.findLocalAddressFromSTUN(transport_->get(),
1355 : &stunServerName_,
1356 0 : stunPort_,
1357 : address,
1358 : port);
1359 0 : if (not success)
1360 0 : emitSignal<libjami::ConfigurationSignal::StunStatusFailed>(getAccountID());
1361 0 : setPublishedAddress({address});
1362 0 : publishedPortUsed_ = port;
1363 0 : usePublishedAddressPortInVIA();
1364 : } else {
1365 27 : if (!receivedParameter_.empty()) {
1366 0 : address = receivedParameter_;
1367 0 : JAMI_DBG("Using received address %s", address.c_str());
1368 : }
1369 :
1370 27 : if (rPort_ > 0) {
1371 0 : port = rPort_;
1372 0 : JAMI_DBG("Using received port %d", port);
1373 : }
1374 : }
1375 :
1376 27 : std::lock_guard lock(contactMutex_);
1377 27 : contactAddress_ = dhtnet::IpAddr(address);
1378 27 : contactAddress_.setPort(port);
1379 :
1380 27 : return contactAddress_;
1381 27 : }
1382 :
1383 : std::string
1384 30 : SIPAccount::printContactHeader(const std::string& username,
1385 : const std::string& displayName,
1386 : const std::string& address,
1387 : pj_uint16_t port,
1388 : bool secure,
1389 : const std::string& deviceKey)
1390 : {
1391 : // This method generates SIP contact header field, with push
1392 : // notification parameters if any.
1393 : // Example without push notification:
1394 : // John Doe<sips:jdoe@10.10.10.10:5060;transport=tls>
1395 : // Example with push notification:
1396 : // John Doe<sips:jdoe@10.10.10.10:5060;transport=tls;pn-provider=XXX;pn-param=YYY;pn-prid=ZZZ>
1397 :
1398 59 : std::string quotedDisplayName = displayName.empty() ? "" : "\"" + displayName + "\" ";
1399 :
1400 30 : std::ostringstream contact;
1401 30 : auto scheme = secure ? "sips" : "sip";
1402 30 : auto transport = secure ? ";transport=tls" : "";
1403 :
1404 : contact << quotedDisplayName << "<" << scheme << ":" << username
1405 30 : << (username.empty() ? "" : "@") << address << ":" << port << transport;
1406 :
1407 30 : if (not deviceKey.empty()) {
1408 : contact
1409 : #if defined(__ANDROID__)
1410 : << ";pn-provider=" << PN_FCM
1411 : #elif defined(__Apple__)
1412 : << ";pn-provider=" << PN_APNS
1413 : #endif
1414 : << ";pn-param="
1415 0 : << ";pn-prid=" << deviceKey;
1416 : }
1417 30 : contact << ">";
1418 :
1419 60 : return contact.str();
1420 30 : }
1421 :
1422 : pjsip_host_port
1423 0 : SIPAccount::getHostPortFromSTUN(pj_pool_t* pool)
1424 : {
1425 0 : std::string addr;
1426 : pj_uint16_t port;
1427 0 : auto success = link_.findLocalAddressFromSTUN(transport_ ? transport_->get() : nullptr,
1428 : &stunServerName_,
1429 0 : stunPort_,
1430 : addr,
1431 : port);
1432 0 : if (not success)
1433 0 : emitSignal<libjami::ConfigurationSignal::StunStatusFailed>(getAccountID());
1434 : pjsip_host_port result;
1435 0 : pj_strdup2(pool, &result.host, addr.c_str());
1436 0 : result.port = port;
1437 0 : return result;
1438 0 : }
1439 :
1440 : const std::vector<std::string>&
1441 0 : SIPAccount::getSupportedTlsCiphers()
1442 : {
1443 : // Currently, both OpenSSL and GNUTLS implementations are static
1444 : // reloading this for each account is unnecessary
1445 0 : static std::vector<std::string> availCiphers {};
1446 :
1447 : // LIMITATION Assume the size might change, if there aren't any ciphers,
1448 : // this will cause the cache to be repopulated at each call for nothing.
1449 0 : if (availCiphers.empty()) {
1450 0 : unsigned cipherNum = 256;
1451 0 : CipherArray avail_ciphers(cipherNum);
1452 0 : if (pj_ssl_cipher_get_availables(&avail_ciphers.front(), &cipherNum) != PJ_SUCCESS)
1453 0 : JAMI_ERR("Unable to determine cipher list on this system");
1454 0 : avail_ciphers.resize(cipherNum);
1455 0 : availCiphers.reserve(cipherNum);
1456 0 : for (const auto& item : avail_ciphers) {
1457 0 : if (item > 0) // 0 doesn't have a name
1458 0 : availCiphers.push_back(pj_ssl_cipher_name(item));
1459 : }
1460 0 : }
1461 0 : return availCiphers;
1462 : }
1463 :
1464 : const std::vector<std::string>&
1465 0 : SIPAccount::getSupportedTlsProtocols()
1466 : {
1467 : static std::vector<std::string> availProtos {VALID_TLS_PROTOS,
1468 0 : VALID_TLS_PROTOS + std::size(VALID_TLS_PROTOS)};
1469 0 : return availProtos;
1470 : }
1471 :
1472 : void
1473 24 : SIPAccount::setCredentials(const std::vector<SipAccountConfig::Credentials>& creds)
1474 : {
1475 24 : cred_.clear();
1476 24 : cred_.reserve(creds.size());
1477 24 : bool md5HashingEnabled = Manager::instance().preferences.getMd5Hash();
1478 :
1479 48 : for (auto& c : creds) {
1480 24 : cred_.emplace_back(
1481 48 : pjsip_cred_info {/*.realm = */ CONST_PJ_STR(c.realm),
1482 : /*.scheme = */ CONST_PJ_STR("digest"),
1483 24 : /*.username = */ CONST_PJ_STR(c.username),
1484 : /*.data_type = */
1485 24 : (md5HashingEnabled ? PJSIP_CRED_DATA_DIGEST
1486 : : PJSIP_CRED_DATA_PLAIN_PASSWD),
1487 : /*.data = */
1488 24 : CONST_PJ_STR(md5HashingEnabled ? c.password_h : c.password),
1489 : /*.ext = */ {}});
1490 : }
1491 24 : }
1492 :
1493 : void
1494 59 : SIPAccount::setRegistrationState(RegistrationState state,
1495 : int details_code,
1496 : const std::string& /*detail_str*/)
1497 : {
1498 59 : std::string details_str;
1499 59 : const pj_str_t* description = pjsip_get_status_text(details_code);
1500 59 : if (description)
1501 59 : details_str = sip_utils::as_view(*description);
1502 59 : registrationStateDetailed_ = {details_code, details_str};
1503 59 : SIPAccountBase::setRegistrationState(state, details_code, details_str);
1504 59 : }
1505 :
1506 : bool
1507 183 : SIPAccount::isIP2IP() const
1508 : {
1509 183 : return config().hostname.empty();
1510 : }
1511 :
1512 : SIPPresence*
1513 0 : SIPAccount::getPresence() const
1514 : {
1515 0 : return presence_;
1516 : }
1517 :
1518 : /**
1519 : * Enable the presence module
1520 : */
1521 : void
1522 24 : SIPAccount::enablePresence(const bool& enabled)
1523 : {
1524 24 : if (!presence_) {
1525 0 : JAMI_ERR("Presence not initialized");
1526 0 : return;
1527 : }
1528 :
1529 72 : JAMI_LOG("[Account {}] Presence enabled: {}.", accountID_, enabled ? TRUE_STR : FALSE_STR);
1530 :
1531 24 : presence_->enable(enabled);
1532 : }
1533 :
1534 : /**
1535 : * Set the presence (PUBLISH/SUBSCRIBE) support flags
1536 : * and process the change.
1537 : */
1538 : void
1539 0 : SIPAccount::supportPresence(int function, bool enabled)
1540 : {
1541 0 : if (!presence_) {
1542 0 : JAMI_ERR("Presence not initialized");
1543 0 : return;
1544 : }
1545 :
1546 0 : if (presence_->isSupported(function) == enabled)
1547 0 : return;
1548 :
1549 0 : JAMI_LOG("[Account {}] Presence support ({}: {}).",
1550 : accountID_,
1551 : function == PRESENCE_FUNCTION_PUBLISH ? "publish" : "subscribe",
1552 : enabled ? TRUE_STR : FALSE_STR);
1553 0 : presence_->support(function, enabled);
1554 :
1555 : // force presence to disable when nothing is supported
1556 0 : if (not presence_->isSupported(PRESENCE_FUNCTION_PUBLISH)
1557 0 : and not presence_->isSupported(PRESENCE_FUNCTION_SUBSCRIBE))
1558 0 : enablePresence(false);
1559 :
1560 0 : Manager::instance().saveConfig();
1561 : // FIXME: bad signal used here, we need a global config changed signal.
1562 0 : emitSignal<libjami::ConfigurationSignal::AccountsChanged>();
1563 : }
1564 :
1565 : MatchRank
1566 33 : SIPAccount::matches(std::string_view userName, std::string_view server) const
1567 : {
1568 33 : if (fullMatch(userName, server)) {
1569 18 : JAMI_LOG("Matching account ID in request is a fullmatch {:s}@{:s}",
1570 : userName,
1571 : server);
1572 6 : return MatchRank::FULL;
1573 27 : } else if (hostnameMatch(server)) {
1574 9 : JAMI_LOG("Matching account ID in request with hostname {:s}", server);
1575 3 : return MatchRank::PARTIAL;
1576 24 : } else if (userMatch(userName)) {
1577 18 : JAMI_LOG("Matching account ID in request with username {:s}", userName);
1578 6 : return MatchRank::PARTIAL;
1579 18 : } else if (proxyMatch(server)) {
1580 0 : JAMI_LOG("Matching account ID in request with proxy {:s}", server);
1581 0 : return MatchRank::PARTIAL;
1582 : } else {
1583 18 : return MatchRank::NONE;
1584 : }
1585 : }
1586 :
1587 : void
1588 27 : SIPAccount::destroyRegistrationInfo()
1589 : {
1590 27 : if (!regc_)
1591 22 : return;
1592 5 : pjsip_regc_destroy(regc_);
1593 5 : regc_ = nullptr;
1594 : }
1595 :
1596 : void
1597 28 : SIPAccount::resetAutoRegistration()
1598 : {
1599 28 : auto_rereg_.active = PJ_FALSE;
1600 28 : auto_rereg_.attempt_cnt = 0;
1601 28 : if (auto_rereg_.timer.user_data) {
1602 0 : delete ((std::weak_ptr<SIPAccount>*) auto_rereg_.timer.user_data);
1603 0 : auto_rereg_.timer.user_data = nullptr;
1604 : }
1605 28 : }
1606 :
1607 : bool
1608 3 : SIPAccount::checkNATAddress(pjsip_regc_cbparam* param, pj_pool_t* pool)
1609 : {
1610 9 : JAMI_LOG("[Account {}] Checking IP route after the registration", accountID_);
1611 :
1612 3 : pjsip_transport* tp = param->rdata->tp_info.transport;
1613 :
1614 : /* Get the received and rport info */
1615 3 : pjsip_via_hdr* via = param->rdata->msg_info.via;
1616 3 : int rport = 0;
1617 3 : if (via->rport_param < 1) {
1618 : /* Remote doesn't support rport */
1619 0 : rport = via->sent_by.port;
1620 0 : if (rport == 0) {
1621 : pjsip_transport_type_e tp_type;
1622 0 : tp_type = (pjsip_transport_type_e) tp->key.type;
1623 0 : rport = pjsip_transport_get_default_port_for_type(tp_type);
1624 : }
1625 : } else {
1626 3 : rport = via->rport_param;
1627 : }
1628 :
1629 3 : const pj_str_t* via_addr = via->recvd_param.slen != 0 ? &via->recvd_param : &via->sent_by.host;
1630 3 : std::string via_addrstr(sip_utils::as_view(*via_addr));
1631 : /* Enclose IPv6 address in square brackets */
1632 3 : if (dhtnet::IpAddr::isIpv6(via_addrstr))
1633 0 : via_addrstr = dhtnet::IpAddr(via_addrstr).toString(false, true);
1634 :
1635 3 : JAMI_DBG("Checking received VIA address: %s", via_addrstr.c_str());
1636 :
1637 3 : if (via_addr_.host.slen == 0 or via_tp_ != tp) {
1638 2 : if (pj_strcmp(&via_addr_.host, via_addr))
1639 2 : pj_strdup(pool, &via_addr_.host, via_addr);
1640 :
1641 : // Update Via header
1642 2 : via_addr_.port = rport;
1643 2 : via_tp_ = tp;
1644 2 : pjsip_regc_set_via_sent_by(regc_, &via_addr_, via_tp_);
1645 : }
1646 :
1647 : // Set published Ip address
1648 3 : setPublishedAddress(dhtnet::IpAddr(via_addrstr));
1649 :
1650 : /* Compare received and rport with the URI in our registration */
1651 3 : dhtnet::IpAddr contact_addr = getContactAddress();
1652 :
1653 : // TODO. Why note save the port in contact URI/header?
1654 3 : if (contact_addr.getPort() == 0) {
1655 : pjsip_transport_type_e tp_type;
1656 0 : tp_type = (pjsip_transport_type_e) tp->key.type;
1657 0 : contact_addr.setPort(pjsip_transport_get_default_port_for_type(tp_type));
1658 : }
1659 :
1660 : /* Convert IP address strings into sockaddr for comparison.
1661 : * (http://trac.pjsip.org/repos/ticket/863)
1662 : */
1663 3 : bool matched = false;
1664 3 : dhtnet::IpAddr recv_addr {};
1665 3 : auto status = pj_sockaddr_parse(pj_AF_UNSPEC(), 0, via_addr, recv_addr.pjPtr());
1666 3 : recv_addr.setPort(rport);
1667 3 : if (status == PJ_SUCCESS) {
1668 : // Compare the addresses as sockaddr according to the ticket above
1669 3 : matched = contact_addr == recv_addr;
1670 : } else {
1671 : // Compare the addresses as string, as before
1672 0 : auto pjContactAddr = sip_utils::CONST_PJ_STR(contact_addr.toString());
1673 0 : matched = (contact_addr.getPort() == rport and pj_stricmp(&pjContactAddr, via_addr) == 0);
1674 : }
1675 :
1676 3 : if (matched) {
1677 : // Address doesn't change
1678 0 : return false;
1679 : }
1680 :
1681 : /* Get server IP address */
1682 3 : dhtnet::IpAddr srv_ip = {std::string_view(param->rdata->pkt_info.src_name)};
1683 :
1684 : /* At this point we've detected that the address as seen by registrar.
1685 : * has changed.
1686 : */
1687 :
1688 : /* Do not switch if both Contact and server's IP address are
1689 : * public but response contains private IP. A NAT in the middle
1690 : * might have messed up with the SIP packets. See:
1691 : * http://trac.pjsip.org/repos/ticket/643
1692 : *
1693 : * This exception can be disabled by setting allow_contact_rewrite
1694 : * to 2. In this case, the switch will always be done whenever there
1695 : * is difference in the IP address in the response.
1696 : */
1697 3 : if (not contact_addr.isPrivate() and not srv_ip.isPrivate() and recv_addr.isPrivate()) {
1698 : /* Don't switch */
1699 0 : return false;
1700 : }
1701 :
1702 : /* Also don't switch if only the port number part is different, and
1703 : * the Via received address is private.
1704 : * See http://trac.pjsip.org/repos/ticket/864
1705 : */
1706 3 : if (contact_addr == recv_addr and recv_addr.isPrivate()) {
1707 : /* Don't switch */
1708 0 : return false;
1709 : }
1710 :
1711 3 : JAMI_WARN("[account %s] Contact address changed: "
1712 : "(%s → %s:%d). Updating registration.",
1713 : accountID_.c_str(),
1714 : contact_addr.toString(true).c_str(),
1715 : via_addrstr.data(),
1716 : rport);
1717 :
1718 : /*
1719 : * Build new Contact header
1720 : */
1721 : {
1722 6 : auto tempContact = printContactHeader(config().username,
1723 3 : config().displayName,
1724 : via_addrstr,
1725 : rport,
1726 3 : PJSIP_TRANSPORT_IS_SECURE(tp),
1727 6 : config().deviceKey);
1728 :
1729 3 : if (tempContact.empty()) {
1730 0 : JAMI_ERR("Invalid contact header");
1731 0 : return false;
1732 : }
1733 :
1734 : // Update
1735 3 : std::lock_guard lock(contactMutex_);
1736 3 : contactHeader_ = std::move(tempContact);
1737 3 : }
1738 :
1739 3 : if (regc_ != nullptr) {
1740 3 : auto contactHdr = getContactHeader();
1741 3 : auto pjContact = sip_utils::CONST_PJ_STR(contactHdr);
1742 3 : pjsip_regc_update_contact(regc_, 1, &pjContact);
1743 :
1744 : /* Perform new registration at the next registration cycle */
1745 3 : }
1746 :
1747 3 : return true;
1748 3 : }
1749 :
1750 : /* Auto re-registration timeout callback */
1751 : void
1752 0 : SIPAccount::autoReregTimerCb()
1753 : {
1754 : /* Check if the re-registration timer is still valid, e.g: while waiting
1755 : * timeout timer application might have deleted the account or disabled
1756 : * the auto-reregistration.
1757 : */
1758 0 : if (not auto_rereg_.active)
1759 0 : return;
1760 :
1761 : /* Start re-registration */
1762 0 : ++auto_rereg_.attempt_cnt;
1763 : try {
1764 : // If attempt_count was 0, we should call doRegister to reset transports if needed.
1765 0 : if (auto_rereg_.attempt_cnt == 1)
1766 0 : doRegister();
1767 : else
1768 0 : sendRegister();
1769 0 : } catch (const VoipLinkException& e) {
1770 0 : JAMI_ERR("Exception during SIP registration: %s", e.what());
1771 0 : scheduleReregistration();
1772 0 : }
1773 : }
1774 :
1775 : /* Schedule reregistration for specified account. Note that the first
1776 : * re-registration after a registration failure will be done immediately.
1777 : * Also note that this function should be called within PJSUA mutex.
1778 : */
1779 : void
1780 0 : SIPAccount::scheduleReregistration()
1781 : {
1782 0 : if (!isUsable())
1783 0 : return;
1784 :
1785 : /* Cancel any re-registration timer */
1786 0 : if (auto_rereg_.timer.id) {
1787 0 : auto_rereg_.timer.id = PJ_FALSE;
1788 0 : pjsip_endpt_cancel_timer(link_.getEndpoint(), &auto_rereg_.timer);
1789 : }
1790 :
1791 : /* Update re-registration flag */
1792 0 : auto_rereg_.active = PJ_TRUE;
1793 :
1794 : /* Set up timer for reregistration */
1795 0 : auto_rereg_.timer.cb = [](pj_timer_heap_t* /*th*/, pj_timer_entry* te) {
1796 0 : if (auto sipAccount = static_cast<std::weak_ptr<SIPAccount>*>(te->user_data)->lock())
1797 0 : sipAccount->autoReregTimerCb();
1798 0 : };
1799 0 : if (not auto_rereg_.timer.user_data)
1800 0 : auto_rereg_.timer.user_data = new std::weak_ptr<SIPAccount>(weak());
1801 :
1802 : /* Reregistration attempt. The first attempt will be done sooner */
1803 : pj_time_val delay;
1804 0 : delay.sec = auto_rereg_.attempt_cnt ? REGISTRATION_RETRY_INTERVAL
1805 : : REGISTRATION_FIRST_RETRY_INTERVAL;
1806 0 : delay.msec = 0;
1807 :
1808 : /* Randomize interval by ±10 secs */
1809 0 : if (delay.sec >= 10) {
1810 0 : delay.msec = delay10ZeroDist_(rand);
1811 : } else {
1812 0 : delay.sec = 0;
1813 0 : delay.msec = delay10PosDist_(rand);
1814 : }
1815 :
1816 0 : pj_time_val_normalize(&delay);
1817 :
1818 0 : JAMI_WARNING("Scheduling re-registration attempt in {:d} second(s)…", delay.sec);
1819 0 : auto_rereg_.timer.id = PJ_TRUE;
1820 0 : if (pjsip_endpt_schedule_timer(link_.getEndpoint(), &auto_rereg_.timer, &delay) != PJ_SUCCESS)
1821 0 : auto_rereg_.timer.id = PJ_FALSE;
1822 : }
1823 :
1824 : void
1825 10 : SIPAccount::updateDialogViaSentBy(pjsip_dialog* dlg)
1826 : {
1827 10 : if (config().allowIPAutoRewrite && via_addr_.host.slen > 0)
1828 1 : pjsip_dlg_set_via_sent_by(dlg, &via_addr_, via_tp_);
1829 10 : }
1830 :
1831 : #if 0
1832 : /**
1833 : * Create Accept header for MESSAGE.
1834 : */
1835 : static pjsip_accept_hdr* im_create_accept(pj_pool_t *pool)
1836 : {
1837 : /* Create Accept header. */
1838 : pjsip_accept_hdr *accept;
1839 :
1840 : accept = pjsip_accept_hdr_create(pool);
1841 : accept->values[0] = CONST_PJ_STR("text/plain");
1842 : accept->values[1] = CONST_PJ_STR("application/im-iscomposing+xml");
1843 : accept->count = 2;
1844 :
1845 : return accept;
1846 : }
1847 : #endif
1848 :
1849 : void
1850 0 : SIPAccount::sendMessage(const std::string& to,
1851 : const std::string&,
1852 : const std::map<std::string, std::string>& payloads,
1853 : uint64_t id,
1854 : bool,
1855 : bool)
1856 : {
1857 0 : if (to.empty() or payloads.empty()) {
1858 0 : JAMI_WARN("No sender or payload");
1859 0 : messageEngine_.onMessageSent(to, id, false);
1860 0 : return;
1861 : }
1862 :
1863 0 : auto toUri = getToUri(to);
1864 :
1865 0 : constexpr pjsip_method msg_method = {PJSIP_OTHER_METHOD,
1866 : CONST_PJ_STR(sip_utils::SIP_METHODS::MESSAGE)};
1867 0 : std::string from(getFromUri());
1868 0 : pj_str_t pjFrom = sip_utils::CONST_PJ_STR(from);
1869 0 : pj_str_t pjTo = sip_utils::CONST_PJ_STR(toUri);
1870 :
1871 : /* Create request. */
1872 : pjsip_tx_data* tdata;
1873 0 : pj_status_t status = pjsip_endpt_create_request(link_.getEndpoint(),
1874 : &msg_method,
1875 : &pjTo,
1876 : &pjFrom,
1877 : &pjTo,
1878 : nullptr,
1879 : nullptr,
1880 : -1,
1881 : nullptr,
1882 : &tdata);
1883 0 : if (status != PJ_SUCCESS) {
1884 0 : JAMI_ERROR("Unable to create request: {:s}", sip_utils::sip_strerror(status));
1885 0 : messageEngine_.onMessageSent(to, id, false);
1886 0 : return;
1887 : }
1888 :
1889 : /* Add Date Header. */
1890 : pj_str_t date_str;
1891 0 : constexpr auto key = CONST_PJ_STR("Date");
1892 : pjsip_hdr* hdr;
1893 0 : auto time = std::time(nullptr);
1894 0 : auto date = std::ctime(&time);
1895 : // the erase-remove idiom for a Cstring, removes _all_ new lines with in date
1896 0 : *std::remove(date, date + strlen(date), '\n') = '\0';
1897 :
1898 : // Add Header
1899 : hdr = reinterpret_cast<pjsip_hdr*>(
1900 0 : pjsip_date_hdr_create(tdata->pool, &key, pj_cstr(&date_str, date)));
1901 0 : pjsip_msg_add_hdr(tdata->msg, hdr);
1902 :
1903 : // Add user-agent header
1904 0 : sip_utils::addUserAgentHeader(getUserAgentName(), tdata);
1905 :
1906 : // Set input token into callback
1907 0 : std::unique_ptr<ctx> t {new ctx(new pjsip_auth_clt_sess)};
1908 0 : t->acc = shared();
1909 0 : t->to = to;
1910 0 : t->id = id;
1911 :
1912 : /* Initialize Auth header. */
1913 0 : status = pjsip_auth_clt_init(t->auth_sess.get(), link_.getEndpoint(), tdata->pool, 0);
1914 :
1915 0 : if (status != PJ_SUCCESS) {
1916 0 : JAMI_ERROR("Unable to initialize auth session: {:s}", sip_utils::sip_strerror(status));
1917 0 : messageEngine_.onMessageSent(to, id, false);
1918 0 : return;
1919 : }
1920 :
1921 0 : status = pjsip_auth_clt_set_credentials(t->auth_sess.get(), getCredentialCount(), getCredInfo());
1922 :
1923 0 : if (status != PJ_SUCCESS) {
1924 0 : JAMI_ERROR("Unable to set auth session data: {:s}", sip_utils::sip_strerror(status));
1925 0 : messageEngine_.onMessageSent(to, id, false);
1926 0 : return;
1927 : }
1928 :
1929 0 : const pjsip_tpselector tp_sel = getTransportSelector();
1930 0 : status = pjsip_tx_data_set_transport(tdata, &tp_sel);
1931 :
1932 0 : if (status != PJ_SUCCESS) {
1933 0 : JAMI_ERROR("Unable to set transport: {:s}", sip_utils::sip_strerror(status));
1934 0 : messageEngine_.onMessageSent(to, id, false);
1935 0 : return;
1936 : }
1937 :
1938 0 : im::fillPJSIPMessageBody(*tdata, payloads);
1939 :
1940 : // Send message request with callback SendMessageOnComplete
1941 0 : status = pjsip_endpt_send_request(link_.getEndpoint(), tdata, -1, t.release(), &onComplete);
1942 :
1943 0 : if (status != PJ_SUCCESS) {
1944 0 : JAMI_ERROR("Unable to send request: {:s}", sip_utils::sip_strerror(status));
1945 0 : messageEngine_.onMessageSent(to, id, false);
1946 0 : return;
1947 : }
1948 0 : }
1949 :
1950 : void
1951 0 : SIPAccount::onComplete(void* token, pjsip_event* event)
1952 : {
1953 0 : std::unique_ptr<ctx> c {(ctx*) token};
1954 : int code;
1955 : pj_status_t status;
1956 0 : pj_assert(event->type == PJSIP_EVENT_TSX_STATE);
1957 0 : code = event->body.tsx_state.tsx->status_code;
1958 :
1959 0 : auto acc = c->acc.lock();
1960 0 : if (not acc)
1961 0 : return;
1962 :
1963 : // Check if Authorization Header if needed (request rejected by server)
1964 0 : if (code == PJSIP_SC_UNAUTHORIZED || code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) {
1965 0 : JAMI_INFO("Authorization needed for SMS message - Resending");
1966 : pjsip_tx_data* new_request;
1967 :
1968 : // Add Authorization Header into msg
1969 0 : status = pjsip_auth_clt_reinit_req(c->auth_sess.get(),
1970 0 : event->body.tsx_state.src.rdata,
1971 0 : event->body.tsx_state.tsx->last_tx,
1972 : &new_request);
1973 :
1974 0 : if (status == PJ_SUCCESS) {
1975 : // Increment Cseq number by one manually
1976 : pjsip_cseq_hdr* cseq_hdr;
1977 0 : cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(new_request->msg, PJSIP_H_CSEQ, NULL);
1978 0 : cseq_hdr->cseq += 1;
1979 :
1980 : // Resend request
1981 0 : auto to = c->to;
1982 0 : auto id = c->id;
1983 0 : status = pjsip_endpt_send_request(acc->link_.getEndpoint(),
1984 : new_request,
1985 : -1,
1986 0 : c.release(),
1987 : &onComplete);
1988 :
1989 0 : if (status != PJ_SUCCESS) {
1990 0 : JAMI_ERROR("Unable to send request: {:s}", sip_utils::sip_strerror(status));
1991 0 : acc->messageEngine_.onMessageSent(to, id, false);
1992 : }
1993 0 : return;
1994 0 : } else {
1995 0 : JAMI_ERROR("Unable to add Authorization Header into msg");
1996 0 : acc->messageEngine_.onMessageSent(c->to, c->id, false);
1997 0 : return;
1998 : }
1999 : }
2000 0 : acc->messageEngine_.onMessageSent(c->to,
2001 0 : c->id,
2002 0 : event && event->body.tsx_state.tsx
2003 0 : && (event->body.tsx_state.tsx->status_code == PJSIP_SC_OK
2004 0 : || event->body.tsx_state.tsx->status_code
2005 : == PJSIP_SC_ACCEPTED));
2006 0 : }
2007 :
2008 : std::string
2009 0 : SIPAccount::getUserUri() const
2010 : {
2011 0 : return getFromUri();
2012 : }
2013 :
2014 : dhtnet::IpAddr
2015 28 : SIPAccount::createBindingAddress()
2016 : {
2017 28 : auto family = hostIp_ ? hostIp_.getFamily() : PJ_AF_INET;
2018 28 : const auto& conf = config();
2019 :
2020 28 : dhtnet::IpAddr ret = conf.bindAddress.empty() ? (
2021 28 : conf.interface == dhtnet::ip_utils::DEFAULT_INTERFACE
2022 0 : || conf.interface.empty()
2023 28 : ? dhtnet::ip_utils::getAnyHostAddr(family)
2024 0 : : dhtnet::ip_utils::getInterfaceAddr(getLocalInterface(), family))
2025 28 : : dhtnet::IpAddr(conf.bindAddress, family);
2026 :
2027 28 : if (ret.getPort() == 0) {
2028 28 : ret.setPort(conf.tlsEnable ? conf.tlsListenerPort : conf.localPort);
2029 : }
2030 :
2031 28 : return ret;
2032 : }
2033 :
2034 : void
2035 24 : SIPAccount::setActiveCodecs(const std::vector<unsigned>& list)
2036 : {
2037 24 : Account::setActiveCodecs(list);
2038 24 : if (!hasActiveCodec(MEDIA_AUDIO)) {
2039 72 : JAMI_WARNING("All audio codecs disabled, enabling all");
2040 24 : setAllCodecsActive(MEDIA_AUDIO, true);
2041 : }
2042 24 : if (!hasActiveCodec(MEDIA_VIDEO)) {
2043 72 : JAMI_WARNING("All video codecs disabled, enabling all");
2044 24 : setAllCodecsActive(MEDIA_VIDEO, true);
2045 : }
2046 24 : config_->activeCodecs = getActiveCodecs(MEDIA_ALL);
2047 24 : }
2048 :
2049 : } // namespace jami
|