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(),
78 : pres_client->getURI().data(),
79 : pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null");
80 :
81 0 : pjsip_evsub_state state = pjsip_evsub_get_state(sub);
82 :
83 0 : SIPPresence* pres = pres_client->getPresence();
84 :
85 0 : if (state == PJSIP_EVSUB_STATE_ACCEPTED) {
86 0 : pres_client->enable(true);
87 0 : emitSignal<libjami::PresenceSignal::SubscriptionStateChanged>(pres->getAccount()->getAccountID(),
88 0 : std::string(pres_client->getURI()),
89 : PJ_TRUE);
90 :
91 0 : pres->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, true);
92 :
93 0 : } else if (state == PJSIP_EVSUB_STATE_TERMINATED) {
94 0 : int resub_delay = -1;
95 0 : pj_strdup_with_null(pres_client->pool_, &pres_client->term_reason_, pjsip_evsub_get_termination_reason(sub));
96 :
97 0 : emitSignal<libjami::PresenceSignal::SubscriptionStateChanged>(pres->getAccount()->getAccountID(),
98 0 : std::string(pres_client->getURI()),
99 : PJ_FALSE);
100 :
101 0 : pres_client->term_code_ = 200;
102 :
103 : /* Determine whether to resubscribe automatically */
104 0 : if (event && event->type == PJSIP_EVENT_TSX_STATE) {
105 0 : const pjsip_transaction* tsx = event->body.tsx_state.tsx;
106 :
107 0 : if (pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) {
108 0 : pres_client->term_code_ = tsx->status_code;
109 0 : std::ostringstream os;
110 0 : os << pres_client->term_code_;
111 0 : const std::string error = os.str() + "/" + sip_utils::as_view(pres_client->term_reason_);
112 :
113 0 : std::string msg;
114 0 : bool subscribe_allowed = PJ_FALSE;
115 :
116 0 : switch (tsx->status_code) {
117 0 : case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST:
118 : /* 481: we refreshed too late? resubscribe
119 : * immediately.
120 : */
121 : /* But this must only happen when the 481 is received
122 : * on subscription refresh request. We MUST NOT try to
123 : * resubscribe automatically if the 481 is received
124 : * on the initial SUBSCRIBE (if server returns this
125 : * response for some reason).
126 : */
127 0 : if (pres_client->dlg_->remote.contact)
128 0 : resub_delay = 500;
129 0 : msg = "Bad subscribe refresh.";
130 0 : subscribe_allowed = PJ_TRUE;
131 0 : break;
132 :
133 0 : case PJSIP_SC_NOT_FOUND:
134 0 : msg = "Subscribe context not set for this buddy.";
135 0 : subscribe_allowed = PJ_TRUE;
136 0 : break;
137 :
138 0 : case PJSIP_SC_FORBIDDEN:
139 0 : msg = "Subscribe not allowed for this buddy.";
140 0 : subscribe_allowed = PJ_TRUE;
141 0 : break;
142 :
143 0 : case PJSIP_SC_PRECONDITION_FAILURE:
144 0 : msg = "Wrong server.";
145 0 : break;
146 : }
147 :
148 : /* report error:
149 : * 1) send a signal through DBus
150 : * 2) change the support field in the account schema if the pres_sub's server
151 : * is the same as the account's server
152 : */
153 0 : emitSignal<libjami::PresenceSignal::ServerError>(pres_client->getPresence()->getAccount()->getAccountID(),
154 : error,
155 : msg);
156 :
157 0 : auto account_host = sip_utils::as_view(*pj_gethostname());
158 0 : auto sub_host = sip_utils::getHostFromUri(pres_client->getURI());
159 :
160 0 : if (not subscribe_allowed and account_host == sub_host)
161 0 : pres_client->getPresence()->getAccount()->supportPresence(PRESENCE_FUNCTION_SUBSCRIBE, false);
162 :
163 0 : } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) {
164 0 : if (pres_client->isTermReason("deactivated") || pres_client->isTermReason("timeout")) {
165 : /* deactivated: The subscription has been terminated,
166 : * but the subscriber SHOULD retry immediately with
167 : * a new subscription.
168 : */
169 : /* timeout: The subscription has been terminated
170 : * because it was not refreshed before it expired.
171 : * Clients MAY re-subscribe immediately. The
172 : * "retry-after" parameter has no semantics for
173 : * "timeout".
174 : */
175 0 : resub_delay = 500;
176 0 : } else if (pres_client->isTermReason("probation") || pres_client->isTermReason("giveup")) {
177 : /* probation: The subscription has been terminated,
178 : * but the client SHOULD retry at some later time.
179 : * If a "retry-after" parameter is also present, the
180 : * client SHOULD wait at least the number of seconds
181 : * specified by that parameter before attempting to re-
182 : * subscribe.
183 : */
184 : /* giveup: The subscription has been terminated because
185 : * the notifier was unable to obtain authorization in a
186 : * timely fashion. If a "retry-after" parameter is
187 : * also present, the client SHOULD wait at least the
188 : * number of seconds specified by that parameter before
189 : * attempting to re-subscribe; otherwise, the client
190 : * MAY retry immediately, but will likely get put back
191 : * into pending state.
192 : */
193 : const pjsip_sub_state_hdr* sub_hdr;
194 0 : constexpr pj_str_t sub_state = CONST_PJ_STR("Subscription-State");
195 : const pjsip_msg* msg;
196 :
197 0 : msg = event->body.tsx_state.src.rdata->msg_info.msg;
198 0 : sub_hdr = (const pjsip_sub_state_hdr*) pjsip_msg_find_hdr_by_name(msg, &sub_state, NULL);
199 :
200 0 : if (sub_hdr && sub_hdr->retry_after > 0)
201 0 : resub_delay = sub_hdr->retry_after * 1000;
202 : }
203 : }
204 : }
205 :
206 : /* For other cases of subscription termination, if resubscribe
207 : * timer is not set, schedule with default expiration (plus minus
208 : * some random value, to avoid sending SUBSCRIBEs all at once)
209 : */
210 0 : if (resub_delay == -1) {
211 0 : resub_delay = PRES_TIMER * 1000;
212 : }
213 :
214 0 : pres_client->sub_ = sub;
215 0 : pres_client->rescheduleTimer(PJ_TRUE, resub_delay);
216 :
217 : } else { // state==ACTIVE ......
218 : // This will clear the last termination code/reason
219 0 : pres_client->term_code_ = 0;
220 0 : pres_client->term_reason_.ptr = NULL;
221 : }
222 :
223 : /* Clear subscription */
224 0 : if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
225 0 : pjsip_evsub_terminate(pres_client->sub_, PJ_FALSE); // = NULL;
226 0 : pres_client->status_.info_cnt = 0;
227 0 : pres_client->dlg_ = NULL;
228 0 : pres_client->rescheduleTimer(PJ_FALSE, 0);
229 0 : pjsip_evsub_set_mod_data(sub, modId_, NULL);
230 :
231 0 : pres_client->enable(false);
232 : }
233 : }
234 :
235 : /* Callback when transaction state has changed. */
236 : void
237 0 : PresSubClient::pres_client_evsub_on_tsx_state(pjsip_evsub* sub, pjsip_transaction* tsx, pjsip_event* event)
238 : {
239 : PresSubClient* pres_client;
240 : pjsip_contact_hdr* contact_hdr;
241 :
242 0 : pres_client = (PresSubClient*) pjsip_evsub_get_mod_data(sub, modId_);
243 : /* No need to pres->lock() here since the client has a locked dialog*/
244 :
245 0 : if (!pres_client) {
246 0 : JAMI_WARN("Unable to find pres_client.");
247 0 : return;
248 : }
249 :
250 : /* We only use this to update pres_client's Contact, when it's not
251 : * set.
252 : */
253 0 : if (pres_client->contact_.slen != 0) {
254 : /* Contact already set */
255 0 : return;
256 : }
257 :
258 : /* Only care about 2xx response to outgoing SUBSCRIBE */
259 0 : if (tsx->status_code / 100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG
260 0 : || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method()) != 0) {
261 0 : return;
262 : }
263 :
264 : /* Find contact header. */
265 0 : contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT, NULL);
266 :
267 0 : if (!contact_hdr || !contact_hdr->uri) {
268 0 : return;
269 : }
270 :
271 0 : pres_client->contact_.ptr = (char*) pj_pool_alloc(pres_client->pool_, PJSIP_MAX_URL_SIZE);
272 0 : pres_client->contact_.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR,
273 0 : contact_hdr->uri,
274 : pres_client->contact_.ptr,
275 : PJSIP_MAX_URL_SIZE);
276 :
277 0 : if (pres_client->contact_.slen < 0)
278 0 : pres_client->contact_.slen = 0;
279 : }
280 :
281 : /* Callback called when we receive NOTIFY */
282 : void
283 0 : PresSubClient::pres_client_evsub_on_rx_notify(pjsip_evsub* sub,
284 : pjsip_rx_data* rdata,
285 : int* p_st_code,
286 : pj_str_t** p_st_text,
287 : pjsip_hdr* res_hdr,
288 : pjsip_msg_body** p_body)
289 : {
290 0 : PresSubClient* pres_client = (PresSubClient*) pjsip_evsub_get_mod_data(sub, modId_);
291 :
292 0 : if (!pres_client) {
293 0 : JAMI_WARN("Unable to find pres_client from ev_sub.");
294 0 : return;
295 : }
296 : /* No need to pres->lock() here since the client has a locked dialog*/
297 :
298 0 : pjsip_pres_get_status(sub, &pres_client->status_);
299 0 : pres_client->reportPresence();
300 :
301 : /* The default is to send 200 response to NOTIFY.
302 : * Just leave it there.
303 : */
304 : PJ_UNUSED_ARG(rdata);
305 : PJ_UNUSED_ARG(p_st_code);
306 : PJ_UNUSED_ARG(p_st_text);
307 : PJ_UNUSED_ARG(res_hdr);
308 : PJ_UNUSED_ARG(p_body);
309 : }
310 :
311 0 : PresSubClient::PresSubClient(const std::string& uri, SIPPresence* pres)
312 0 : : pres_(pres)
313 0 : , uri_ {0, 0}
314 0 : , contact_ {0, 0}
315 0 : , display_()
316 0 : , dlg_(NULL)
317 0 : , monitored_(false)
318 0 : , name_()
319 0 : , cp_()
320 0 : , pool_(0)
321 0 : , status_()
322 0 : , sub_(NULL)
323 0 : , term_code_(0)
324 0 : , term_reason_()
325 0 : , timer_()
326 0 : , user_data_(NULL)
327 0 : , lock_count_(0)
328 0 : , lock_flag_(0)
329 : {
330 0 : pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0);
331 0 : pool_ = pj_pool_create(&cp_.factory, "Pres_sub_client", 512, 512, NULL);
332 0 : uri_ = pj_strdup3(pool_, uri.c_str());
333 0 : contact_ = pj_strdup3(pool_, pres_->getAccount()->getFromUri().c_str());
334 0 : }
335 :
336 0 : PresSubClient::~PresSubClient()
337 : {
338 0 : JAMI_DBG("Destroying pres_client object with uri %.*s", (int) uri_.slen, uri_.ptr);
339 0 : rescheduleTimer(PJ_FALSE, 0);
340 0 : unsubscribe();
341 0 : pj_pool_release(pool_);
342 0 : }
343 :
344 : bool
345 0 : PresSubClient::isSubscribed()
346 : {
347 0 : return monitored_;
348 : }
349 :
350 : std::string_view
351 0 : PresSubClient::getURI()
352 : {
353 0 : return {uri_.ptr, (size_t) uri_.slen};
354 : }
355 :
356 : SIPPresence*
357 0 : PresSubClient::getPresence()
358 : {
359 0 : return pres_;
360 : }
361 :
362 : bool
363 0 : PresSubClient::isPresent()
364 : {
365 0 : return status_.info[0].basic_open;
366 : }
367 :
368 : std::string_view
369 0 : PresSubClient::getLineStatus()
370 : {
371 0 : return {status_.info[0].rpid.note.ptr, (size_t) status_.info[0].rpid.note.slen};
372 : }
373 :
374 : bool
375 0 : PresSubClient::isTermReason(const std::string& reason)
376 : {
377 0 : const std::string_view myReason(term_reason_.ptr, (size_t) term_reason_.slen);
378 0 : return not myReason.compare(reason);
379 : }
380 :
381 : void
382 0 : PresSubClient::rescheduleTimer(bool reschedule, unsigned msec)
383 : {
384 0 : if (timer_.id) {
385 0 : pjsip_endpt_cancel_timer(Manager::instance().sipVoIPLink().getEndpoint(), &timer_);
386 0 : timer_.id = PJ_FALSE;
387 : }
388 :
389 0 : if (reschedule) {
390 : pj_time_val delay;
391 :
392 0 : JAMI_WARN("pres_client %.*s will resubscribe in %u ms (reason: %.*s)",
393 : (int) uri_.slen,
394 : uri_.ptr,
395 : msec,
396 : (int) term_reason_.slen,
397 : term_reason_.ptr);
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_DBG("pres_client %.*s is %s monitored.", (int) getURI().size(), getURI().data(), 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_DBG("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_WARN("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_WARN("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_WARN("pres_client %.*s: unsubscribing..", (int) uri_.slen, uri_.ptr);
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_WARN("Unable to unsubscribe presence (%d)", 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_DBG("PreseSubClient %.*s: already subscribed. Refresh it.", (int) uri_.slen, uri_.ptr);
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_DBG("PresSubClient %.*s: subscribing ", (int) uri_.slen, uri_.ptr);
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_ERR("Unable to create dialog \n");
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, acc->getCredentialCount(), acc->getCredInfo())
553 : != PJ_SUCCESS) {
554 0 : JAMI_ERR("Unable to initialize credentials for subscribe session authentication");
555 : }
556 :
557 : /* Increment the dialog's lock otherwise when presence session creation
558 : * fails the dialog will be destroyed prematurely.
559 : */
560 0 : pjsip_dlg_inc_lock(dlg_);
561 :
562 0 : status = pjsip_pres_create_uac(dlg_, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &sub_);
563 :
564 0 : if (status != PJ_SUCCESS) {
565 0 : sub_ = NULL;
566 0 : JAMI_WARN("Unable to create presence client (%d)", status);
567 :
568 : /* This should destroy the dialog since there's no session
569 : * referencing it
570 : */
571 0 : if (dlg_) {
572 0 : pjsip_dlg_dec_lock(dlg_);
573 : }
574 :
575 0 : return false;
576 : }
577 :
578 : /* Add credential for authentication */
579 0 : if (acc->hasCredentials()
580 0 : and pjsip_auth_clt_set_credentials(&dlg_->auth_sess, acc->getCredentialCount(), acc->getCredInfo())
581 : != PJ_SUCCESS) {
582 0 : JAMI_ERR("Unable to initialize credentials for invite session authentication");
583 0 : return false;
584 : }
585 :
586 : /* Set route-set */
587 0 : pjsip_regc* regc = acc->getRegistrationInfo();
588 0 : if (regc and acc->hasServiceRoute())
589 0 : pjsip_regc_set_route_set(regc, sip_utils::createRouteSet(acc->getServiceRoute(), pres_->getPool()));
590 :
591 : // attach the client data to the sub
592 0 : pjsip_evsub_set_mod_data(sub_, modId_, this);
593 :
594 0 : status = pjsip_pres_initiate(sub_, -1, &tdata);
595 0 : if (status != PJ_SUCCESS) {
596 0 : if (dlg_)
597 0 : pjsip_dlg_dec_lock(dlg_);
598 0 : if (sub_)
599 0 : pjsip_pres_terminate(sub_, PJ_FALSE);
600 0 : sub_ = NULL;
601 0 : JAMI_WARN("Unable to create initial SUBSCRIBE (%d)", status);
602 0 : return false;
603 : }
604 :
605 : // pjsua_process_msg_data(tdata, NULL);
606 :
607 0 : status = pjsip_pres_send_request(sub_, tdata);
608 :
609 0 : if (status != PJ_SUCCESS) {
610 0 : if (dlg_)
611 0 : pjsip_dlg_dec_lock(dlg_);
612 0 : if (sub_)
613 0 : pjsip_pres_terminate(sub_, PJ_FALSE);
614 0 : sub_ = NULL;
615 0 : JAMI_WARN("Unable to send initial SUBSCRIBE (%d)", status);
616 0 : return false;
617 : }
618 :
619 0 : pjsip_dlg_dec_lock(dlg_);
620 0 : return true;
621 : }
622 :
623 : bool
624 0 : PresSubClient::match(PresSubClient* b)
625 : {
626 0 : return (b->getURI() == getURI());
627 : }
628 :
629 : } // namespace jami
|