LCOV - code coverage report
Current view: top level - src/sip - sipaccount.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 520 1022 50.9 %
Date: 2024-03-29 09:30:40 Functions: 63 139 45.3 %

          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, &registration_cb, &regc) != 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

Generated by: LCOV version 1.14