LCOV - code coverage report
Current view: top level - foo/src/sip - pres_sub_client.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 0 278 0.0 %
Date: 2026-04-01 09:29:43 Functions: 0 22 0.0 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2012, 2013 LOTES TM LLC
       3             :  *  Author : Andrey Loukhnov <aol.nnov@gmail.com>
       4             :  *
       5             :  *  This file is a part of pult5-voip
       6             :  *
       7             :  *  pult5-voip is free software; you can redistribute it and/or modify
       8             :  *  it under the terms of the GNU General Public License as published by
       9             :  *  the Free Software Foundation; either version 3 of the License, or
      10             :  *  (at your option) any later version.
      11             :  *
      12             :  *  pult5-voip is distributed in the hope that it will be useful,
      13             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  *  GNU General Public License for more details.
      16             :  *
      17             :  *  You should have received a copy of the GNU General Public License
      18             :  *  along with this programm. If not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <pj/log.h>
      22             : #include <pj/rand.h>
      23             : #include <pjsip/sip_module.h>
      24             : #include <pjsip/sip_types.h>
      25             : #include <pjsip/sip_event.h>
      26             : #include <pjsip/sip_transaction.h>
      27             : #include <pjsip/sip_dialog.h>
      28             : #include <pjsip/sip_endpoint.h>
      29             : #include <string>
      30             : #include <sstream>
      31             : #include <thread>
      32             : #include <pj/pool.h>
      33             : #include <pjsip/sip_ua_layer.h>
      34             : #include <pjsip-simple/evsub.h>
      35             : #include <unistd.h>
      36             : 
      37             : #include "pres_sub_client.h"
      38             : #include "sip/sipaccount.h"
      39             : #include "sip/sippresence.h"
      40             : #include "sip/sipvoiplink.h"
      41             : #include "connectivity/sip_utils.h"
      42             : #include "manager.h"
      43             : #include "client/jami_signal.h"
      44             : 
      45             : #include "logger.h"
      46             : 
      47             : #define PRES_TIMER 300 // 5min
      48             : 
      49             : namespace jami {
      50             : 
      51             : using sip_utils::CONST_PJ_STR;
      52             : 
      53             : int PresSubClient::modId_ = 0; // used to extract data structure from event_subscription
      54             : 
      55             : void
      56           0 : PresSubClient::pres_client_timer_cb(pj_timer_heap_t* /*th*/, pj_timer_entry* entry)
      57             : {
      58           0 :     PresSubClient* c = (PresSubClient*) entry->user_data;
      59           0 :     JAMI_DBG("timeout for %.*s", (int) c->getURI().size(), c->getURI().data());
      60           0 : }
      61             : 
      62             : /* Callback called when *client* subscription state has changed. */
      63             : void
      64           0 : PresSubClient::pres_client_evsub_on_state(pjsip_evsub* sub, pjsip_event* event)
      65             : {
      66             :     PJ_UNUSED_ARG(event);
      67             : 
      68           0 :     PresSubClient* pres_client = (PresSubClient*) pjsip_evsub_get_mod_data(sub, modId_);
      69             :     /* No need to pres->lock() here since the client has a locked dialog*/
      70             : 
      71           0 :     if (!pres_client) {
      72           0 :         JAMI_WARN("pres_client not found");
      73           0 :         return;
      74             :     }
      75             : 
      76           0 :     JAMI_DBG("Subscription for pres_client '%.*s' is '%s'",
      77             :              (int) pres_client->getURI().size(),
      78             :              pres_client->getURI().data(),
      79             :              pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null");
      80             : 
      81           0 :     pjsip_evsub_state state = pjsip_evsub_get_state(sub);
      82             : 
      83           0 :     SIPPresence* pres = pres_client->getPresence();
      84             : 
      85           0 :     if (state == PJSIP_EVSUB_STATE_ACCEPTED) {
      86           0 :         pres_client->enable(true);
      87           0 :         emitSignal<libjami::PresenceSignal::SubscriptionStateChanged>(pres->getAccount()->getAccountID(),
      88           0 :                                                                       std::string(pres_client->getURI()),
      89             :                                                                       PJ_TRUE);
      90             : 
      91           0 :         pres->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, true);
      92             : 
      93           0 :     } else if (state == PJSIP_EVSUB_STATE_TERMINATED) {
      94           0 :         int resub_delay = -1;
      95           0 :         pj_strdup_with_null(pres_client->pool_, &pres_client->term_reason_, pjsip_evsub_get_termination_reason(sub));
      96             : 
      97           0 :         emitSignal<libjami::PresenceSignal::SubscriptionStateChanged>(pres->getAccount()->getAccountID(),
      98           0 :                                                                       std::string(pres_client->getURI()),
      99             :                                                                       PJ_FALSE);
     100             : 
     101           0 :         pres_client->term_code_ = 200;
     102             : 
     103             :         /* Determine whether to resubscribe automatically */
     104           0 :         if (event && event->type == PJSIP_EVENT_TSX_STATE) {
     105           0 :             const pjsip_transaction* tsx = event->body.tsx_state.tsx;
     106             : 
     107           0 :             if (pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) {
     108           0 :                 pres_client->term_code_ = tsx->status_code;
     109           0 :                 std::ostringstream os;
     110           0 :                 os << pres_client->term_code_;
     111           0 :                 const std::string error = os.str() + "/" + sip_utils::as_view(pres_client->term_reason_);
     112             : 
     113           0 :                 std::string msg;
     114           0 :                 bool subscribe_allowed = PJ_FALSE;
     115             : 
     116           0 :                 switch (tsx->status_code) {
     117           0 :                 case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST:
     118             :                     /* 481: we refreshed too late? resubscribe
     119             :                      * immediately.
     120             :                      */
     121             :                     /* But this must only happen when the 481 is received
     122             :                      * on subscription refresh request. We MUST NOT try to
     123             :                      * resubscribe automatically if the 481 is received
     124             :                      * on the initial SUBSCRIBE (if server returns this
     125             :                      * response for some reason).
     126             :                      */
     127           0 :                     if (pres_client->dlg_->remote.contact)
     128           0 :                         resub_delay = 500;
     129           0 :                     msg = "Bad subscribe refresh.";
     130           0 :                     subscribe_allowed = PJ_TRUE;
     131           0 :                     break;
     132             : 
     133           0 :                 case PJSIP_SC_NOT_FOUND:
     134           0 :                     msg = "Subscribe context not set for this buddy.";
     135           0 :                     subscribe_allowed = PJ_TRUE;
     136           0 :                     break;
     137             : 
     138           0 :                 case PJSIP_SC_FORBIDDEN:
     139           0 :                     msg = "Subscribe not allowed for this buddy.";
     140           0 :                     subscribe_allowed = PJ_TRUE;
     141           0 :                     break;
     142             : 
     143           0 :                 case PJSIP_SC_PRECONDITION_FAILURE:
     144           0 :                     msg = "Wrong server.";
     145           0 :                     break;
     146             : 
     147           0 :                 default:
     148           0 :                     JAMI_WARNING("Unrecognized status code: {}", tsx->status_code);
     149             :                 }
     150             : 
     151             :                 /*  report error:
     152             :                  *  1) send a signal through DBus
     153             :                  *  2) change the support field in the account schema if the pres_sub's server
     154             :                  *  is the same as the account's server
     155             :                  */
     156           0 :                 emitSignal<libjami::PresenceSignal::ServerError>(pres_client->getPresence()->getAccount()->getAccountID(),
     157             :                                                                  error,
     158             :                                                                  msg);
     159             : 
     160           0 :                 auto account_host = sip_utils::as_view(*pj_gethostname());
     161           0 :                 auto sub_host = sip_utils::getHostFromUri(pres_client->getURI());
     162             : 
     163           0 :                 if (not subscribe_allowed and account_host == sub_host)
     164           0 :                     pres_client->getPresence()->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, false);
     165             : 
     166           0 :             } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
     167           0 :                 if (pres_client->isTermReason("deactivated") || pres_client->isTermReason("timeout")) {
     168             :                     /* deactivated: The subscription has been terminated,
     169             :                      * but the subscriber SHOULD retry immediately with
     170             :                      * a new subscription.
     171             :                      */
     172             :                     /* timeout: The subscription has been terminated
     173             :                      * because it was not refreshed before it expired.
     174             :                      * Clients MAY re-subscribe immediately. The
     175             :                      * "retry-after" parameter has no semantics for
     176             :                      * "timeout".
     177             :                      */
     178           0 :                     resub_delay = 500;
     179           0 :                 } else if (pres_client->isTermReason("probation") || pres_client->isTermReason("giveup")) {
     180             :                     /* probation: The subscription has been terminated,
     181             :                      * but the client SHOULD retry at some later time.
     182             :                      * If a "retry-after" parameter is also present, the
     183             :                      * client SHOULD wait at least the number of seconds
     184             :                      * specified by that parameter before attempting to re-
     185             :                      * subscribe.
     186             :                      */
     187             :                     /* giveup: The subscription has been terminated because
     188             :                      * the notifier was unable to obtain authorization in a
     189             :                      * timely fashion.  If a "retry-after" parameter is
     190             :                      * also present, the client SHOULD wait at least the
     191             :                      * number of seconds specified by that parameter before
     192             :                      * attempting to re-subscribe; otherwise, the client
     193             :                      * MAY retry immediately, but will likely get put back
     194             :                      * into pending state.
     195             :                      */
     196             :                     const pjsip_sub_state_hdr* sub_hdr;
     197           0 :                     constexpr pj_str_t sub_state = CONST_PJ_STR("Subscription-State");
     198             :                     const pjsip_msg* msg;
     199             : 
     200           0 :                     msg = event->body.tsx_state.src.rdata->msg_info.msg;
     201           0 :                     sub_hdr = (const pjsip_sub_state_hdr*) pjsip_msg_find_hdr_by_name(msg, &sub_state, NULL);
     202             : 
     203           0 :                     if (sub_hdr && sub_hdr->retry_after > 0)
     204           0 :                         resub_delay = sub_hdr->retry_after * 1000;
     205             :                 }
     206             :             }
     207             :         }
     208             : 
     209             :         /* For other cases of subscription termination, if resubscribe
     210             :          * timer is not set, schedule with default expiration (plus minus
     211             :          * some random value, to avoid sending SUBSCRIBEs all at once)
     212             :          */
     213           0 :         if (resub_delay == -1) {
     214           0 :             resub_delay = PRES_TIMER * 1000;
     215             :         }
     216             : 
     217           0 :         pres_client->sub_ = sub;
     218           0 :         pres_client->rescheduleTimer(PJ_TRUE, resub_delay);
     219             : 
     220             :     } else { // state==ACTIVE ......
     221             :         // This will clear the last termination code/reason
     222           0 :         pres_client->term_code_ = 0;
     223           0 :         pres_client->term_reason_.ptr = NULL;
     224             :     }
     225             : 
     226             :     /* Clear subscription */
     227           0 :     if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
     228           0 :         pjsip_evsub_terminate(pres_client->sub_, PJ_FALSE); // = NULL;
     229           0 :         pres_client->status_.info_cnt = 0;
     230           0 :         pres_client->dlg_ = NULL;
     231           0 :         pres_client->rescheduleTimer(PJ_FALSE, 0);
     232           0 :         pjsip_evsub_set_mod_data(sub, modId_, NULL);
     233             : 
     234           0 :         pres_client->enable(false);
     235             :     }
     236             : }
     237             : 
     238             : /* Callback when transaction state has changed. */
     239             : void
     240           0 : PresSubClient::pres_client_evsub_on_tsx_state(pjsip_evsub* sub, pjsip_transaction* tsx, pjsip_event* event)
     241             : {
     242             :     PresSubClient* pres_client;
     243             :     pjsip_contact_hdr* contact_hdr;
     244             : 
     245           0 :     pres_client = (PresSubClient*) pjsip_evsub_get_mod_data(sub, modId_);
     246             :     /* No need to pres->lock() here since the client has a locked dialog*/
     247             : 
     248           0 :     if (!pres_client) {
     249           0 :         JAMI_WARN("Unable to find pres_client.");
     250           0 :         return;
     251             :     }
     252             : 
     253             :     /* We only use this to update pres_client's Contact, when it's not
     254             :      * set.
     255             :      */
     256           0 :     if (pres_client->contact_.slen != 0) {
     257             :         /* Contact already set */
     258           0 :         return;
     259             :     }
     260             : 
     261             :     /* Only care about 2xx response to outgoing SUBSCRIBE */
     262           0 :     if (tsx->status_code / 100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG
     263           0 :         || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method()) != 0) {
     264           0 :         return;
     265             :     }
     266             : 
     267             :     /* Find contact header. */
     268           0 :     contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
     269             : 
     270           0 :     if (!contact_hdr || !contact_hdr->uri) {
     271           0 :         return;
     272             :     }
     273             : 
     274           0 :     pres_client->contact_.ptr = (char*) pj_pool_alloc(pres_client->pool_, PJSIP_MAX_URL_SIZE);
     275           0 :     pres_client->contact_.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,
     276           0 :                                                  contact_hdr->uri,
     277             :                                                  pres_client->contact_.ptr,
     278             :                                                  PJSIP_MAX_URL_SIZE);
     279             : 
     280           0 :     if (pres_client->contact_.slen < 0)
     281           0 :         pres_client->contact_.slen = 0;
     282             : }
     283             : 
     284             : /* Callback called when we receive NOTIFY */
     285             : void
     286           0 : PresSubClient::pres_client_evsub_on_rx_notify(pjsip_evsub* sub,
     287             :                                               pjsip_rx_data* rdata,
     288             :                                               int* p_st_code,
     289             :                                               pj_str_t** p_st_text,
     290             :                                               pjsip_hdr* res_hdr,
     291             :                                               pjsip_msg_body** p_body)
     292             : {
     293           0 :     PresSubClient* pres_client = (PresSubClient*) pjsip_evsub_get_mod_data(sub, modId_);
     294             : 
     295           0 :     if (!pres_client) {
     296           0 :         JAMI_WARN("Unable to find pres_client from ev_sub.");
     297           0 :         return;
     298             :     }
     299             :     /* No need to pres->lock() here since the client has a locked dialog*/
     300             : 
     301           0 :     pjsip_pres_get_status(sub, &pres_client->status_);
     302           0 :     pres_client->reportPresence();
     303             : 
     304             :     /* The default is to send 200 response to NOTIFY.
     305             :      * Just leave it there.
     306             :      */
     307             :     PJ_UNUSED_ARG(rdata);
     308             :     PJ_UNUSED_ARG(p_st_code);
     309             :     PJ_UNUSED_ARG(p_st_text);
     310             :     PJ_UNUSED_ARG(res_hdr);
     311             :     PJ_UNUSED_ARG(p_body);
     312             : }
     313             : 
     314           0 : PresSubClient::PresSubClient(const std::string& uri, SIPPresence* pres)
     315           0 :     : pres_(pres)
     316           0 :     , uri_ {0, 0}
     317           0 :     , contact_ {0, 0}
     318           0 :     , display_()
     319           0 :     , dlg_(NULL)
     320           0 :     , monitored_(false)
     321           0 :     , name_()
     322           0 :     , cp_()
     323           0 :     , pool_(0)
     324           0 :     , status_()
     325           0 :     , sub_(NULL)
     326           0 :     , term_code_(0)
     327           0 :     , term_reason_()
     328           0 :     , timer_()
     329           0 :     , user_data_(NULL)
     330           0 :     , lock_count_(0)
     331           0 :     , lock_flag_(0)
     332             : {
     333           0 :     pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0);
     334           0 :     pool_ = pj_pool_create(&cp_.factory, "Pres_sub_client", 512, 512, NULL);
     335           0 :     uri_ = pj_strdup3(pool_, uri.c_str());
     336           0 :     contact_ = pj_strdup3(pool_, pres_->getAccount()->getFromUri().c_str());
     337           0 : }
     338             : 
     339           0 : PresSubClient::~PresSubClient()
     340             : {
     341           0 :     JAMI_DBG("Destroying pres_client object with uri %.*s", (int) uri_.slen, uri_.ptr);
     342           0 :     rescheduleTimer(PJ_FALSE, 0);
     343           0 :     unsubscribe();
     344           0 :     pj_pool_release(pool_);
     345           0 : }
     346             : 
     347             : bool
     348           0 : PresSubClient::isSubscribed()
     349             : {
     350           0 :     return monitored_;
     351             : }
     352             : 
     353             : std::string_view
     354           0 : PresSubClient::getURI()
     355             : {
     356           0 :     return {uri_.ptr, (size_t) uri_.slen};
     357             : }
     358             : 
     359             : SIPPresence*
     360           0 : PresSubClient::getPresence()
     361             : {
     362           0 :     return pres_;
     363             : }
     364             : 
     365             : bool
     366           0 : PresSubClient::isPresent()
     367             : {
     368           0 :     return status_.info[0].basic_open;
     369             : }
     370             : 
     371             : std::string_view
     372           0 : PresSubClient::getLineStatus()
     373             : {
     374           0 :     return {status_.info[0].rpid.note.ptr, (size_t) status_.info[0].rpid.note.slen};
     375             : }
     376             : 
     377             : bool
     378           0 : PresSubClient::isTermReason(const std::string& reason)
     379             : {
     380           0 :     const std::string_view myReason(term_reason_.ptr, (size_t) term_reason_.slen);
     381           0 :     return not myReason.compare(reason);
     382             : }
     383             : 
     384             : void
     385           0 : PresSubClient::rescheduleTimer(bool reschedule, unsigned msec)
     386             : {
     387           0 :     if (timer_.id) {
     388           0 :         pjsip_endpt_cancel_timer(Manager::instance().sipVoIPLink().getEndpoint(), &timer_);
     389           0 :         timer_.id = PJ_FALSE;
     390             :     }
     391             : 
     392           0 :     if (reschedule) {
     393             :         pj_time_val delay;
     394             : 
     395           0 :         JAMI_WARN("pres_client  %.*s will resubscribe in %u ms (reason: %.*s)",
     396             :                   (int) uri_.slen,
     397             :                   uri_.ptr,
     398             :                   msec,
     399             :                   (int) term_reason_.slen,
     400             :                   term_reason_.ptr);
     401           0 :         pj_timer_entry_init(&timer_, 0, this, &pres_client_timer_cb);
     402           0 :         delay.sec = 0;
     403           0 :         delay.msec = msec;
     404           0 :         pj_time_val_normalize(&delay);
     405             : 
     406           0 :         if (pjsip_endpt_schedule_timer(Manager::instance().sipVoIPLink().getEndpoint(), &timer_, &delay) == PJ_SUCCESS) {
     407           0 :             timer_.id = PJ_TRUE;
     408             :         }
     409             :     }
     410           0 : }
     411             : 
     412             : void
     413           0 : PresSubClient::enable(bool flag)
     414             : {
     415           0 :     JAMI_DBG("pres_client %.*s is %s monitored.", (int) getURI().size(), getURI().data(), flag ? "" : "NOT");
     416           0 :     if (flag and not monitored_)
     417           0 :         pres_->addPresSubClient(this);
     418           0 :     monitored_ = flag;
     419           0 : }
     420             : 
     421             : void
     422           0 : PresSubClient::reportPresence()
     423             : {
     424             :     /* callback*/
     425           0 :     pres_->reportPresSubClientNotification(getURI(), &status_);
     426           0 : }
     427             : 
     428             : bool
     429           0 : PresSubClient::lock()
     430             : {
     431             :     unsigned i;
     432             : 
     433           0 :     for (i = 0; i < 50; i++) {
     434           0 :         if (not pres_->tryLock()) {
     435             :             // FIXME: i/10 in ms, sure!?
     436           0 :             std::this_thread::sleep_for(std::chrono::milliseconds(i / 10));
     437           0 :             continue;
     438             :         }
     439           0 :         lock_flag_ = PRESENCE_LOCK_FLAG;
     440             : 
     441           0 :         if (dlg_ == NULL) {
     442           0 :             pres_->unlock();
     443           0 :             return true;
     444             :         }
     445             : 
     446           0 :         if (pjsip_dlg_try_inc_lock(dlg_) != PJ_SUCCESS) {
     447           0 :             lock_flag_ = 0;
     448           0 :             pres_->unlock();
     449             :             // FIXME: i/10 in ms, sure!?
     450           0 :             std::this_thread::sleep_for(std::chrono::milliseconds(i / 10));
     451           0 :             continue;
     452             :         }
     453             : 
     454           0 :         lock_flag_ = PRESENCE_CLIENT_LOCK_FLAG;
     455           0 :         pres_->unlock();
     456             :     }
     457             : 
     458           0 :     if (lock_flag_ == 0) {
     459           0 :         JAMI_DBG("pres_client failed to lock : timeout");
     460           0 :         return false;
     461             :     }
     462           0 :     return true;
     463             : }
     464             : 
     465             : void
     466           0 : PresSubClient::unlock()
     467             : {
     468           0 :     if (lock_flag_ & PRESENCE_CLIENT_LOCK_FLAG)
     469           0 :         pjsip_dlg_dec_lock(dlg_);
     470             : 
     471           0 :     if (lock_flag_ & PRESENCE_LOCK_FLAG)
     472           0 :         pres_->unlock();
     473           0 : }
     474             : 
     475             : bool
     476           0 : PresSubClient::unsubscribe()
     477             : {
     478           0 :     if (not lock())
     479           0 :         return false;
     480             : 
     481           0 :     monitored_ = false;
     482             : 
     483             :     pjsip_tx_data* tdata;
     484             :     pj_status_t retStatus;
     485             : 
     486           0 :     if (sub_ == NULL or dlg_ == NULL) {
     487           0 :         JAMI_WARN("PresSubClient already unsubscribed.");
     488           0 :         unlock();
     489           0 :         return false;
     490             :     }
     491             : 
     492           0 :     if (pjsip_evsub_get_state(sub_) == PJSIP_EVSUB_STATE_TERMINATED) {
     493           0 :         JAMI_WARN("pres_client already unsubscribed sub=TERMINATED.");
     494           0 :         sub_ = NULL;
     495           0 :         unlock();
     496           0 :         return false;
     497             :     }
     498             : 
     499             :     /* Unsubscribe means send a subscribe with timeout=0s*/
     500           0 :     JAMI_WARN("pres_client %.*s: unsubscribing..", (int) uri_.slen, uri_.ptr);
     501           0 :     retStatus = pjsip_pres_initiate(sub_, 0, &tdata);
     502             : 
     503           0 :     if (retStatus == PJ_SUCCESS) {
     504           0 :         pres_->fillDoc(tdata, NULL);
     505           0 :         retStatus = pjsip_pres_send_request(sub_, tdata);
     506             :     }
     507             : 
     508           0 :     if (retStatus != PJ_SUCCESS and sub_) {
     509           0 :         pjsip_pres_terminate(sub_, PJ_FALSE);
     510           0 :         sub_ = NULL;
     511           0 :         JAMI_WARN("Unable to unsubscribe presence (%d)", retStatus);
     512           0 :         unlock();
     513           0 :         return false;
     514             :     }
     515             : 
     516             :     // pjsip_evsub_set_mod_data(sub_, modId_, NULL);   // Not interested with further events
     517             : 
     518           0 :     unlock();
     519           0 :     return true;
     520             : }
     521             : 
     522             : bool
     523           0 : PresSubClient::subscribe()
     524             : {
     525           0 :     if (sub_ and dlg_) { // do not bother if already subscribed
     526           0 :         pjsip_evsub_terminate(sub_, PJ_FALSE);
     527           0 :         JAMI_DBG("PreseSubClient %.*s: already subscribed. Refresh it.", (int) uri_.slen, uri_.ptr);
     528             :     }
     529             : 
     530             :     // subscribe
     531             :     pjsip_evsub_user pres_callback;
     532             :     pjsip_tx_data* tdata;
     533             :     pj_status_t status;
     534             : 
     535             :     /* Event subscription callback. */
     536           0 :     pj_bzero(&pres_callback, sizeof(pres_callback));
     537           0 :     pres_callback.on_evsub_state = &pres_client_evsub_on_state;
     538           0 :     pres_callback.on_tsx_state = &pres_client_evsub_on_tsx_state;
     539           0 :     pres_callback.on_rx_notify = &pres_client_evsub_on_rx_notify;
     540             : 
     541           0 :     SIPAccount* acc = pres_->getAccount();
     542           0 :     JAMI_DBG("PresSubClient %.*s: subscribing ", (int) uri_.slen, uri_.ptr);
     543             : 
     544             :     /* Create UAC dialog */
     545           0 :     pj_str_t from = pj_strdup3(pool_, acc->getFromUri().c_str());
     546           0 :     status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from, &contact_, &uri_, NULL, &dlg_);
     547             : 
     548           0 :     if (status != PJ_SUCCESS) {
     549           0 :         JAMI_ERR("Unable to create dialog \n");
     550           0 :         return false;
     551             :     }
     552             : 
     553             :     /* Add credential for auth. */
     554           0 :     if (acc->hasCredentials()
     555           0 :         and pjsip_auth_clt_set_credentials(&dlg_->auth_sess,
     556           0 :                                            static_cast<int>(acc->getCredentialCount()),
     557             :                                            acc->getCredInfo())
     558             :                 != PJ_SUCCESS) {
     559           0 :         JAMI_ERR("Unable to initialize credentials for subscribe session authentication");
     560             :     }
     561             : 
     562             :     /* Increment the dialog's lock otherwise when presence session creation
     563             :      * fails the dialog will be destroyed prematurely.
     564             :      */
     565           0 :     pjsip_dlg_inc_lock(dlg_);
     566             : 
     567           0 :     status = pjsip_pres_create_uac(dlg_, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &sub_);
     568             : 
     569           0 :     if (status != PJ_SUCCESS) {
     570           0 :         sub_ = NULL;
     571           0 :         JAMI_WARN("Unable to create presence client (%d)", status);
     572             : 
     573             :         /* This should destroy the dialog since there's no session
     574             :          * referencing it
     575             :          */
     576           0 :         if (dlg_) {
     577           0 :             pjsip_dlg_dec_lock(dlg_);
     578             :         }
     579             : 
     580           0 :         return false;
     581             :     }
     582             : 
     583             :     /* Add credential for authentication */
     584           0 :     if (acc->hasCredentials()
     585           0 :         and pjsip_auth_clt_set_credentials(&dlg_->auth_sess,
     586           0 :                                            static_cast<int>(acc->getCredentialCount()),
     587             :                                            acc->getCredInfo())
     588             :                 != PJ_SUCCESS) {
     589           0 :         JAMI_ERR("Unable to initialize credentials for invite session authentication");
     590           0 :         return false;
     591             :     }
     592             : 
     593             :     /* Set route-set */
     594           0 :     pjsip_regc* regc = acc->getRegistrationInfo();
     595           0 :     if (regc and acc->hasServiceRoute())
     596           0 :         pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(acc->getServiceRoute(), pres_->getPool()));
     597             : 
     598             :     // attach the client data to the sub
     599           0 :     pjsip_evsub_set_mod_data(sub_, modId_, this);
     600             : 
     601           0 :     status = pjsip_pres_initiate(sub_, -1, &tdata);
     602           0 :     if (status != PJ_SUCCESS) {
     603           0 :         if (dlg_)
     604           0 :             pjsip_dlg_dec_lock(dlg_);
     605           0 :         if (sub_)
     606           0 :             pjsip_pres_terminate(sub_, PJ_FALSE);
     607           0 :         sub_ = NULL;
     608           0 :         JAMI_WARN("Unable to create initial SUBSCRIBE (%d)", status);
     609           0 :         return false;
     610             :     }
     611             : 
     612             :     //    pjsua_process_msg_data(tdata, NULL);
     613             : 
     614           0 :     status = pjsip_pres_send_request(sub_, tdata);
     615             : 
     616           0 :     if (status != PJ_SUCCESS) {
     617           0 :         if (dlg_)
     618           0 :             pjsip_dlg_dec_lock(dlg_);
     619           0 :         if (sub_)
     620           0 :             pjsip_pres_terminate(sub_, PJ_FALSE);
     621           0 :         sub_ = NULL;
     622           0 :         JAMI_WARN("Unable to send initial SUBSCRIBE (%d)", status);
     623           0 :         return false;
     624             :     }
     625             : 
     626           0 :     pjsip_dlg_dec_lock(dlg_);
     627           0 :     return true;
     628             : }
     629             : 
     630             : bool
     631           0 : PresSubClient::match(PresSubClient* b)
     632             : {
     633           0 :     return (b->getURI() == getURI());
     634             : }
     635             : 
     636             : } // namespace jami

Generated by: LCOV version 1.14