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

Generated by: LCOV version 2.0-1