From 093d8afecffd09a4980a13955c273ce8e285e0b2 Mon Sep 17 00:00:00 2001 From: Patrick Keroulas <patrick.keroulas@savoirfairelinux.com> Date: Wed, 28 Aug 2013 16:35:12 -0400 Subject: [PATCH] * #28472 : Rename all subscribers/buddies related variables. Limit the * size of these lists. Add a tmp fake status for IP2IP subscription. * Change loops to fit c++ 11. Remove code from Manager class. --- daemon/src/client/callmanager.h | 6 +- .../src/client/dbus/callmanager-introspec.xml | 15 +- daemon/src/client/dbus/callmanager.cpp | 62 +- daemon/src/managerimpl.cpp | 24 - daemon/src/managerimpl.h | 16 - daemon/src/sip/Makefile.am | 8 +- daemon/src/sip/presence_subscription.cpp | 300 ---------- daemon/src/sip/presence_subscription.h | 100 ---- daemon/src/sip/sipaccount.cpp | 2 +- daemon/src/sip/sipbuddy.cpp | 552 ------------------ daemon/src/sip/sipbuddy.h | 171 ------ daemon/src/sip/sippresence.cpp | 152 +++-- daemon/src/sip/sippresence.h | 43 +- daemon/src/sip/sippublish.cpp | 63 +- daemon/src/sip/sipvoiplink.cpp | 26 +- daemon/src/sip/sipvoiplink.h | 7 - 16 files changed, 192 insertions(+), 1355 deletions(-) delete mode 100644 daemon/src/sip/presence_subscription.cpp delete mode 100644 daemon/src/sip/presence_subscription.h delete mode 100644 daemon/src/sip/sipbuddy.cpp delete mode 100644 daemon/src/sip/sipbuddy.h diff --git a/daemon/src/client/callmanager.h b/daemon/src/client/callmanager.h index f6fd495ef8..e0733b53b4 100644 --- a/daemon/src/client/callmanager.h +++ b/daemon/src/client/callmanager.h @@ -181,10 +181,10 @@ class CallManager #endif // __ANDROID__ /* Presence subscription/Notification. */ - void subscribePresence(const std::string& accountID, const std::string& buddySipUri); - void unsubscribePresence(const std::string& accountID, const std::string& buddySipUri); + void enablePresence(const std::string& accountID, const bool& flag); void sendPresence(const std::string& accountID, const std::string& status, const std::string& note); - void approvePresenceSubscription(const bool& flag, const std::string& uri); + void approvePresSubServer(const bool& flag, const std::string& uri); + void subscribePresSubClient(const std::string& accountID, const std::string& uri, const bool& flag); private: #if HAVE_ZRTP diff --git a/daemon/src/client/dbus/callmanager-introspec.xml b/daemon/src/client/dbus/callmanager-introspec.xml index 9da2ec54ea..efee97a78b 100644 --- a/daemon/src/client/dbus/callmanager-introspec.xml +++ b/daemon/src/client/dbus/callmanager-introspec.xml @@ -820,16 +820,17 @@ <arg type="b" name="accepted" direction="in"/> </method> - <method name="subscribePresence" tp:name-for-bindings="subscribePresence"> + <method name="subscribePresSubClient" tp:name-for-bindings="subscribePresSubClient"> <tp:added version="0.9.7"/> <arg type="s" name="accountID" direction="in"/> - <arg type="s" name="buddySipUri" direction="in"/> + <arg type="s" name="uri" direction="in"/> + <arg type="b" name="flag" direction="in"/> </method> - <method name="unsubscribePresence" tp:name-for-bindings="unsubscribePresence"> + <method name="enablePresence" tp:name-for-bindings="enablePresence"> <tp:added version="0.9.7"/> <arg type="s" name="accountID" direction="in"/> - <arg type="s" name="buddySipUri" direction="in"/> + <arg type="b" name="flag" direction="in"/> </method> <method name="sendPresence" tp:name-for-bindings="sendPresence"> @@ -839,20 +840,20 @@ <arg type="s" name="note" direction="in"/> </method> - <method name="approvePresenceSubscription" tp:name-for-bindings="approvePresenceSubscription"> + <method name="approvePresSubServer" tp:name-for-bindings="approvePresSubServer"> <tp:added version="0.9.7"/> <arg type="b" name="flag" direction="in"/> <arg type="s" name="uri" direction="in"/> </method> - <signal name="newPresenceNotification" tp:name-for-bindings="newPresenceNotification"> + <signal name="newPresSubClientNotification" tp:name-for-bindings="newPresSubClientNotification"> <tp:added version="0.9.7"/> <arg type="s" name="buddyUri"/> <arg type="s" name="status"/> <arg type="s" name="lineStatus"/> </signal> - <signal name="newPresenceSubscription" tp:name-for-bindings="newPresenceSubscription"> + <signal name="newPresSubServerRequest" tp:name-for-bindings="newPresSubServerRequest"> <arg type="s" name="buddyUri"/> </signal> diff --git a/daemon/src/client/dbus/callmanager.cpp b/daemon/src/client/dbus/callmanager.cpp index 8f3fb40cdb..d7822f41da 100644 --- a/daemon/src/client/dbus/callmanager.cpp +++ b/daemon/src/client/dbus/callmanager.cpp @@ -35,6 +35,8 @@ #include "sip/sipcall.h" #include "sip/sipvoiplink.h" +#include "sip/sipaccount.h" +#include "sip/sippresence.h" #include "audio/audiolayer.h" #include "audio/audiortp/audio_rtp_factory.h" #if HAVE_ZRTP @@ -423,30 +425,64 @@ CallManager::sendTextMessage(const std::string& callID, const std::string& messa #endif } + +/** + * Un/subscribe to buddySipUri for an accountID + */ void -CallManager::subscribePresence(const std::string& accountID, const std::string& buddySipUri) +CallManager::subscribePresSubClient(const std::string& accountID, const std::string& uri, const bool& flag) { - DEBUG("subscribePresence (acc:%s, buddy:%s)",accountID.c_str(), buddySipUri.c_str()); - Manager::instance().subscribePresence(accountID,buddySipUri); + + SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID); + if (!sipaccount) + ERROR("Could not find account %s",accountID.c_str()); + else{ + DEBUG("%subscribePresence (acc:%s, buddy:%s)",flag? "S":"Uns", accountID.c_str(), uri.c_str()); + sipaccount->getPresence()->subscribePresSubClient(uri,flag); + } } +/** + * Enable the presence module (PUBLISH/SUBSCRIBE) + */ void -CallManager::unsubscribePresence(const std::string& accountID, const std::string& buddySipUri) -{ - DEBUG("unsubscribePresence (acc:%s, buddy:%s)",accountID.c_str(), buddySipUri.c_str()); - Manager::instance().unsubscribePresence(accountID,buddySipUri); +CallManager::enablePresence(const std::string& accountID, const bool& flag){ + SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID); + if (!sipaccount) + ERROR("Could not find account %s",accountID.c_str()); + else{ + DEBUG("Enable Presence (acc:%s : %s)",accountID.c_str(), flag? "yes":"no"); + sipaccount->getPresence()->enable(flag); + } } +/** + * push a presence for a account + * Notify for IP2IP account and publish for PBX account + */ void CallManager::sendPresence(const std::string& accountID, const std::string& status, const std::string& note) { - DEBUG("sendPresence (acc:%s, status:%s).",accountID.c_str(),status.c_str()); - Manager::instance().sendPresence(accountID,status,note); + SIPAccount *sipaccount = Manager::instance().getSipAccount(accountID); + if (!sipaccount) + ERROR("Could not find account %s",accountID.c_str()); + else{ + DEBUG("Send Presence (acc:%s)",accountID.c_str()); + sipaccount->getPresence()->sendPresence(status,note); + } } +/** + * Accept or not a PresSubServer request for IP2IP account + */ void -CallManager::approvePresenceSubscription(const bool& flag, const std::string& uri) -{ - DEBUG("approvePresenceSubscription %s : %s.",uri.c_str(), flag? "yes":"no"); - Manager::instance().approvePresenceSubscription(flag, uri); +CallManager::approvePresSubServer(const bool& flag, const std::string& buddySipUri) +{ + SIPAccount *sipaccount = Manager::instance().getIP2IPAccount(); + if (!sipaccount) + ERROR("Could not find account IP2IP"); + else{ + DEBUG("Approve presence (acc:IP2IP, buddy:%s)", buddySipUri.c_str()); + sipaccount->getPresence()->approvePresSubServer(flag, buddySipUri); + } } diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 91bc070178..4fd90f795a 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -2932,30 +2932,6 @@ void ManagerImpl::startAudioDriverStream() audiodriver_->startStream(); } -void ManagerImpl::subscribePresence(const std::string& accountID, const std::string& buddySipUri) -{ - SIPAccount *account = Manager::instance().getSipAccount(accountID); - account->getPresence()->subscribeBuddy(buddySipUri); -} - -void ManagerImpl::unsubscribePresence(const std::string& accountID, const std::string& buddySipUri) -{ - SIPAccount *account = Manager::instance().getSipAccount(accountID); - account->getPresence()->unsubscribeBuddy(buddySipUri); -} - -void ManagerImpl::sendPresence(const std::string& accountID, const std::string& status, const std::string& note) -{ - SIPAccount *account = Manager::instance().getSipAccount(accountID); - account->getPresence()->sendPresence(status,note); -} - -void ManagerImpl::approvePresenceSubscription(const bool& flag, const std::string& uri) -{ - SIPAccount *account = Manager::instance().getSipAccount("IP2IP"); - account->getPresence()->approveServerSubscription(flag, uri); -} - void ManagerImpl::registerAccounts() { diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index 0b8095dd52..e437649a9b 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -1035,22 +1035,6 @@ class ManagerImpl { void checkAudio(); - /** - * Subscribe to buddySipUri for an accountID - */ - void subscribePresence(const std::string& accountID, const std::string& buddySipUri); - void unsubscribePresence(const std::string& accountID, const std::string& buddySipUri); - - /** - * push a presence for a account - * Notify for IP2IP account and publish for PBX account - */ - void sendPresence(const std::string& accountID, const std::string& status, const std::string& note); - /** - * Accept or not a PresenceSubscription request for IP2IP account - */ - void approvePresenceSubscription(const bool& flag, const std::string& uri); - private: NON_COPYABLE(ManagerImpl); diff --git a/daemon/src/sip/Makefile.am b/daemon/src/sip/Makefile.am index 0b75e4f6c8..0bb68fdc2c 100644 --- a/daemon/src/sip/Makefile.am +++ b/daemon/src/sip/Makefile.am @@ -17,10 +17,10 @@ libsiplink_la_SOURCES = \ sip_utils.h \ sippresence.cpp \ sippresence.h \ - sipbuddy.cpp \ - sipbuddy.h \ - presence_subscription.cpp\ - presence_subscription.h\ + pres_sub_server.cpp\ + pres_sub_server.h\ + pres_sub_client.cpp\ + pres_sub_client.h\ sippublish.cpp\ sippublish.h if BUILD_SDES diff --git a/daemon/src/sip/presence_subscription.cpp b/daemon/src/sip/presence_subscription.cpp deleted file mode 100644 index e1c8829c3a..0000000000 --- a/daemon/src/sip/presence_subscription.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. - * - * Author: Patrick Keroulas <patrick.keroulas@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Additional permission under GNU GPL version 3 section 7: - * - * If you modify this program, or any covered work, by linking or - * combining it with the OpenSSL project's OpenSSL library (or a - * modified version of that library), containing parts covered by the - * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. - * grants you additional permission to convey the resulting work. - * Corresponding Source for a non-source form of such a combination - * shall include the source code for the parts of OpenSSL used as well - * as that of the covered work. - */ - - -#include "pjsip/sip_multipart.h" - -#include "sipvoiplink.h" -#include "manager.h" -#include "sippresence.h" -#include "logger.h" -#include "presence_subscription.h" - -/* Callback called when *server* subscription state has changed. */ -void pres_evsub_on_srv_state(pjsip_evsub *sub, pjsip_event *event) { - pjsip_rx_data *rdata = event->body.rx_msg.rdata; - if(!rdata) { - DEBUG("Presence server state has changed but no rdata."); - return; - } - - PJ_UNUSED_ARG(event); - SIPPresence * pres = Manager::instance().getSipAccount("IP2IP")->getPresence(); - pres->lock(); - PresenceSubscription *presenceSub = (PresenceSubscription *) pjsip_evsub_get_mod_data(sub,pres->getModId()); - DEBUG("Presence server subscription to %s is %s", presenceSub->remote, pjsip_evsub_get_state_name(sub)); - - if (presenceSub) { - pjsip_evsub_state state; - - state = pjsip_evsub_get_state(sub); - - if (state == PJSIP_EVSUB_STATE_TERMINATED) { - pjsip_evsub_set_mod_data(sub, pres->getModId(), NULL); - pres->removeServerSubscription(presenceSub); - } - /* TODO check if other cases should be handled*/ - } - pres->unlock(); -} - -pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata) { - - pjsip_method *method = &rdata->msg_info.msg->line.req.method; - pj_str_t *str = &method->name; - std::string request(str->ptr, str->slen); -// pj_str_t contact; - pj_status_t status; - pjsip_dialog *dlg; - pjsip_evsub *sub; - pjsip_evsub_user pres_cb; - pjsip_tx_data *tdata; - pjsip_expires_hdr *expires_hdr; - pjsip_status_code st_code; - pj_str_t reason; - pres_msg_data msg_data; - pjsip_evsub_state ev_state; - - - /* Only hande incoming subscribe messages should be processed here. - * Otherwise we return FALSE to let other modules handle it */ - if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, pjsip_get_subscribe_method()) != 0) - return PJ_FALSE; - - /* debug msg */ - std::string name(rdata->msg_info.to->name.ptr, rdata->msg_info.to->name.slen); - std::string server(rdata->msg_info.from->name.ptr, rdata->msg_info.from->name.slen); - DEBUG("Incomming pres_on_rx_subscribe_request for %s, name:%s, server:%s." - , request.c_str() - , name.c_str() - , server.c_str()); - - /* get parents*/ - std::string accountId = "IP2IP"; /* this code is only used for IP2IP accounts */ - SIPAccount *acc = (SIPAccount *) Manager::instance().getSipAccount(accountId); - pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(); - SIPPresence * pres = acc->getPresence(); - pres->lock(); - - /* Create UAS dialog: */ - std::string c(acc->getContactHeader()); - const pj_str_t contact = pj_str((char*) c.c_str()); - status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); - if (status != PJ_SUCCESS) { - char errmsg[PJ_ERR_MSG_SIZE]; - pj_strerror(status, errmsg, sizeof(errmsg)); - WARN("Unable to create UAS dialog for subscription: %s [status=%d]", errmsg, status); - pres->unlock(); - pjsip_endpt_respond_stateless(endpt, rdata, 400, NULL, NULL, NULL); - return PJ_TRUE; - } - - /* Init callback: */ - pj_bzero(&pres_cb, sizeof(pres_cb)); - pres_cb.on_evsub_state = &pres_evsub_on_srv_state; - - /* Create server presence subscription: */ - status = pjsip_pres_create_uas(dlg, &pres_cb, rdata, &sub); - if (status != PJ_SUCCESS) { - int code = PJSIP_ERRNO_TO_SIP_STATUS(status); - pjsip_tx_data *tdata; - - WARN("Unable to create server subscription %d", status); - - if (code == 599 || code > 699 || code < 300) { - code = 400; - } - - status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata); - if (status == PJ_SUCCESS) { - status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); - } - - pres->unlock(); - return PJ_FALSE; - } - - /* Attach our data to the subscription: */ - char* remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE); - status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, remote, PJSIP_MAX_URL_SIZE); - if (status < 1) - pj_ansi_strcpy(remote, "<-- url is too long-->"); - else - remote[status] = '\0'; - //pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, dlg->local.info->uri, contact.ptr, PJSIP_MAX_URL_SIZE); - - /* Create a new PresenceSubription server and wait for client approve */ - PresenceSubscription *presenceSub = new PresenceSubscription(pres, sub, remote, dlg); - pjsip_evsub_set_mod_data(sub, pres->getModId(), presenceSub); - pres->reportNewServerSubscription(presenceSub); /* Notify the client.*/ - pres->addServerSubscription(presenceSub); - - /* Capture the value of Expires header. */ - expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); - if (expires_hdr) - presenceSub->setExpires(expires_hdr->ivalue); - else - presenceSub->setExpires(-1); - - st_code = (pjsip_status_code) 200; - reason = pj_str("OK"); - pj_bzero(&msg_data, sizeof(msg_data)); - pj_list_init(&msg_data.hdr_list); - pjsip_media_type_init(&msg_data.multipart_ctype, NULL, NULL); - pj_list_init(&msg_data.multipart_parts); - - /* Create and send 2xx response to the SUBSCRIBE request: */ - status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list); - if (status != PJ_SUCCESS) { - WARN("Unable to accept presence subscription %d", status); - pjsip_pres_terminate(sub, PJ_FALSE); - pres->unlock(); - return PJ_FALSE; - } -//TODO: handle rejection case pjsua_pers.c:956 - - -// -------------------------------------------------------------------------------V -// presenceSub->init(); -// return PJ_TRUE; - /*Send notify immediatly*/ - - pjsip_pres_set_status(sub, pres->getStatus()); - - ev_state = PJSIP_EVSUB_STATE_ACTIVE; - if (presenceSub->getExpires() == 0) - ev_state = PJSIP_EVSUB_STATE_TERMINATED; - - /* Create and send the the first NOTIFY to active subscription: */ - pj_str_t stateStr = pj_str(""); - tdata = NULL; - status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata); - if (status == PJ_SUCCESS) { - pres->fillDoc(tdata, &msg_data); - status = pjsip_pres_send_request(sub, tdata); - } - - if (status != PJ_SUCCESS) { - WARN("Unable to create/send NOTIFY %d", status); - pjsip_pres_terminate(sub, PJ_FALSE); - pres->unlock(); - return status; - } - pres->unlock(); - return PJ_TRUE; -} - - - -PresenceSubscription::PresenceSubscription(SIPPresence * pres, pjsip_evsub *evsub, char *r, pjsip_dialog *d) - : pres_(pres) - , sub(evsub) - , remote(r) - , dlg(d) - , expires(-1) - , approved(false) -{} - - -void PresenceSubscription::setExpires(int ms) { - expires = ms; -} - -int PresenceSubscription::getExpires(){ - return expires; -} - -/*SIPPresence * PresenceSubscription::getPresence(){ - return pres_; -}*/ - -bool PresenceSubscription::matches(char *s){ - // servers match if they have the same remote uri and the account ID. - return (!(strcmp(remote,s))) ; -} - -void PresenceSubscription::approve(const bool& flag){ - approved = flag; -} - -/** - * Send the tirst notification. - * FIXME : pjsip_pres_notify crash because the header can't be cloned - * So far, the first notify is sent in sipvoip_pres.c instead. - */ -void PresenceSubscription::init(){ - pjsip_tx_data *tdata = NULL; - pres_msg_data msg_data; - pj_str_t reason = pj_str("OK"); - pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE; - - pjsip_pres_set_status(sub, pres_->getStatus()); - if (expires == 0) - ev_state = PJSIP_EVSUB_STATE_TERMINATED; - - /* Create and send the the first NOTIFY to active subscription: */ - pj_str_t stateStr = pj_str(""); - pj_status_t status = pjsip_pres_notify(sub, ev_state, &stateStr, &reason, &tdata); - if (status == PJ_SUCCESS) { - pres_->fillDoc(tdata, &msg_data); - status = pjsip_pres_send_request(sub, tdata); - } - - if (status != PJ_SUCCESS) { - WARN("Unable to create/send NOTIFY %d", status); - pjsip_pres_terminate(sub, PJ_FALSE); - } -} - -void PresenceSubscription::notify() { - /* Only send NOTIFY once subscription is active. Some subscriptions - * may still be in NULL (when app is adding a new buddy while in the - * on_incoming_subscribe() callback) or PENDING (when user approval is - * being requested) state and we don't send NOTIFY to these subs until - * the user accepted the request. - */ - if ((pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE) && (approved)) { - DEBUG("Notifying %s.", remote); - - pjsip_tx_data *tdata; - pjsip_pres_set_status(sub, pres_->getStatus()); - - if (pjsip_pres_current_notify(sub, &tdata) == PJ_SUCCESS) { - // add msg header and send - pres_->fillDoc(tdata, NULL); - pjsip_pres_send_request(sub, tdata); - } - else{ - WARN("Unable to create/send NOTIFY"); - pjsip_pres_terminate(sub, PJ_FALSE); - } - } -} diff --git a/daemon/src/sip/presence_subscription.h b/daemon/src/sip/presence_subscription.h deleted file mode 100644 index a5ea086a45..0000000000 --- a/daemon/src/sip/presence_subscription.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. - * - * Author: Patrick Keroulas <patrick.keroulas@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Additional permission under GNU GPL version 3 section 7: - * - * If you modify this program, or any covered work, by linking or - * combining it with the OpenSSL project's OpenSSL library (or a - * modified version of that library), containing parts covered by the - * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. - * grants you additional permission to convey the resulting work. - * Corresponding Source for a non-source form of such a combination - * shall include the source code for the parts of OpenSSL used as well - * as that of the covered work. - */ - - -#ifndef SERVERPRESENCESUB_H -#define SERVERPRESENCESUB_H - -#include <pj/string.h> -#include <pjsip/sip_types.h> -#include <pjsip-simple/evsub.h> -#include <pjsip-simple/presence.h> -#include <pjsip/sip_module.h> - -#include "src/noncopyable.h" - -extern pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata); - -static pjsip_module mod_presence_server = { - NULL, NULL, /* prev, next. */ - pj_str("mod-presence-server"), /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_DIALOG_USAGE, - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &pres_on_rx_subscribe_request, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request. */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ - -}; - - -class SIPpresence; - -class PresenceSubscription { - -public: - - PresenceSubscription(SIPPresence * pres, pjsip_evsub *evsub, char *r,pjsip_dialog *d); - - char *remote; /**< Remote URI. */ - - void setExpires(int ms); - int getExpires(); - bool matches(char *s); - void approve(const bool& flag); - /** - * Send the tirst notification. - * FIXME : pjsip_pres_notify crash because the header can't be cloned - * So far, the first notify is sent in pres_on_rx_subscribe_request() instead. - */ - void init(); - void notify(); - - friend void pres_evsub_on_srv_state( pjsip_evsub *sub, pjsip_event *event); - friend pj_bool_t pres_on_rx_subscribe_request(pjsip_rx_data *rdata); - -private: - - NON_COPYABLE(PresenceSubscription); - SIPPresence *pres_; - pjsip_evsub *sub; /**< The evsub. */ - pjsip_dialog *dlg; /**< Dialog. */ - int expires; /**< "expires" value in the request. */ - bool approved; /**< The client approved this subscription*/ -}; - - -#endif /* SERVERPRESENCESUB_H */ diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index 0e5e2bc6cd..881571ff33 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -810,7 +810,7 @@ void SIPAccount::trimCiphers() int sum = 0; int count = 0; // PJSIP aborts if our cipher list exceeds 1010 characters - static const int MAX_CIPHERS_STRLEN = 1010; + static const int MAX_CIPHERS_STRLEN = 1000; for (const auto &item : ciphers_) { sum += strlen(pj_ssl_cipher_name(item)); diff --git a/daemon/src/sip/sipbuddy.cpp b/daemon/src/sip/sipbuddy.cpp deleted file mode 100644 index f91263bc38..0000000000 --- a/daemon/src/sip/sipbuddy.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (C) 2012, 2013 LOTES TM LLC - * Author : Andrey Loukhnov <aol.nnov@gmail.com> - * - * This file is a part of pult5-voip - * - * pult5-voip is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * pult5-voip is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this programm. If not, see <http://www.gnu.org/licenses/>. - * - * Additional permission under GNU GPL version 3 section 7: - * - * If you modify pult5-voip, or any covered work, by linking or - * combining it with the OpenSSL project's OpenSSL library (or a - * modified version of that library), containing parts covered by the - * terms of the OpenSSL or SSLeay licenses, LOTES-TM LLC - * grants you additional permission to convey the resulting work. - * Corresponding Source for a non-source form of such a combination - * shall include the source code for the parts of OpenSSL used as well - * as that of the covered work. - */ - -#include <pj/log.h> -#include <pj/rand.h> -#include <pjsip/sip_module.h> -#include <pjsip/sip_types.h> -#include <pjsip/sip_event.h> -#include <pjsip/sip_transaction.h> -#include <pjsip/sip_dialog.h> -#include <pjsip/sip_endpoint.h> -#include <string> -#include <pj/pool.h> -#include <pjsip/sip_ua_layer.h> -#include <pjsip-simple/evsub.h> -#include <unistd.h> - -#include "sipbuddy.h" -#include "sipaccount.h" -#include "sippresence.h" -#include "sipvoiplink.h" - -#include "manager.h" - -#include "logger.h" - -#define BUDDY_SUB_TERM_REASON_LEN 32 -#define PRES_TIMER 300 - -int modId; - -void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry) { - (void) th; - SIPBuddy *b = (SIPBuddy *) entry->user_data; - b->reportPresence(); -} - -/* Callback called when *client* subscription state has changed. */ -void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event) { - SIPBuddy *buddy; - - PJ_UNUSED_ARG(event); - - /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has - * a dialog attached to it, lock_buddy() will use the dialog - * lock, which we are currently holding! - */ - - buddy = (SIPBuddy *) pjsip_evsub_get_mod_data(sub, modId); - if (buddy) { - buddy->incLock(); - DEBUG("Presence subscription to '%s' is '%s'", buddy->getURI().c_str(), - pjsip_evsub_get_state_name(sub) ? pjsip_evsub_get_state_name(sub) : "null"); - - pjsip_evsub_state state = pjsip_evsub_get_state(sub); - if(state == PJSIP_EVSUB_STATE_ACCEPTED){ - DEBUG("Buddy accepted."); - buddy->accept(); - } - else if (state == PJSIP_EVSUB_STATE_TERMINATED) { - int resub_delay = -1; - -// const pj_str_t *pjTermReason = pjsip_evsub_get_termination_reason(sub); -// std::string termReason(pjTermReason->ptr, -// pjTermReason->slen > BUDDY_SUB_TERM_REASON_LEN? -// BUDDY_SUB_TERM_REASON_LEN: -// pjTermReason->slen -// ); - pj_strdup_with_null(buddy->pool, &buddy->term_reason, pjsip_evsub_get_termination_reason(sub)); -// buddy->setTermReason(termReason); -// buddy->setTermCode(200); - buddy->term_code = 200; - - /* Determine whether to resubscribe automatically */ - if (event && event->type == PJSIP_EVENT_TSX_STATE) { - const pjsip_transaction *tsx = event->body.tsx_state.tsx; - if (pjsip_method_cmp(&tsx->method, &pjsip_subscribe_method) == 0) { -// buddy->setTermCode(tsx->status_code); - buddy->term_code = tsx->status_code; - switch (tsx->status_code) { - case PJSIP_SC_CALL_TSX_DOES_NOT_EXIST: - /* 481: we refreshed too late? resubscribe - * immediately. - */ - /* But this must only happen when the 481 is received - * on subscription refresh request. We MUST NOT try to - * resubscribe automatically if the 481 is received - * on the initial SUBSCRIBE (if server returns this - * response for some reason). - */ - if (buddy->dlg->remote.contact) - resub_delay = 500; - break; - } - } else if (pjsip_method_cmp(&tsx->method, &pjsip_notify_method) == 0) { - if (buddy->isTermReason("deactivated") || buddy->isTermReason("timeout")) { - /* deactivated: The subscription has been terminated, - * but the subscriber SHOULD retry immediately with - * a new subscription. - */ - /* timeout: The subscription has been terminated - * because it was not refreshed before it expired. - * Clients MAY re-subscribe immediately. The - * "retry-after" parameter has no semantics for - * "timeout". - */ - resub_delay = 500; - } else if (buddy->isTermReason("probation") || buddy->isTermReason("giveup")) { - /* probation: The subscription has been terminated, - * but the client SHOULD retry at some later time. - * If a "retry-after" parameter is also present, the - * client SHOULD wait at least the number of seconds - * specified by that parameter before attempting to re- - * subscribe. - */ - /* giveup: The subscription has been terminated because - * the notifier could not obtain authorization in a - * timely fashion. If a "retry-after" parameter is - * also present, the client SHOULD wait at least the - * number of seconds specified by that parameter before - * attempting to re-subscribe; otherwise, the client - * MAY retry immediately, but will likely get put back - * into pending state. - */ - const pjsip_sub_state_hdr *sub_hdr; - pj_str_t sub_state = {"Subscription-State", 18 }; - const pjsip_msg *msg; - - msg = event->body.tsx_state.src.rdata->msg_info.msg; - sub_hdr = (const pjsip_sub_state_hdr*) pjsip_msg_find_hdr_by_name(msg, &sub_state, NULL); - if (sub_hdr && sub_hdr->retry_after > 0) - resub_delay = sub_hdr->retry_after * 1000; - } - - } - } - - /* For other cases of subscription termination, if resubscribe - * timer is not set, schedule with default expiration (plus minus - * some random value, to avoid sending SUBSCRIBEs all at once) - */ - if (resub_delay == -1) { -// pj_assert(PRES_TIMER >= 3); - resub_delay = PRES_TIMER * 1000;// - 2500 + (pj_rand() % 5000); - } - buddy->sub = sub; - buddy->rescheduleTimer(PJ_TRUE, resub_delay); - }/* else { - This will clear the last termination code/reason - buddy->term_code = 0; - buddy->term_reason.ptr = NULL; - }*/ - - /* Clear subscription */ - /* if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { - pjsip_evsub_terminate(buddy->sub, PJ_FALSE); // = NULL; - buddy->status.info_cnt = 0; - buddy->dlg = NULL; - buddy->rescheduleTimer(PJ_FALSE, 0); -// pjsip_evsub_set_mod_data(sub, modId, NULL); - }*/ - -// pj_log_pop_indent(); - buddy->decLock(); - } -} - -/* Callback when transaction state has changed. */ -void buddy_evsub_on_tsx_state(pjsip_evsub *sub, pjsip_transaction *tsx, pjsip_event *event) { - - SIPBuddy *buddy; - pjsip_contact_hdr *contact_hdr; - - /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has - * a dialog attached to it, lock_buddy() will use the dialog - * lock, which we are currently holding! - */ - buddy = (SIPBuddy *) pjsip_evsub_get_mod_data(sub, modId); - if (!buddy) { - return; - } - buddy->incLock(); - - /* We only use this to update buddy's Contact, when it's not - * set. - */ - if (buddy->contact.slen != 0) { - /* Contact already set */ - buddy->decLock(); - return; - } - - /* Only care about 2xx response to outgoing SUBSCRIBE */ - if (tsx->status_code / 100 != 2 || tsx->role != PJSIP_UAC_ROLE || event->type != PJSIP_EVENT_RX_MSG - || pjsip_method_cmp(&tsx->method, pjsip_get_subscribe_method()) != 0) { - buddy->decLock(); - return; - } - - /* Find contact header. */ - contact_hdr = (pjsip_contact_hdr*) pjsip_msg_find_hdr(event->body.rx_msg.rdata->msg_info.msg, PJSIP_H_CONTACT, - NULL); - if (!contact_hdr || !contact_hdr->uri) { - buddy->decLock(); - return; - } - - buddy->contact.ptr = (char*) pj_pool_alloc(buddy->pool, PJSIP_MAX_URL_SIZE); - buddy->contact.slen = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, contact_hdr->uri, buddy->contact.ptr, - PJSIP_MAX_URL_SIZE); - if (buddy->contact.slen < 0) - buddy->contact.slen = 0; - - buddy->decLock(); -} - -/* Callback called when we receive NOTIFY */ -static void buddy_evsub_on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, - pjsip_hdr *res_hdr, pjsip_msg_body **p_body) { - SIPBuddy *buddy; - - /* Note: #937: no need to acuire PJSUA_LOCK here. Since the buddy has - * a dialog attached to it, lock_buddy() will use the dialog - * lock, which we are currently holding! - */ - buddy = (SIPBuddy *) pjsip_evsub_get_mod_data(sub, modId); - if (!buddy) - return; - - pjsip_pres_get_status(sub, &buddy->status); - buddy->reportPresence(); - - /* The default is to send 200 response to NOTIFY. - * Just leave it there.. - */ - PJ_UNUSED_ARG(rdata); - PJ_UNUSED_ARG(p_st_code); - PJ_UNUSED_ARG(p_st_text); - PJ_UNUSED_ARG(res_hdr); - PJ_UNUSED_ARG(p_body); - - buddy->decLock(); -} - -SIPBuddy::SIPBuddy(const std::string& uri_, SIPAccount *acc_) : - acc(acc_), - uri(pj_str(strdup(uri_.c_str()))), - contact(pj_str(strdup(acc->getFromUri().c_str()))), - display(), - dlg(NULL), - monitor(false), - name(), - cp_(), - pool(0), - status(), - sub(NULL), - term_code(0), - term_reason(), - timer(), - user_data(NULL), - lock_count(0) -{ - pj_caching_pool_init(&cp_, &pj_pool_factory_default_policy, 0); - pool = pj_pool_create(&cp_.factory, "buddy", 512, 512, NULL); -} - -SIPBuddy::~SIPBuddy() { - while(lock_count >0) { - usleep(200); - } - DEBUG("Destroying buddy object with uri %s", uri.ptr); - rescheduleTimer(PJ_FALSE, 0); - unsubscribe(); - - pj_pool_release(pool); -} - -bool SIPBuddy::isSubscribed() { - return this->monitor; -} - -std::string SIPBuddy::getURI() { - std::string buddyURI(uri.ptr, uri.slen); - return buddyURI; -} - -bool SIPBuddy::isTermReason(std::string reason) { - std::string myReason(term_reason.ptr, term_reason.slen); - return !myReason.compare(reason); -} - -void SIPBuddy::rescheduleTimer(bool reschedule, unsigned msec) { - if (timer.id) { - // pjsua_cancel_timer(&timer); - pjsip_endpt_cancel_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer); - timer.id = PJ_FALSE; - } - - if (reschedule) { - pj_time_val delay; - - WARN("Resubscribing buddy %.*s in %u ms (reason: %.*s)", - uri.slen, uri.ptr, msec, (int) term_reason.slen, term_reason.ptr); - monitor = PJ_TRUE; - pj_timer_entry_init(&timer, 0, this, &buddy_timer_cb); - delay.sec = 0; - delay.msec = msec; - pj_time_val_normalize(&delay); - - // if (pjsua_schedule_timer(&timer, &delay)==PJ_SUCCESS) - - if (pjsip_endpt_schedule_timer(((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(), &timer, &delay) == PJ_SUCCESS) { -// timer.id = PJ_TRUE; - } - } -} - -void SIPBuddy::accept() { - acc->getPresence()->addBuddy(this); -} - -void SIPBuddy::reportPresence() { - - //incLock(); - /* callback*/ - acc->getPresence()->reportBuddy(getURI(),&status); - //decLock(); -} - - -pj_status_t SIPBuddy::updateSubscription() { - - if (!monitor) { - /* unsubscribe */ - pjsip_tx_data *tdata; - pj_status_t retStatus; - - if (sub == NULL) { - WARN("Buddy already unsubscribed sub=NULL."); - return PJ_SUCCESS; - } - - if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) { - WARN("Buddy already unsubscribed sub=TERMINATED."); - //pjsip_evsub_terminate(sub, PJ_FALSE); // - sub = NULL; - return PJ_SUCCESS; - } - - WARN("Buddy %s: unsubscribing..", uri.ptr); - retStatus = pjsip_pres_initiate(sub, 0, &tdata); - if (retStatus == PJ_SUCCESS) { - acc->getPresence()->fillDoc(tdata, NULL); - /*if (tdata->msg->type == PJSIP_REQUEST_MSG) { - const pj_str_t STR_USER_AGENT = {"User-Agent", 10}; - pj_str_t ua = pj_str(strdup(acc->getUserAgentName().c_str())); - pjsip_hdr *h; - h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &ua); - pjsip_msg_add_hdr(tdata->msg, h); - }*/ - retStatus = pjsip_pres_send_request(sub, tdata); - } - - if (retStatus != PJ_SUCCESS && sub) { - pjsip_pres_terminate(sub, PJ_FALSE); - pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL; - WARN("Unable to unsubscribe presence", status); - } - - pjsip_evsub_set_mod_data(sub, modId, NULL); // Not interested with further events - - return PJ_SUCCESS; - } - -//#if 0 - if (sub && dlg) { //do not bother if already subscribed -// return PJ_SUCCESS; - pjsip_evsub_terminate(sub, PJ_FALSE); - DEBUG("Terminate existing sub."); - } -//#endif - - //subscribe - pjsip_evsub_user pres_callback; -// pj_pool_t *tmp_pool = NULL; // related to "contact field. TODO: check if this is necessary" - - pjsip_tx_data *tdata; - pj_status_t status; - - /* Event subscription callback. */ - pj_bzero(&pres_callback, sizeof(pres_callback)); - pres_callback.on_evsub_state = &buddy_evsub_on_state; - pres_callback.on_tsx_state = &buddy_evsub_on_tsx_state; - pres_callback.on_rx_notify = &buddy_evsub_on_rx_notify; - - DEBUG("Buddy %s: subscribing presence,using account %s..", - uri.ptr, acc->getAccountID().c_str()); - - /* Generate suitable Contact header unless one is already set in - * the account - */ -#if 0 - if (acc->contact.slen) { - contact = acc->contact; - } else { - tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256); - - status = pjsua_acc_create_uac_contact(tmp_pool, &contact, - acc_id, &buddy->uri); - if (status != PJ_SUCCESS) { - pjsua_perror(THIS_FILE, "Unable to generate Contact header", - status); - pj_pool_release(tmp_pool); - pj_log_pop_indent(); - return; - } - } -#endif - /* Create UAC dialog */ - pj_str_t from = pj_str(strdup(acc->getFromUri().c_str())); - status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from, &contact, &uri, NULL, &dlg); - if (status != PJ_SUCCESS) { - ERROR("Unable to create dialog \n"); - return PJ_FALSE; - } - // Add credential for auth. - if (acc->hasCredentials() and pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) { - ERROR("Could not initialize credentials for subscribe session authentication"); - } - - /* Increment the dialog's lock otherwise when presence session creation - * fails the dialog will be destroyed prematurely. - */ - pjsip_dlg_inc_lock(dlg); - - status = pjsip_pres_create_uac(dlg, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &sub); - if (status != PJ_SUCCESS) { - pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL; - WARN("Unable to create presence client", status); - /* This should destroy the dialog since there's no session - * referencing it - */ - if (dlg) { - pjsip_dlg_dec_lock(dlg); - } -// if (tmp_pool) pj_pool_release(tmp_pool); -// pj_log_pop_indent(); - return PJ_SUCCESS; - } -#if 0 - /* If account is locked to specific transport, then lock dialog - * to this transport too. - */ - if (acc->cfg.transport_id != PJSUA_INVALID_ID) { - pjsip_tpselector tp_sel; - pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); - pjsip_dlg_set_transport(buddy->dlg, &tp_sel); - } - - /* Set route-set */ - if (!pj_list_empty(&acc->route_set)) { - pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set); - } - - /* Set credentials */ - if (acc->cred_cnt) { - pjsip_auth_clt_set_credentials(&buddy->dlg->auth_sess - acc->cred_cnt, acc->cred); - } - - /* Set authentication preference */ - pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref); -#endif - modId = ((SIPVoIPLink*) acc->getVoIPLink())->getModId(); - pjsip_evsub_set_mod_data(sub, modId, this); - - status = pjsip_pres_initiate(sub, -1, &tdata); - if (status != PJ_SUCCESS) { - if (dlg) - pjsip_dlg_dec_lock(dlg); - if (sub) { - pjsip_pres_terminate(sub, PJ_FALSE); - } - pjsip_evsub_terminate(sub, PJ_FALSE); // = NULL; - WARN("Unable to create initial SUBSCRIBE", status); -// if (tmp_pool) pj_pool_release(tmp_pool); - return PJ_SUCCESS; - } - -// pjsua_process_msg_data(tdata, NULL); - - status = pjsip_pres_send_request(sub, tdata); - if (status != PJ_SUCCESS) { - if (dlg) - pjsip_dlg_dec_lock(dlg); - if (sub) { - pjsip_pres_terminate(sub, PJ_FALSE); - sub = NULL; - } - - WARN("Unable to send initial SUBSCRIBE", status); -// if (tmp_pool) pj_pool_release(tmp_pool); - return PJ_SUCCESS; - } - - pjsip_dlg_dec_lock(dlg); -// if (tmp_pool) pj_pool_release(tmp_pool); - return PJ_SUCCESS; -} - -bool SIPBuddy::subscribe() { - monitor = true; - return ((updateSubscription() == PJ_SUCCESS))? true : false; -} - -bool SIPBuddy::unsubscribe() { - monitor = false; - return ((updateSubscription() == PJ_SUCCESS))? true : false; -} - -bool SIPBuddy::match(SIPBuddy *b){ - //return !(strcmp(b->getURI(),getURI())); - return (b->getURI()==getURI()); -} diff --git a/daemon/src/sip/sipbuddy.h b/daemon/src/sip/sipbuddy.h deleted file mode 100644 index 93905edf7d..0000000000 --- a/daemon/src/sip/sipbuddy.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2012, 2013 LOTES TM LLC - * Author : Andrey Loukhnov <aol.nnov@gmail.com> - * Author : Patrick Keroulas <patrick.keroulas@savoirfairelinux.com> - * This file is a part of pult5-voip - * - * pult5-voip is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * pult5-voip is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this programm. If not, see <http://www.gnu.org/licenses/>. - * - * Additional permission under GNU GPL version 3 section 7: - * - * If you modify pult5-voip, or any covered work, by linking or - * combining it with the OpenSSL project's OpenSSL library (or a - * modified version of that library), containing parts covered by the - * terms of the OpenSSL or SSLeay licenses, LOTES-TM LLC - * Corresponding Source for a non-source form of such a combination - * shall include the source code for the parts of OpenSSL used as well - * as that of the covered work. - */ - -#ifndef SIPBUDDY_H -#define SIPBUDDY_H - -#include <pjsip-simple/presence.h> -#include <pj/timer.h> -#include <pj/pool.h> -#include <string> - -#include <pjsip-simple/evsub.h> -#include <pjsip-simple/evsub_msg.h> -#include <pjsip/sip_endpoint.h> -#include <pjsip/sip_transport.h> -#include "noncopyable.h" - -class SIPAccount; - -/** - * Transaction functions of event subscription client side. - */ -static void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event); -static void buddy_evsub_on_tsx_state(pjsip_evsub *sub, - pjsip_transaction *tsx, - pjsip_event *event); -static void buddy_evsub_on_rx_notify(pjsip_evsub *sub, - pjsip_rx_data *rdata, - int *p_st_code, - pj_str_t **p_st_text, - pjsip_hdr *res_hdr, - pjsip_msg_body **p_body); -static void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry); - - -class SIPBuddy { - - public: - /** - * Constructor - * @param uri SIP uri of remote user that we want to subscribe, - */ - SIPBuddy(const std::string &uri, SIPAccount *acc); - /** - * Destructor. - * Process the the unsubscription before the destruction. - */ - ~SIPBuddy(); - /** - * Compare with another buddy's uris. - * @param b Other buddy pointer - */ - bool match(SIPBuddy *b); - /** - * The PBX must approve the subrciption before the buddy is added in the buddy list. - */ - void accept(); - /** - * Send a SUBCRIBE to the PXB or directly to a buddy in the IP2IP context. - */ - bool subscribe(); - /** - * Send a SUBCRIBE to the PXB or directly to a buddy in the IP2IP context but - * the 0s timeout make the dialog expire immediatly. - */ - bool unsubscribe(); - /** - * Return the monitor variable. - */ - bool isSubscribed(); - /** - * Return the buddy URI - */ - std::string getURI(); - - - friend void buddy_evsub_on_state(pjsip_evsub *sub, pjsip_event *event); - friend void buddy_evsub_on_tsx_state(pjsip_evsub *sub, - pjsip_transaction *tsx, - pjsip_event *event); - friend void buddy_evsub_on_rx_notify(pjsip_evsub *sub, - pjsip_rx_data *rdata, - int *p_st_code, - pj_str_t **p_st_text, - pjsip_hdr *res_hdr, - pjsip_msg_body **p_body); - friend void buddy_timer_cb(pj_timer_heap_t *th, pj_timer_entry *entry); - - /** - * TODO: explain this: - */ - void incLock() { - lock_count++; - } - void decLock() { - lock_count--; - } - - private: - - NON_COPYABLE(SIPBuddy); - /** - * Plan a retry or a renew a subscription. - * @param reschedule Allow for reschedule. - * @param msec Delay value in milliseconds. - */ - void rescheduleTimer(bool reschedule, unsigned msec); - /** - * Callback after a presence notification was received. - * Tranfert info to the SIP account. - */ - void reportPresence(); - /** - * Process the un/subscribe request transmission. - */ - pj_status_t updateSubscription(); - /* - * Compare the reason of a transaction end with the given string. - */ - bool isTermReason(std::string); - /** - * return the code after a transaction is terminated. - */ - unsigned getTermCode(); - - SIPAccount *acc; /**< Associated SIP account pointer */ - pj_str_t uri; /**< Buddy URI. */ - pj_str_t contact; /**< Contact learned from subscrp. */ - pj_str_t display; /**< Buddy display name. */ - pjsip_dialog *dlg; /**< The underlying dialog. */ - pj_bool_t monitor; /**< Should we monitor? */ - pj_str_t name; /**< Buddy name. */ - pj_caching_pool cp_; - pj_pool_t *pool; /**< Pool for this buddy. */ - pjsip_pres_status status; /**< Buddy presence status. */ - pjsip_evsub *sub; /**< Buddy presence subscription */ - unsigned term_code; /**< Subscription termination code */ - pj_str_t term_reason;/**< Subscription termination reason */ - pj_timer_entry timer; /**< Resubscription timer */ - void *user_data; /**< Application data. */ - int lock_count; -}; - -#endif /* SIPBUDDY_H */ diff --git a/daemon/src/sip/sippresence.cpp b/daemon/src/sip/sippresence.cpp index 1aaab76a78..2fc006307a 100644 --- a/daemon/src/sip/sippresence.cpp +++ b/daemon/src/sip/sippresence.cpp @@ -35,23 +35,24 @@ #include "client/client.h" #include "client/callmanager.h" #include "sipaccount.h" -#include "sipbuddy.h" #include "sippublish.h" #include "sippresence.h" -#include "presence_subscription.h" +#include "pres_sub_server.h" +#include "pres_sub_client.h" #include "sipvoiplink.h" - +#define MAX_N_PRES_SUB_SERVER 20 +#define MAX_N_PRES_SUB_CLIENT 20 SIPPresence::SIPPresence(SIPAccount *acc) : pres_status_data() , online_status() , publish_sess() , publish_state() - , publish_enabled(true) + , enabled(true) , acc_(acc) - , serverSubscriptions_ () - , buddies_ () + , pres_sub_server_list_ () //IP2IP context + , pres_sub_client_list_ () , mutex_() , mutex_nesting_level_() , mutex_owner_() @@ -73,12 +74,10 @@ SIPPresence::SIPPresence(SIPAccount *acc) SIPPresence::~SIPPresence(){ /* Flush the lists */ - std::list< PresenceSubscription *>::iterator serverIt; - std::list< SIPBuddy *>::iterator buddyIt; - for (buddyIt = buddies_.begin(); buddyIt != buddies_.end(); buddyIt++) - delete *buddyIt; - for (serverIt = serverSubscriptions_.begin(); serverIt != serverSubscriptions_.end(); serverIt++) - delete *serverIt; + for (auto c : pres_sub_client_list_) + removePresSubClient(c) ; + for (auto s : pres_sub_server_list_) + removePresSubServer(s); } SIPAccount * SIPPresence::getAccount(){ @@ -97,6 +96,10 @@ pj_pool_t* SIPPresence::getPool(){ return pool_; } +void SIPPresence::enable(const bool& flag){ + enabled = flag; +} + void SIPPresence::updateStatus(const std::string &status, const std::string ¬e){ //char* pj_note = (char*) pj_pool_alloc(pool_, "50"); @@ -104,14 +107,13 @@ void SIPPresence::updateStatus(const std::string &status, const std::string ¬ pj_str("20"), PJRPID_ACTIVITY_UNKNOWN, pj_str((char *) note.c_str())}; - //pj_str(strdup(note.c_str()))}; /*TODO : del strdup*/ /* fill activity if user not available. */ if(note=="away") rpid.activity = PJRPID_ACTIVITY_AWAY; else if (note=="busy") rpid.activity = PJRPID_ACTIVITY_BUSY; - else + else // TODO: is there any other possibilities DEBUG("Presence : no activity"); pj_bzero(&pres_status_data, sizeof(pres_status_data)); @@ -124,91 +126,95 @@ void SIPPresence::updateStatus(const std::string &status, const std::string ¬ void SIPPresence::sendPresence(const std::string &status, const std::string ¬e){ updateStatus(status,note); - if (acc_->isIP2IP()) - notifyServerSubscription(); // to each subscribers - else - pres_publish(this); // to sipvoip server + if(enabled){ + if (acc_->isIP2IP()) + notifyPresSubServer(); // to each subscribers + else + pres_publish(this); // to the PBX server + } } -void SIPPresence::reportBuddy(const std::string& buddySipUri, pjsip_pres_status * status){ +void SIPPresence::reportPresSubClientNotification(const std::string& uri, pjsip_pres_status * status){ /* Update our info. See pjsua_buddy_get_info() for additionnal ideas*/ const std::string basic(status->info[0].basic_open ? "open" : "closed"); const std::string note(status->info[0].rpid.note.ptr,status->info[0].rpid.note.slen); - DEBUG(" Received presenceStateChange for %s status=%s note=%s",buddySipUri.c_str(),basic.c_str(),note.c_str()); + DEBUG(" Received presenceStateChange for %s status=%s note=%s",uri.c_str(),basic.c_str(),note.c_str()); /* report status to client signal */ - Manager::instance().getClient()->getCallManager()->newPresenceNotification(buddySipUri, basic, note); + Manager::instance().getClient()->getCallManager()->newPresSubClientNotification(uri, basic, note); } -void SIPPresence::subscribeBuddy(const std::string& buddySipUri){ - std::list< SIPBuddy *>::iterator buddyIt; - for (buddyIt = buddies_.begin(); buddyIt != buddies_.end(); buddyIt++) - if((*buddyIt)->getURI()==buddySipUri){ - DEBUG("-Buddy:%s exist in the list. Replace it.",buddySipUri.c_str()); - delete *buddyIt; - removeBuddy(*buddyIt); +void SIPPresence::subscribePresSubClient(const std::string& uri, const bool& flag){ + /* Check if the buddy was already subscribed */ + for(auto c : pres_sub_client_list_) + if(c->getURI()==uri){ + DEBUG("-PresSubClient:%s exists in the list. Replace it.",uri.c_str()); + delete c; + removePresSubClient(c); break; } - SIPBuddy *b = new SIPBuddy(buddySipUri, acc_); - if(!(b->subscribe())){ - WARN("Failed to add buddy."); - delete b; - } -} -void SIPPresence::unsubscribeBuddy(const std::string& buddySipUri){ - std::list< SIPBuddy *>::iterator buddyIt; - for (buddyIt = buddies_.begin(); buddyIt != buddies_.end(); buddyIt++) - if((*buddyIt)->getURI()==buddySipUri){ - DEBUG("-Found buddy:%s in the buddy list.",buddySipUri.c_str()); - delete *buddyIt; - removeBuddy(*buddyIt); - return; + if(flag){ + PresSubClient *b = new PresSubClient(uri, acc_); + if(!(b->subscribe())){ + WARN("Failed send subscribe."); + delete b; } + // the buddy has to be accepted before being added in the list + } } -void SIPPresence::addBuddy(SIPBuddy *b){ - DEBUG("-New buddy subscription added in the buddy list."); - buddies_.push_back(b); +void SIPPresence::addPresSubClient(PresSubClient *b){ + if(pres_sub_client_list_.size() < MAX_N_PRES_SUB_CLIENT){ + pres_sub_client_list_.push_back(b); + DEBUG("-New Presence_subscription_client client added in the list[l=%i].",pres_sub_client_list_.size()); + } + else{ + WARN("-Max Presence_subscription_client is reach."); + delete b; + } } -void SIPPresence::removeBuddy(SIPBuddy *b){ - DEBUG("-Buddy subscription removed from the buddy list."); - buddies_.remove(b); + +void SIPPresence::removePresSubClient(PresSubClient *b){ + DEBUG("-Presence_subscription_client removed from the buddy list."); + pres_sub_client_list_.remove(b); } -void SIPPresence::reportNewServerSubscription(PresenceSubscription *s){ - //newPresenceSubscription_ = s; - Manager::instance().getClient()->getCallManager()->newPresenceSubscription(s->remote); +void SIPPresence::reportNewPresSubServerRequest(PresSubServer *s){ + Manager::instance().getClient()->getCallManager()->newPresSubServerRequest(s->remote); } -void SIPPresence::approveServerSubscription(const bool& flag, const std::string& uri){ - std::list< PresenceSubscription *>::iterator serverIt; - for (serverIt = serverSubscriptions_.begin(); serverIt != serverSubscriptions_.end(); serverIt++){ - if((*serverIt)->matches((char *) uri.c_str())){ - DEBUG("-Approve subscription for %s.",(*serverIt)->remote); - (*serverIt)->approve(flag); +void SIPPresence::approvePresSubServer(const bool& flag, const std::string& uri){ + for (auto s : pres_sub_server_list_) + if(s->matches((char *) uri.c_str())){ + DEBUG("-Approve Presence_subscription_server for %s.",s->remote); + s->approve(flag); // return; // 'return' would prevent multiple-time subscribers from spam } - } } -void SIPPresence::addServerSubscription(PresenceSubscription *s) { - DEBUG("-PresenceServer subscription added: %s.",s->remote); - serverSubscriptions_.push_back(s); +void SIPPresence::addPresSubServer(PresSubServer *s) { + if(pres_sub_server_list_.size() < MAX_N_PRES_SUB_SERVER){ + DEBUG("-Presence_subscription_server added: %s.",s->remote); + pres_sub_server_list_.push_back(s); + } + else{ + WARN("-Max Presence_subscription_server is reach."); + delete s; + } } -void SIPPresence::removeServerSubscription(PresenceSubscription *s) { - serverSubscriptions_.remove(s); - DEBUG("-PresenceServer removed"); +void SIPPresence::removePresSubServer(PresSubServer *s) { + pres_sub_server_list_.remove(s); + DEBUG("-Presence_subscription_server removed"); } -void SIPPresence::notifyServerSubscription() { - std::list< PresenceSubscription *>::iterator serverIt; - DEBUG("-Iterating through PresenceServers:"); - for (serverIt = serverSubscriptions_.begin(); serverIt != serverSubscriptions_.end(); serverIt++) - (*serverIt)->notify(); +void SIPPresence::notifyPresSubServer() { + DEBUG("-Iterating through Presence_subscription_server:"); + for (auto s : pres_sub_server_list_) + s->notify(); } @@ -251,14 +257,6 @@ void SIPPresence::fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data) pj_str_t pJuseragent = pj_str((char*) useragent.c_str()); pjsip_hdr *h = (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_USER_AGENT, &pJuseragent); pjsip_msg_add_hdr(tdata->msg, h); - - /*pjsip_hdr hdr_list; - pj_list_init(&hdr_list); - std::string useragent(account->getUserAgentName()); - pj_str_t pJuseragent = pj_str((char*) useragent.c_str()); - const pj_str_t STR_USER_AGENT = { (char*) "User-Agent", 10 }; - pjsip_generic_string_hdr *h = pjsip_generic_string_hdr_create(pool_, &STR_USER_AGENT, &pJuseragent); - */ } if(msg_data == NULL) diff --git a/daemon/src/sip/sippresence.h b/daemon/src/sip/sippresence.h index 4fb549871c..1dae8372fb 100644 --- a/daemon/src/sip/sippresence.h +++ b/daemon/src/sip/sippresence.h @@ -88,8 +88,8 @@ struct pres_msg_data class SIPAccount; -class SIPBuddy; -class PresenceSubscription; +class PresSubClient; +class PresSubServer; /** * TODO Clean this: */ @@ -132,6 +132,10 @@ public: */ pj_pool_t* getPool(); /** + * Activate the module (PUBLISH/SUBSCRIBE) + */ + void enable(const bool& flag); + /** * Fill xml document, the header and the body */ void fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data); @@ -149,60 +153,53 @@ public: * Send a signal to the client on DBus. The signal contain the status * of a remote user. */ - void reportBuddy(const std::string& buddySipUri, pjsip_pres_status * status); + void reportPresSubClientNotification(const std::string& uri, pjsip_pres_status * status); /** * Send a SUBSCRIBE request to PBX/IP2IP * @param buddyUri Remote user that we want to subscribe */ - void subscribeBuddy(const std::string& buddySipUri); - /** - * Send a SUBSCRIBE request to PBX/IP2IP but the the 0s timeout makes - * the dialog expire immediatly. - * @param buddyUri Remote user that we want to unsubscribe - */ - void unsubscribeBuddy(const std::string& buddySipUri); - + void subscribePresSubClient(const std::string& uri, const bool& flag); /** * Add a buddy in the buddy list. - * @param b Buddy pointer + * @param b PresSubClient pointer */ - void addBuddy(SIPBuddy *b); + void addPresSubClient(PresSubClient *b); /** * Remove a buddy from the list. - * @param b Buddy pointer + * @param b PresSubClient pointer */ - void removeBuddy(SIPBuddy *b); + void removePresSubClient(PresSubClient *b); /** * IP2IP context. * Report new Subscription to the client, waiting for approval. * @param s PresenceSubcription pointer. */ - void reportNewServerSubscription(PresenceSubscription *s); + void reportNewPresSubServerRequest(PresSubServer *s); /** * IP2IP context. * Process new subscription based on client decision. * @param flag client decision. * @param uri uri of the remote subscriber */ - void approveServerSubscription(const bool& flag, const std::string& uri); + void approvePresSubServer(const bool& flag, const std::string& uri); /** * IP2IP context. * Add a server associated to a subscriber in the list. * @param s PresenceSubcription pointer. */ - void addServerSubscription(PresenceSubscription *s); + void addPresSubServer(PresSubServer *s); /** * IP2IP context. * Remove a server associated to a subscriber from the list. * @param s PresenceSubcription pointer. */ - void removeServerSubscription(PresenceSubscription *s); + void removePresSubServer(PresSubServer *s); /** * IP2IP context. * Iterate through the subscriber list and send NOTIFY to each. */ - void notifyServerSubscription(); + void notifyPresSubServer(); /** * Lock methods @@ -216,14 +213,14 @@ public: pj_bool_t online_status; /**< Our online status. */ pjsip_publishc *publish_sess; /**< Client publication session.*/ pj_bool_t publish_state; /**< Last published online status.*/ - pj_bool_t publish_enabled; /**< Allow for status publish,*/ + pj_bool_t enabled; /**< Allow for status publish,*/ private: NON_COPYABLE(SIPPresence); SIPAccount * acc_; /**< Associated SIP account. */ - std::list< PresenceSubscription *> serverSubscriptions_; /**< Subscribers list.*/ - std::list< SIPBuddy *> buddies_; /**< Subcribed buddy list.*/ + std::list< PresSubServer *> pres_sub_server_list_; /**< Subscribers list.*/ + std::list< PresSubClient *> pres_sub_client_list_; /**< Subcribed buddy list.*/ pj_mutex_t *mutex_; /**< Mutex protection for this data */ unsigned mutex_nesting_level_; /**< Mutex nesting level. */ diff --git a/daemon/src/sip/sippublish.cpp b/daemon/src/sip/sippublish.cpp index cf04602b1a..7ba2115759 100644 --- a/daemon/src/sip/sippublish.cpp +++ b/daemon/src/sip/sippublish.cpp @@ -200,45 +200,40 @@ pj_status_t pres_publish(SIPPresence *pres) pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint(); /* Create and init client publication session */ - if (pres->publish_enabled) { - /* Create client publication */ - status = pjsip_publishc_create(endpt,&my_publish_opt, - pres, &pres_publish_cb, - &pres->publish_sess); - if (status != PJ_SUCCESS) { - pres->publish_sess = NULL; - ERROR("Failed to create a publish seesion."); - return status; - } - - /* Initialize client publication */ - pj_str_t from = pj_str(strdup(acc->getFromUri().c_str())); - status = pjsip_publishc_init(pres->publish_sess, &STR_PRESENCE,&from, &from, &from, 0xFFFF); - if (status != PJ_SUCCESS) { - ERROR("Failed to init a publish session"); - pres->publish_sess = NULL; - return status; - } + /* Create client publication */ + status = pjsip_publishc_create(endpt,&my_publish_opt, + pres, &pres_publish_cb, + &pres->publish_sess); + if (status != PJ_SUCCESS) { + pres->publish_sess = NULL; + ERROR("Failed to create a publish seesion."); + return status; + } - /* Add credential for authentication */ - if (acc->hasCredentials() and pjsip_publishc_set_credentials(pres->publish_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) { - ERROR("Could not initialize credentials for invite session authentication"); - return status; - } + /* Initialize client publication */ + pj_str_t from = pj_str(strdup(acc->getFromUri().c_str())); + status = pjsip_publishc_init(pres->publish_sess, &STR_PRESENCE,&from, &from, &from, 0xFFFF); + if (status != PJ_SUCCESS) { + ERROR("Failed to init a publish session"); + pres->publish_sess = NULL; + return status; + } - /* Set route-set */ - if (acc->hasServiceRoute()) - pjsip_regc_set_route_set(acc->getRegistrationInfo(), sip_utils::createRouteSet(acc->getServiceRoute(), pres->getPool())); + /* Add credential for authentication */ + if (acc->hasCredentials() and pjsip_publishc_set_credentials(pres->publish_sess, acc->getCredentialCount(), acc->getCredInfo()) != PJ_SUCCESS) { + ERROR("Could not initialize credentials for invite session authentication"); + return status; + } - /* Send initial PUBLISH request */ - status = pres_send_publish(pres, PJ_TRUE); - if (status != PJ_SUCCESS) - return status; + /* Set route-set */ + if (acc->hasServiceRoute()) + pjsip_regc_set_route_set(acc->getRegistrationInfo(), sip_utils::createRouteSet(acc->getServiceRoute(), pres->getPool())); - } else { - pres->publish_sess = NULL; - } + /* Send initial PUBLISH request */ + status = pres_send_publish(pres, PJ_TRUE); + if (status != PJ_SUCCESS) + return status; return PJ_SUCCESS; } diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index 0d413698b5..1fd38cc484 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -80,9 +80,9 @@ #include <utility> // for std::pair #include <algorithm> -#include "presence_subscription.h" -#include"pjsip-simple/presence.h" -#include"pjsip-simple/publish.h" +#include "pjsip-simple/presence.h" +#include "pjsip-simple/publish.h" +#include "pres_sub_server.h" using namespace sfl; @@ -171,7 +171,6 @@ void handleIncomingOptions(pjsip_rx_data *rdata) // return PJ_FALSE so that eventuall other modules will handle these requests // TODO: move Voicemail to separate module -// TODO: add Buddy presence in separate module pj_bool_t transaction_response_cb(pjsip_rx_data *rdata) { pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata); @@ -515,7 +514,6 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), sipAccountMap_(), , keyframeRequestsMutex_() , keyframeRequests_() #endif - , presenceState() { #define TRY(ret) do { \ @@ -2405,24 +2403,6 @@ void setCallMediaLocal(SIPCall* call, const std::string &localIP) } } // end anonymous namespace -/* -// pkeroulas : is this usefull -void SIPVoIPLink::setPresenceState(const std::string &accId, const std::string& state) { - this->presenceState = state; -#if 0 // ELOI : modify account management - SIPAccount *acc = dynamic_cast<SIPAccount*>(Phone::instance().getAccountById(accId)); - acc->notifyServers(presenceState, channelState); -#else - SIPAccount *acc = Manager::instance().getSipAccount(accId); - //no need of channelStatte. We put it to NULL - acc->notifyServerSubscription(presenceState, NULL); -#endif -} -std::string SIPVoIPLink::getPresenceState() { - return this->presenceState; -} // end anonymous namespace -*/ - int SIPVoIPLink::getModId() { return mod_ua_.id; } diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h index 8c2db215b6..8caf833ec8 100644 --- a/daemon/src/sip/sipvoiplink.h +++ b/daemon/src/sip/sipvoiplink.h @@ -298,16 +298,9 @@ class SIPVoIPLink : public VoIPLink { std::string getAccountIdFromNameAndServer(const std::string &userName, const std::string &server) const; - // ELOI add of variables - std::string presenceState; - //--- - // ELOI add of those prototypes - void setPresenceState(const std::string &accId, const std::string& state); - std::string getPresenceState(); int getModId(); pjsip_endpoint * getEndpoint(); pjsip_module * getMod(); - //--- private: NON_COPYABLE(SIPVoIPLink); -- GitLab