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
|