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

Generated by: LCOV version 1.14