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