Commit 77b017ca authored by Tristan Matthews's avatar Tristan Matthews

* #29736: presence: merge sippublish into sippresence

parent f03f5101
......@@ -20,9 +20,8 @@ libsiplink_la_SOURCES = \
pres_sub_server.cpp\
pres_sub_server.h\
pres_sub_client.cpp\
pres_sub_client.h\
sippublish.cpp\
sippublish.h
pres_sub_client.h
if BUILD_SDES
libsiplink_la_SOURCES+= sdes_negotiator.cpp \
sdes_negotiator.h \
......
......@@ -30,14 +30,14 @@
*/
#include "sippresence.h"
#include "logger.h"
#include "manager.h"
#include "client/client.h"
#include "client/callmanager.h"
#include "client/presencemanager.h"
#include "sipaccount.h"
#include "sippublish.h"
#include "sippresence.h"
#include "sip_utils.h"
#include "pres_sub_server.h"
#include "pres_sub_client.h"
#include "sipvoiplink.h"
......@@ -46,7 +46,7 @@
#define MAX_N_PRES_SUB_CLIENT 20
SIPPresence::SIPPresence(SIPAccount *acc)
: publish_sess()
: publish_sess_()
, pres_status_data_()
, enabled_(true)
, acc_(acc)
......@@ -74,10 +74,10 @@ SIPPresence::SIPPresence(SIPAccount *acc)
SIPPresence::~SIPPresence()
{
/* Flush the lists */
for (const auto &c : pres_sub_client_list_)
for (const auto & c : pres_sub_client_list_)
removePresSubClient(c) ;
for (const auto &s : pres_sub_server_list_)
for (const auto & s : pres_sub_server_list_)
removePresSubServer(s);
}
......@@ -160,13 +160,14 @@ void SIPPresence::reportPresSubClientNotification(const std::string& uri, pjsip_
void SIPPresence::subscribeClient(const std::string& uri, bool flag)
{
/* Check if the buddy was already subscribed */
for (const auto &c : pres_sub_client_list_)
for (const 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;
}
}
if (pres_sub_client_list_.size() >= MAX_N_PRES_SUB_CLIENT) {
WARN("Can't add PresSubClient, max number reached.");
......@@ -210,12 +211,13 @@ void SIPPresence::reportnewServerSubscriptionRequest(PresSubServer *s)
void SIPPresence::approvePresSubServer(const std::string& uri, bool flag)
{
for (const auto &s : pres_sub_server_list_)
for (const auto & s : pres_sub_server_list_) {
if (s->matches((char *) uri.c_str())) {
DEBUG("Approve Presence_subscription_server for %s: %s.", s->remote, flag ? "true" : "false");
s->approve(flag);
// return; // 'return' would prevent multiple-time subscribers from spam
}
}
}
......@@ -240,7 +242,7 @@ void SIPPresence::notifyPresSubServer()
{
DEBUG("Iterating through Presence_subscription_server:");
for (const auto &s : pres_sub_server_list_)
for (const auto & s : pres_sub_server_list_)
s->notify();
}
......@@ -292,3 +294,190 @@ void SIPPresence::fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data)
tdata->msg->body = body;
}
}
static const pjsip_publishc_opt my_publish_opt = {true}; // this is queue_request
/*
* Client presence publication callback.
*/
void
SIPPresence::pres_publish_cb(struct pjsip_publishc_cbparam *param)
{
SIPPresence *pres = (SIPPresence*) param->token;
if (param->code / 100 != 2 || param->status != PJ_SUCCESS) {
pjsip_publishc_destroy(param->pubc);
pres->publish_sess_ = NULL;
if (param->status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(param->status, errmsg, sizeof(errmsg));
ERROR("Client publication (PUBLISH) failed, status=%d, msg=%s", param->status, errmsg);
} else if (param->code == 412) {
/* 412 (Conditional Request Failed)
* The PUBLISH refresh has failed, retry with new one.
*/
WARN("Publish retry.");
pres_publish(pres);
} else {
ERROR("Client publication (PUBLISH) failed (%u/%.*s)",
param->code, param->reason.slen, param->reason.ptr);
}
} else {
if (param->expiration < 1) {
/* Could happen if server "forgot" to include Expires header
* in the response. We will not renew, so destroy the pubc.
*/
pjsip_publishc_destroy(param->pubc);
pres->publish_sess_ = NULL;
}
}
}
/*
* Send PUBLISH request.
*/
pj_status_t
SIPPresence::pres_send_publish(SIPPresence * pres, pj_bool_t active)
{
pjsip_tx_data *tdata;
pj_status_t status;
DEBUG("Send presence %sPUBLISH..", (active ? "" : "un-"));
SIPAccount * acc = pres->getAccount();
std::string contactWithAngles = acc->getFromUri();
contactWithAngles.erase(contactWithAngles.find('>'));
int semicolon = contactWithAngles.find_first_of(":");
std::string contactWithoutAngles = contactWithAngles.substr(semicolon + 1);
// pj_str_t contact = pj_str(strdup(contactWithoutAngles.c_str()));
// pj_memcpy(&pres_status_data.info[0].contact, &contt, sizeof(pj_str_t));;
/* Create PUBLISH request */
if (active) {
char *bpos;
pj_str_t entity;
status = pjsip_publishc_publish(pres->publish_sess_, PJ_TRUE, &tdata);
if (status != PJ_SUCCESS) {
ERROR("Error creating PUBLISH request", status);
goto on_error;
}
pj_str_t from = pj_str(strdup(acc->getFromUri().c_str()));
if ((bpos = pj_strchr(&from, '<')) != NULL) {
char *epos = pj_strchr(&from, '>');
if (epos - bpos < 2) {
pj_assert(!"Unexpected invalid URI");
status = PJSIP_EINVALIDURI;
goto on_error;
}
entity.ptr = bpos + 1;
entity.slen = epos - bpos - 1;
} else {
entity = from;
}
/* Create and add PIDF message body */
status = pjsip_pres_create_pidf(tdata->pool, pres->getStatus(),
&entity, &tdata->msg->body);
if (status != PJ_SUCCESS) {
ERROR("Error creating PIDF for PUBLISH request");
pjsip_tx_data_dec_ref(tdata);
goto on_error;
}
} else {
WARN("Unpublish is not implemented.");
}
pres_msg_data msg_data;
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);
pres->fillDoc(tdata, &msg_data);
/* Send the PUBLISH request */
status = pjsip_publishc_send(pres->publish_sess_, tdata);
if (status == PJ_EPENDING) {
WARN("Previous request is in progress, ");
} else if (status != PJ_SUCCESS) {
ERROR("Error sending PUBLISH request");
goto on_error;
}
return PJ_SUCCESS;
on_error:
if (pres->publish_sess_) {
pjsip_publishc_destroy(pres->publish_sess_);
pres->publish_sess_ = NULL;
}
return status;
}
/* Create client publish session */
pj_status_t
SIPPresence::pres_publish(SIPPresence *pres)
{
pj_status_t status;
const pj_str_t STR_PRESENCE = pj_str("presence");
SIPAccount * acc = pres->getAccount();
pjsip_endpoint *endpt = ((SIPVoIPLink*) acc->getVoIPLink())->getEndpoint();
/* Create and init client publication session */
/* 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;
}
/* 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;
}
/* Set route-set */
if (acc->hasServiceRoute())
pjsip_regc_set_route_set(acc->getRegistrationInfo(), sip_utils::createRouteSet(acc->getServiceRoute(), pres->getPool()));
/* Send initial PUBLISH request */
status = pres_send_publish(pres, PJ_TRUE);
if (status != PJ_SUCCESS)
return status;
return PJ_SUCCESS;
}
......@@ -44,26 +44,25 @@
#include "pjsip-simple/rpid.h"
#include <pj/pool.h>
struct pres_msg_data
{
struct pres_msg_data {
/**
* Additional message headers as linked list. Application can add
* headers to the list by creating the header, either from the heap/pool
* or from temporary local variable, and add the header using
* linked list operation. See pjsip_apps.c for some sample codes.
*/
pjsip_hdr hdr_list;
pjsip_hdr hdr_list;
/**
* MIME type of optional message body.
*/
pj_str_t content_type;
pj_str_t content_type;
/**
* Optional message body to be added to the message, only when the
* message doesn't have a body.
*/
pj_str_t msg_body;
pj_str_t msg_body;
/**
* Content type of the multipart body. If application wants to send
......@@ -102,133 +101,136 @@ struct pj_caching_pool;
class SIPPresence {
public:
/**
* Constructor
* @param acc the associated sipaccount
*/
SIPPresence(SIPAccount * acc);
/**
* Destructor
*/
~SIPPresence();
/**
* Return associated sipaccount
*/
SIPAccount * getAccount() const;
/**
* Return presence data.
*/
pjsip_pres_status * getStatus();
/**
* Return presence module ID which is actually the same as the VOIP link
*/
int getModId() const;
/**
* Return a pool for generic functions.
*/
pj_pool_t* getPool() const;
/**
* Activate the module (PUBLISH/SUBSCRIBE)
*/
void enable(bool flag);
/**
* Fill xml document, the header and the body
*/
void fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data);
/**
* Modify the presence data
* @param status is basically "open" or "close"
*/
void updateStatus(bool status, const std::string &note);
/**
* Send the presence data in a PUBLISH to the PBX or in a NOTIFY
* to a remote subscriber (IP2IP)
*/
void sendPresence(bool status, const std::string &note);
/**
* Send a signal to the client on DBus. The signal contain the status
* of a remote user.
*/
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 subscribeClient(const std::string& uri, bool flag);
/**
* Add a buddy in the buddy list.
* @param b PresSubClient pointer
*/
void addPresSubClient(PresSubClient *b);
/**
* Remove a buddy from the list.
* @param b PresSubClient pointer
*/
void removePresSubClient(PresSubClient *b);
/**
* IP2IP context.
* Report new Subscription to the client, waiting for approval.
* @param s PresenceSubcription pointer.
*/
void reportnewServerSubscriptionRequest(PresSubServer *s);
/**
* IP2IP context.
* Process new subscription based on client decision.
* @param flag client decision.
* @param uri uri of the remote subscriber
*/
void approvePresSubServer(const std::string& uri, bool flag);
/**
* IP2IP context.
* Add a server associated to a subscriber in the list.
* @param s PresenceSubcription pointer.
*/
void addPresSubServer(PresSubServer *s);
/**
* IP2IP context.
* Remove a server associated to a subscriber from the list.
* @param s PresenceSubcription pointer.
*/
void removePresSubServer(PresSubServer *s);
/**
* IP2IP context.
* Iterate through the subscriber list and send NOTIFY to each.
*/
void notifyPresSubServer();
bool isEnabled() const {
return enabled_;
}
const std::list< PresSubClient *> getClientSubscriptions() {
return pres_sub_client_list_;
}
void lock();
void unlock();
pjsip_publishc *publish_sess; /**< Client publication session.*/
private:
pjsip_pres_status pres_status_data_; /**< Presence Data.*/
pj_bool_t enabled_; /**< Allow for status publish,*/
NON_COPYABLE(SIPPresence);
SIPAccount * acc_; /**< Associated SIP account. */
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. */
pj_thread_t *mutex_owner_; /**< Mutex owner. */
pj_caching_pool cp_; /**< Global pool factory. */
pj_pool_t *pool_; /**< pjsua's private pool. */
public:
/**
* Constructor
* @param acc the associated sipaccount
*/
SIPPresence(SIPAccount * acc);
/**
* Destructor
*/
~SIPPresence();
/**
* Return associated sipaccount
*/
SIPAccount * getAccount() const;
/**
* Return presence data.
*/
pjsip_pres_status * getStatus();
/**
* Return presence module ID which is actually the same as the VOIP link
*/
int getModId() const;
/**
* Return a pool for generic functions.
*/
pj_pool_t* getPool() const;
/**
* Activate the module (PUBLISH/SUBSCRIBE)
*/
void enable(bool flag);
/**
* Fill xml document, the header and the body
*/
void fillDoc(pjsip_tx_data *tdata, const pres_msg_data *msg_data);
/**
* Modify the presence data
* @param status is basically "open" or "close"
*/
void updateStatus(bool status, const std::string &note);
/**
* Send the presence data in a PUBLISH to the PBX or in a NOTIFY
* to a remote subscriber (IP2IP)
*/
void sendPresence(bool status, const std::string &note);
/**
* Send a signal to the client on DBus. The signal contain the status
* of a remote user.
*/
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 subscribeClient(const std::string& uri, bool flag);
/**
* Add a buddy in the buddy list.
* @param b PresSubClient pointer
*/
void addPresSubClient(PresSubClient *b);
/**
* Remove a buddy from the list.
* @param b PresSubClient pointer
*/
void removePresSubClient(PresSubClient *b);
/**
* IP2IP context.
* Report new Subscription to the client, waiting for approval.
* @param s PresenceSubcription pointer.
*/
void reportnewServerSubscriptionRequest(PresSubServer *s);
/**
* IP2IP context.
* Process new subscription based on client decision.
* @param flag client decision.
* @param uri uri of the remote subscriber
*/
void approvePresSubServer(const std::string& uri, bool flag);
/**
* IP2IP context.
* Add a server associated to a subscriber in the list.
* @param s PresenceSubcription pointer.
*/
void addPresSubServer(PresSubServer *s);
/**
* IP2IP context.
* Remove a server associated to a subscriber from the list.
* @param s PresenceSubcription pointer.
*/
void removePresSubServer(PresSubServer *s);
/**
* IP2IP context.
* Iterate through the subscriber list and send NOTIFY to each.
*/
void notifyPresSubServer();
bool isEnabled() const {
return enabled_;
}
const std::list< PresSubClient *> getClientSubscriptions() {
return pres_sub_client_list_;
}
void lock();
void unlock();
private:
NON_COPYABLE(SIPPresence);
static pj_status_t pres_publish(SIPPresence *pres);
static void pres_publish_cb(struct pjsip_publishc_cbparam *param);
static pj_status_t pres_send_publish(SIPPresence *pres, pj_bool_t active);
pjsip_publishc *publish_sess_; /**< Client publication session.*/
pjsip_pres_status pres_status_data_; /**< Presence Data.*/
pj_bool_t enabled_; /**< Allow for status publish,*/
SIPAccount * acc_; /**< Associated SIP account. */
std::list< PresSubServer *> pres_sub_server_list_; /**< Subscribers list.*/
std::list< PresSubClient *> pres_sub_client_list_; /**< Subcribed buddy list.*/
pj_mutex_t *mutex_;
unsigned mutex_nesting_level_;
pj_thread_t *mutex_owner_;
pj_caching_pool cp_;
pj_pool_t *pool_;
};
#endif
/*
* 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_endpoint.h>
#include "sippresence.h"
#include "sip_utils.h"
#include "sippublish.h"
#include "logger.h"
#include "sipvoiplink.h"
void pres_publish_cb(struct pjsip_publishc_cbparam *param);
pj_status_t pres_send_publish(SIPPresence * pres, pj_bool_t active);
const pjsip_publishc_opt my_publish_opt = {true}; // this is queue_request
/*
* Client presence publication callback.
*/
void pres_publish_cb(struct pjsip_publishc_cbparam *param)
{
SIPPresence *pres = (SIPPresence*) param->token;