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