Commit c04fcf0b authored by Simon Morlat's avatar Simon Morlat

Rework the way GRUU support is implemented.

* define two functions in RegistrarDb to convert a sip.instance to gr parameter and vice versa, used everywhere needed
* set the pub-gruu into the ExtendedContact, instead of synthetize when generating the 200 Ok response
* Fix an issue where the null character was accidentally inserted at the end of a c++ string, causing an ostringstream to stop (when printing ExtendedContact's paths).
* Eliminate useless code.

The initial goal of this rework is to allow a SIP client to REGISTER with a GRUU address as contact.
This wasn't possible because Flexisip was confusing the gr parameter it was computing and the gr parameter set by the client in the Contact header.
parent 4c858d94
Pipeline #4204 passed with stages
in 24 minutes and 43 seconds
...@@ -48,10 +48,10 @@ struct ExtendedContactCommon { ...@@ -48,10 +48,10 @@ struct ExtendedContactCommon {
std::list<std::string> mPath; std::list<std::string> mPath;
ExtendedContactCommon(const char *contactId, const std::list<std::string> &path, const std::string &callId, ExtendedContactCommon(const char *contactId, const std::list<std::string> &path, const std::string &callId,
const char *lineValue) { const std::string &uniqueId) {
if (!callId.empty()) mCallId = callId; mCallId = callId;
mPath = path; mPath = path;
if (lineValue) mUniqueId = lineValue; mUniqueId = uniqueId;
mContactId = contactId; mContactId = contactId;
} }
ExtendedContactCommon(const std::string &route) : mContactId(), mCallId(), mUniqueId(), mPath({route}) { ExtendedContactCommon(const std::string &route) : mContactId(), mCallId(), mUniqueId(), mPath({route}) {
...@@ -255,8 +255,8 @@ class Record { ...@@ -255,8 +255,8 @@ class Record {
} }
/* /*
* Synthetise the pub-gruu address from an extended contact belonging to this Record. * Synthetise the pub-gruu address from an extended contact belonging to this Record.
* FIXME: Unfortunately this function is not widely used in Flexisip, instead there are several * FIXME: of course this method should be directly attached to ExtendedContact.
* places where pub-gruu address is synthesized. * Unfortunately, because pub-gruu were not contained in the ExtendedContact, it shall remain in Record for compatibility.
*/ */
url_t *getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home); url_t *getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home);
/** /**
...@@ -373,7 +373,6 @@ class RegistrarDb { ...@@ -373,7 +373,6 @@ class RegistrarDb {
void clear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener); void clear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener);
void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive = false); void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive = false);
void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool includingDomains, bool recursive); void fetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool includingDomains, bool recursive);
void fetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener);
void fetchList(const std::vector<url_t *> urls, const std::shared_ptr<ListContactUpdateListener> &listener); void fetchList(const std::vector<url_t *> urls, const std::shared_ptr<ListContactUpdateListener> &listener);
void notifyContactListener (const std::shared_ptr<Record> &r, const std::string &uid); void notifyContactListener (const std::shared_ptr<Record> &r, const std::string &uid);
void updateRemoteExpireTime(const std::string &key, time_t expireat); void updateRemoteExpireTime(const std::string &key, time_t expireat);
...@@ -401,6 +400,8 @@ class RegistrarDb { ...@@ -401,6 +400,8 @@ class RegistrarDb {
void unsubscribeLocalRegExpire(LocalRegExpireListener *listener) { void unsubscribeLocalRegExpire(LocalRegExpireListener *listener) {
mLocalRegExpire->unsubscribe(listener); mLocalRegExpire->unsubscribe(listener);
} }
static std::string uniqueIdToGr(const std::string &uid);
static std::string grToUniqueId(const std::string &gr);
protected: protected:
class LocalRegExpire { class LocalRegExpire {
std::map<std::string, time_t> mRegMap; std::map<std::string, time_t> mRegMap;
...@@ -429,7 +430,7 @@ class RegistrarDb { ...@@ -429,7 +430,7 @@ class RegistrarDb {
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener) = 0; virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener) = 0; virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener) = 0; virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener) = 0; virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener) = 0;
virtual void doMigration() = 0; virtual void doMigration() = 0;
int count_sip_contacts(const sip_contact_t *contact); int count_sip_contacts(const sip_contact_t *contact);
...@@ -438,7 +439,7 @@ class RegistrarDb { ...@@ -438,7 +439,7 @@ class RegistrarDb {
void fetchWithDomain(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive); void fetchWithDomain(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener, bool recursive);
void notifyContactListener(const std::string &key, const std::string &uid); void notifyContactListener(const std::string &key, const std::string &uid);
void notifyStateListener () const; void notifyStateListener () const;
RegistrarDb(Agent *ag); RegistrarDb(Agent *ag);
virtual ~RegistrarDb(); virtual ~RegistrarDb();
std::multimap<std::string, std::shared_ptr<ContactRegisteredListener>> mContactListenersMap; std::multimap<std::string, std::shared_ptr<ContactRegisteredListener>> mContactListenersMap;
......
Subproject commit f46b9b1ea5f9a829639a3c563194fef17711762a Subproject commit 2cc5ec84eead76112836aaae74f98e05dde9dc05
...@@ -37,13 +37,10 @@ ConferenceAddressGenerator::ConferenceAddressGenerator ( ...@@ -37,13 +37,10 @@ ConferenceAddressGenerator::ConferenceAddressGenerator (
void ConferenceAddressGenerator::run () { void ConferenceAddressGenerator::run () {
char token[17]; char token[17];
ostringstream os; ostringstream os;
belle_sip_random_token(token, sizeof(token)); belle_sip_random_token(token, sizeof(token));
os.str("");
os << "chatroom-" << token; os << "chatroom-" << token;
mConferenceAddr->setUsername(os.str()); mConferenceAddr->setUsername(os.str());
os.str("");
os << "\"<urn:uuid:" << mUuid << ">\"";
mConferenceAddr->setParam("+sip.instance", os.str());
url_t *url = url_make(mHome.home(), mConferenceAddr->asStringUriOnly().c_str()); url_t *url = url_make(mHome.home(), mConferenceAddr->asStringUriOnly().c_str());
RegistrarDb::get()->fetch(url, shared_from_this(), false, false); RegistrarDb::get()->fetch(url, shared_from_this(), false, false);
...@@ -64,13 +61,20 @@ void ConferenceAddressGenerator::onRecordFound(const std::shared_ptr<Record> &r) ...@@ -64,13 +61,20 @@ void ConferenceAddressGenerator::onRecordFound(const std::shared_ptr<Record> &r)
); );
} }
} else { } else {
if (r->getExtendedContacts().empty()) {
LOGF("Conference address bind failed.");
return;
}
const shared_ptr<ExtendedContact> ec = r->getExtendedContacts().front(); const shared_ptr<ExtendedContact> ec = r->getExtendedContacts().front();
string uri = ExtendedContact::urlToString(ec->mSipContact->m_url); url_t *pub_gruu = r->getPubGruu(ec, mHome.home());
shared_ptr<linphone::Address> addr = linphone::Factory::get()->createAddress(uri); if (!pub_gruu) {
LOGF("Conference does not have gruu address.");
return;
}
shared_ptr<linphone::Address> gruuAddr = linphone::Factory::get()->createAddress( shared_ptr<linphone::Address> gruuAddr = linphone::Factory::get()->createAddress(
mConferenceAddr->asStringUriOnly() url_as_string(mHome.home(), pub_gruu));
);
gruuAddr->setUriParam("gr", addr->getUriParam("gr"));
mChatRoom->setConferenceAddress(gruuAddr); mChatRoom->setConferenceAddress(gruuAddr);
} }
} }
......
...@@ -164,6 +164,10 @@ void flexisip::ConferenceServer::bindAddresses () { ...@@ -164,6 +164,10 @@ void flexisip::ConferenceServer::bindAddresses () {
// Binding loaded chat room // Binding loaded chat room
for (const auto &chatRoom : mCore->getChatRooms()) { for (const auto &chatRoom : mCore->getChatRooms()) {
if (chatRoom->getPeerAddress()->getUriParam("gr").empty()){
LOGE("Skipping chatroom %s with no gruu parameter.", chatRoom->getPeerAddress()->asString().c_str());
continue;
}
bindChatRoom(chatRoom->getPeerAddress()->asStringUriOnly(), mTransport, chatRoom->getPeerAddress()->getUriParam("gr"), nullptr); bindChatRoom(chatRoom->getPeerAddress()->asStringUriOnly(), mTransport, chatRoom->getPeerAddress()->getUriParam("gr"), nullptr);
} }
...@@ -213,9 +217,8 @@ void ConferenceServer::bindChatRoom ( ...@@ -213,9 +217,8 @@ void ConferenceServer::bindChatRoom (
sip_contact_t* sipContact = sip_contact_create(mHome.home(), sip_contact_t* sipContact = sip_contact_create(mHome.home(),
reinterpret_cast<const url_string_t*>(url_make(mHome.home(), contact.c_str())), reinterpret_cast<const url_string_t*>(url_make(mHome.home(), contact.c_str())),
su_strdup(mHome.home(), ("+sip.instance=\"<" + gruu + ">\"").c_str()), nullptr); su_strdup(mHome.home(), ("+sip.instance=" + RegistrarDb::grToUniqueId(gruu) ).c_str()), nullptr);
url_t *from = url_make(mHome.home(), bindingUrl.c_str()); url_t *from = url_make(mHome.home(), bindingUrl.c_str());
url_param_add(mHome.home(), from, ("gr=" + gruu).c_str());
parameter.callId = gruu; parameter.callId = gruu;
parameter.path = mPath; parameter.path = mPath;
......
...@@ -88,9 +88,6 @@ void OwnRegistrationSubscription::stop(){ ...@@ -88,9 +88,6 @@ void OwnRegistrationSubscription::stop(){
unsigned int OwnRegistrationSubscription::getContactCapabilities(const std::shared_ptr<ExtendedContact> &ec){ unsigned int OwnRegistrationSubscription::getContactCapabilities(const std::shared_ptr<ExtendedContact> &ec){
unsigned int mask = 0; unsigned int mask = 0;
if (!url_has_param(ec->mSipContact->m_url, "gr")){
return 0; //eliminate contacts without gruu, there is nothing we can do with them
}
string specs = ec->getOrgLinphoneSpecs(); string specs = ec->getOrgLinphoneSpecs();
//Please excuse the following code that is a bit too basic in terms of parsing: //Please excuse the following code that is a bit too basic in terms of parsing:
if (specs.find("groupchat") != string::npos) mask |= (unsigned int)ChatRoomCapabilities::Conference; if (specs.find("groupchat") != string::npos) mask |= (unsigned int)ChatRoomCapabilities::Conference;
......
...@@ -463,20 +463,6 @@ void ModuleRegistrar::reply(shared_ptr<RequestSipEvent> &ev, int code, const cha ...@@ -463,20 +463,6 @@ void ModuleRegistrar::reply(shared_ptr<RequestSipEvent> &ev, int code, const cha
for (sip_contact_t *contact = modified_contacts; contact!=nullptr ; contact=contact->m_next) { for (sip_contact_t *contact = modified_contacts; contact!=nullptr ; contact=contact->m_next) {
if(sip->sip_request->rq_method == sip_method_register && code == 200 && contact) { if(sip->sip_request->rq_method == sip_method_register && code == 200 && contact) {
if (url_has_param(contact->m_url, "gr")) {
string gruu;
char *buffer = new char[255];
isize_t result = url_param(contact->m_url->url_params, "gr", buffer, 255);
if (result > 0) {
su_home_t *home = ev->getHome();
stringstream stream;
gruu = string(buffer);
contact->m_url->url_params = url_strip_param_string((char *)contact->m_url->url_params,"gr");
stream << "\"" << url_as_string(home, sip->sip_from->a_url) << ";gr=" << gruu << "\"";
msg_header_replace_param(home, (msg_common_t *) contact, su_sprintf(home, "pub-gruu=%s", stream.str().c_str()));
}
delete[] buffer;
}
if (url_has_param(contact->m_url, "fs-conn-id")) { if (url_has_param(contact->m_url, "fs-conn-id")) {
contact->m_url->url_params = url_strip_param_string((char *)contact->m_url->url_params,"fs-conn-id"); contact->m_url->url_params = url_strip_param_string((char *)contact->m_url->url_params,"fs-conn-id");
} }
......
...@@ -77,7 +77,7 @@ void RegistrarDbInternal::doFetch(const url_t *url, const shared_ptr<ContactUpda ...@@ -77,7 +77,7 @@ void RegistrarDbInternal::doFetch(const url_t *url, const shared_ptr<ContactUpda
listener->onRecordFound(r); listener->onRecordFound(r);
} }
void RegistrarDbInternal::doFetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) { void RegistrarDbInternal::doFetchInstance(const url_t *url, const string &uniqueId, const shared_ptr<ContactUpdateListener> &listener) {
string key(Record::defineKeyFromUrl(url)); string key(Record::defineKeyFromUrl(url));
SofiaAutoHome home; SofiaAutoHome home;
...@@ -101,22 +101,11 @@ void RegistrarDbInternal::doFetchForGruu(const url_t *url, const string &gruu, c ...@@ -101,22 +101,11 @@ void RegistrarDbInternal::doFetchForGruu(const url_t *url, const string &gruu, c
const list<shared_ptr<ExtendedContact>> &contacts = r->getExtendedContacts(); const list<shared_ptr<ExtendedContact>> &contacts = r->getExtendedContacts();
shared_ptr<Record> retRecord = make_shared<Record>(url); shared_ptr<Record> retRecord = make_shared<Record>(url);
for (const auto &contact : contacts) { for (const auto &contact : contacts) {
if (!url_has_param(contact->mSipContact->m_url, "gr")) if (contact->mUniqueId == uniqueId){
continue; retRecord->pushContact(contact);
break;
char buffer[255] = {0}; }
isize_t result = url_param(contact->mSipContact->m_url->url_params, "gr", buffer, sizeof(buffer) - 1);
if (result <= 0)
continue;
stringstream streamGruu;
streamGruu << "\"<" << buffer << ">\"";
if (streamGruu.str() != gruu)
continue;
retRecord->pushContact(contact);
} }
listener->onRecordFound(retRecord); listener->onRecordFound(retRecord);
} }
......
...@@ -30,12 +30,12 @@ class RegistrarDbInternal : public RegistrarDb { ...@@ -30,12 +30,12 @@ class RegistrarDbInternal : public RegistrarDb {
void clearAll(); void clearAll();
private: private:
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doMigration(); virtual void doMigration()override;
virtual void publish(const std::string &topic, const std::string &uid); virtual void publish(const std::string &topic, const std::string &uid)override;
std::map<std::string, std::shared_ptr<Record>> mRecords; std::map<std::string, std::shared_ptr<Record>> mRecords;
}; };
......
...@@ -42,7 +42,7 @@ using namespace std; ...@@ -42,7 +42,7 @@ using namespace std;
using namespace flexisip; using namespace flexisip;
RegistrarUserData::RegistrarUserData(RegistrarDbRedisAsync *s, const url_t *url, shared_ptr<ContactUpdateListener> listener) RegistrarUserData::RegistrarUserData(RegistrarDbRedisAsync *s, const url_t *url, shared_ptr<ContactUpdateListener> listener)
: self(s), listener(listener), token(0), mRetryTimer(nullptr), mRetryCount(0), mGruu(""), mUpdateExpire(false), mIsUnregister(false) { : self(s), listener(listener), token(0), mRetryTimer(nullptr), mRetryCount(0), mUniqueId(""), mUpdateExpire(false), mIsUnregister(false) {
mRecord = make_shared<Record>(url); mRecord = make_shared<Record>(url);
} }
RegistrarUserData::~RegistrarUserData() { RegistrarUserData::~RegistrarUserData() {
...@@ -819,7 +819,7 @@ void RegistrarDbRedisAsync::handleFetch(redisReply *reply, RegistrarUserData *da ...@@ -819,7 +819,7 @@ void RegistrarDbRedisAsync::handleFetch(redisReply *reply, RegistrarUserData *da
} }
} else { } else {
// This is only when we want a contact matching a given gruu // This is only when we want a contact matching a given gruu
const char *gruu = data->mGruu.c_str(); const char *gruu = data->mUniqueId.c_str();
if (reply->len > 0) { if (reply->len > 0) {
LOGD("GOT fs:%s [%lu] for gruu %s --> %s", key, data->token, gruu, reply->str); LOGD("GOT fs:%s [%lu] for gruu %s --> %s", key, data->token, gruu, reply->str);
data->mRecord->updateFromUrlEncodedParams(key, gruu, reply->str, data->listener); data->mRecord->updateFromUrlEncodedParams(key, gruu, reply->str, data->listener);
...@@ -851,10 +851,10 @@ void RegistrarDbRedisAsync::doFetch(const url_t *url, const shared_ptr<ContactUp ...@@ -851,10 +851,10 @@ void RegistrarDbRedisAsync::doFetch(const url_t *url, const shared_ptr<ContactUp
data, "HGETALL fs:%s", key), data); data, "HGETALL fs:%s", key), data);
} }
void RegistrarDbRedisAsync::doFetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) { void RegistrarDbRedisAsync::doFetchInstance(const url_t *url, const string &uniqueId, const shared_ptr<ContactUpdateListener> &listener) {
// fetch only the contact in the AOR (HGET) and call the onRecordFound of the listener // fetch only the contact in the AOR (HGET) and call the onRecordFound of the listener
RegistrarUserData *data = new RegistrarUserData(this, url, listener); RegistrarUserData *data = new RegistrarUserData(this, url, listener);
data->mGruu = gruu; data->mUniqueId = uniqueId;
if (!isConnected() && !connect()) { if (!isConnected() && !connect()) {
LOGE("Not connected to redis server"); LOGE("Not connected to redis server");
...@@ -864,8 +864,8 @@ void RegistrarDbRedisAsync::doFetchForGruu(const url_t *url, const string &gruu, ...@@ -864,8 +864,8 @@ void RegistrarDbRedisAsync::doFetchForGruu(const url_t *url, const string &gruu,
} }
const char *key = data->mRecord->getKey().c_str(); const char *key = data->mRecord->getKey().c_str();
const char *field = gruu.c_str(); const char *field = uniqueId.c_str();
LOGD("Fetching fs:%s [%lu] contact matching gruu %s", key, data->token, field); LOGD("Fetching fs:%s [%lu] contact matching unique id %s", key, data->token, field);
check_redis_command(redisAsyncCommand(mContext, (void (*)(redisAsyncContext*, void*, void*))sHandleFetch, check_redis_command(redisAsyncCommand(mContext, (void (*)(redisAsyncContext*, void*, void*))sHandleFetch,
data, "HGET fs:%s %s", key, field), data); data, "HGET fs:%s %s", key, field), data);
} }
......
...@@ -88,7 +88,7 @@ struct RegistrarUserData { ...@@ -88,7 +88,7 @@ struct RegistrarUserData {
unsigned long token; unsigned long token;
su_timer_t *mRetryTimer; su_timer_t *mRetryTimer;
int mRetryCount; int mRetryCount;
std::string mGruu; std::string mUniqueId;
bool mUpdateExpire; bool mUpdateExpire;
bool mIsUnregister; bool mIsUnregister;
...@@ -105,14 +105,14 @@ class RegistrarDbRedisAsync : public RegistrarDb { ...@@ -105,14 +105,14 @@ class RegistrarDbRedisAsync : public RegistrarDb {
bool disconnect(); bool disconnect();
protected: protected:
virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doBind(const sip_t *sip, int globalExpire, bool alias, int version, const std::shared_ptr<ContactUpdateListener> &listener) override;
virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doClear(const sip_t *sip, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doFetch(const url_t *url, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doFetchForGruu(const url_t *url, const std::string &gruu, const std::shared_ptr<ContactUpdateListener> &listener); virtual void doFetchInstance(const url_t *url, const std::string &uniqueId, const std::shared_ptr<ContactUpdateListener> &listener)override;
virtual void doMigration(); virtual void doMigration()override;
virtual void subscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener); virtual void subscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener)override;
virtual void unsubscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener); virtual void unsubscribe(const std::string &topic, const std::shared_ptr<ContactRegisteredListener> &listener)override;
virtual void publish(const std::string &topic, const std::string &uid); virtual void publish(const std::string &topic, const std::string &uid)override;
private: private:
RegistrarDbRedisAsync(Agent *agent, RedisParameters params); RegistrarDbRedisAsync(Agent *agent, RedisParameters params);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <sofia-sip/sip_protos.h> #include <sofia-sip/sip_protos.h>
#include "recordserializer.hh" #include "recordserializer.hh"
#include <flexisip/module.hh> #include <flexisip/module.hh>
#include "utils/string-utils.hh"
using namespace std; using namespace std;
using namespace flexisip; using namespace flexisip;
...@@ -314,17 +315,20 @@ void ExtendedContact::extractInfoFromHeader(const char *urlHeaders) { ...@@ -314,17 +315,20 @@ void ExtendedContact::extractInfoFromHeader(const char *urlHeaders) {
string valueStr; string valueStr;
string keyStr = reinterpret_cast<msg_common_t*>(headers)->h_class->hc_name; string keyStr = reinterpret_cast<msg_common_t*>(headers)->h_class->hc_name;
valueStr.resize(reinterpret_cast<msg_common_t*>(headers)->h_len); valueStr.resize(reinterpret_cast<msg_common_t*>(headers)->h_len + 1);
msg_header_field_e(&valueStr[0], reinterpret_cast<msg_common_t*>(headers)->h_len, headers, 0); size_t written = msg_header_field_e(&valueStr[0], reinterpret_cast<msg_common_t*>(headers)->h_len, headers, 0);
valueStr.resize(written);
transform(keyStr.begin(), keyStr.end(), keyStr.begin(), [](unsigned char c){ return std::tolower(c); }); transform(keyStr.begin(), keyStr.end(), keyStr.begin(), [](unsigned char c){ return std::tolower(c); });
if (keyStr == "path") { if (keyStr == "path") {
size_t bracket = valueStr.find('<'); // We want to keep only the uri part of the paths.
if (bracket != string::npos) valueStr.erase(bracket, static_cast<size_t>(1)); sip_path_t *path = sip_path_format(home.home(), "%s", valueStr.c_str());
bracket = valueStr.find('>'); if (path){
if (bracket != string::npos) valueStr.erase(bracket, static_cast<size_t>(1)); mPath.push_back(url_as_string(home.home(), path->r_url));
mPath.push_back(valueStr); }else{
LOGE("ExtendedContact::extractInfoFromHeader(): bad path [%s]", valueStr.c_str());
}
} else if (keyStr == "accept") { } else if (keyStr == "accept") {
mAcceptHeader.push_back(valueStr); mAcceptHeader.push_back(valueStr);
} else if (keyStr == "user-agent") { } else if (keyStr == "user-agent") {
...@@ -352,8 +356,8 @@ void Record::applyMaxAor() { ...@@ -352,8 +356,8 @@ void Record::applyMaxAor() {
} }
} }
static void defineContactId(ostringstream &oss, const url_t *url, const char *transport) { static void defineContactId(ostringstream &oss, const url_t *url, const string &transport) {
if (transport != nullptr) if (!transport.empty())
oss << transport << ":"; oss << transport << ":";
if (url->url_user != nullptr) if (url->url_user != nullptr)
oss << url->url_user << ":"; oss << url->url_user << ":";
...@@ -482,6 +486,11 @@ void ExtendedContact::extractInfoFromUrl(const char* full_url) { ...@@ -482,6 +486,11 @@ void ExtendedContact::extractInfoFromUrl(const char* full_url) {
} else { } else {
url = temp_contact->m_url; url = temp_contact->m_url;
} }
if (url == nullptr) {
LOGE("ExtendedContact::extractInfoFromUrl() url is null.");
return;
}
// CallId // CallId
mCallId = extractStringParam(url, "callid"); mCallId = extractStringParam(url, "callid");
...@@ -545,22 +554,18 @@ void Record::update(const sip_t *sip, int globalExpire, bool alias, int version, ...@@ -545,22 +554,18 @@ void Record::update(const sip_t *sip, int globalExpire, bool alias, int version,
userAgent = (sip->sip_user_agent) ? sip->sip_user_agent->g_string : ""; userAgent = (sip->sip_user_agent) ? sip->sip_user_agent->g_string : "";
while (contacts) { while (contacts) {
char buffer[20]; char buffer[20]={0};
list<string> paramName; list<string> paramName;
char *transportPtr;
ostringstream contactId; ostringstream contactId;
const char *lineValuePtr = nullptr; string transport;
string lineValue = extractUniqueId(contacts); string uniqueId = extractUniqueId(contacts);
if (!lineValue.empty()) lineValuePtr = lineValue.c_str(); if (url_param(contacts->m_url[0].url_params, "transport", buffer, sizeof(buffer) - 1) > 0) {
transport = buffer;
transportPtr = buffer;
if (!url_param(contacts->m_url[0].url_params, "transport", buffer, sizeof(buffer) - 1)) {
transportPtr = nullptr;
} }
defineContactId(contactId, contacts->m_url, transportPtr); defineContactId(contactId, contacts->m_url, transport);
ExtendedContactCommon ecc(contactId.str().c_str(), stlPath, sip->sip_call_id->i_id, lineValuePtr); ExtendedContactCommon ecc(contactId.str().c_str(), stlPath, sip->sip_call_id->i_id, uniqueId);
auto exc = make_shared<ExtendedContact>(ecc, contacts, globalExpire, (sip->sip_cseq) ? sip->sip_cseq->cs_seq : 0, getCurrentTime(), alias, acceptHeaders, userAgent); auto exc = make_shared<ExtendedContact>(ecc, contacts, globalExpire, (sip->sip_cseq) ? sip->sip_cseq->cs_seq : 0, getCurrentTime(), alias, acceptHeaders, userAgent);
exc->mUsedAsRoute = sip->sip_from->a_url->url_user == nullptr; exc->mUsedAsRoute = sip->sip_from->a_url->url_user == nullptr;
insertOrUpdateBinding(exc, listener); insertOrUpdateBinding(exc, listener);
...@@ -629,9 +634,27 @@ const url_t *Record::getAor()const{ ...@@ -629,9 +634,27 @@ const url_t *Record::getAor()const{
url_t *Record::getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home){ url_t *Record::getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t *home){
char gr_value[256] = {0}; char gr_value[256] = {0};
url_t *gruu_addr = NULL; url_t *gruu_addr = NULL;
const char *pub_gruu_value = msg_header_find_param((msg_common_t*)ec->mSipContact, "pub-gruu");
if (!ec->mSipContact->m_url->url_params) return NULL; if (pub_gruu_value){
if (pub_gruu_value[0] == '\0'){
/*
* To preserve compatibility with previous storage of pub-gruu (where only a gr parameter was set in URI),
* a client that didn't requested a gruu address has now a "pub-gruu" contact parameter which is empty.
* This means that this client has no pub-gruu assigned by this server.
*/
return nullptr;
}
gruu_addr = url_make(home, StringUtils::unquote(pub_gruu_value).c_str());
return gruu_addr;
}
/*
* Compatibility code, when pub-gruu wasn't stored in RegistrarDb.
* In such case, we have to synthetize the gruu address from the address of record and the gr uri parameter.
*/
if (!ec->mSipContact->m_url->url_params) return NULL;
isize_t result = url_param(ec->mSipContact->m_url->url_params, "gr", gr_value, sizeof(gr_value)-1); isize_t result = url_param(ec->mSipContact->m_url->url_params, "gr", gr_value, sizeof(gr_value)-1);
if (result > 0) { if (result > 0) {
...@@ -1049,10 +1072,8 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener ...@@ -1049,10 +1072,8 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener
} }
if(url_has_param(url, "gr")) { if(url_has_param(url, "gr")) {
char buffer[255] = {0}; char buffer[255] = {0};
if (url_param(url->url_params, "gr", buffer, sizeof(buffer)) > 0) { if (url_param(url->url_params, "gr", buffer, sizeof(buffer)-1) > 0) {
stringstream gruu; doFetchInstance(url, grToUniqueId(buffer), recursive
gruu << "\"<" << buffer << ">\"";
doFetchForGruu(url, gruu.str(), recursive
? make_shared<RecursiveRegistrarDbListener>(this, listener, url) ? make_shared<RecursiveRegistrarDbListener>(this, listener, url)
: listener); : listener);
return; return;
...@@ -1063,10 +1084,6 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener ...@@ -1063,10 +1084,6 @@ void RegistrarDb::fetch(const url_t *url, const shared_ptr<ContactUpdateListener
: listener); : listener);
} }
void RegistrarDb::fetchForGruu(const url_t *url, const string &gruu, const shared_ptr<ContactUpdateListener> &listener) {
doFetchForGruu(url, gruu, listener);
}
void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListContactUpdateListener> &listener) { void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListContactUpdateListener> &listener) {
class InternalContactUpdateListener : public ContactUpdateListener { class InternalContactUpdateListener : public ContactUpdateListener {
public: public:
...@@ -1105,22 +1122,28 @@ void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListCon ...@@ -1105,22 +1122,28 @@ void RegistrarDb::fetchList(const vector<url_t *> urls, const shared_ptr<ListCon
void RegistrarDb::bind(const sip_t *sip, const BindingParameters &parameter, const shared_ptr<ContactUpdateListener> &listener) { void RegistrarDb::bind(const sip_t *sip, const BindingParameters &parameter, const shared_ptr<ContactUpdateListener> &listener) {
SofiaAutoHome home; SofiaAutoHome home;
bool gruu_assigned = false;
if (sip->sip_supported && sip->sip_contact->m_params) { if (sip->sip_supported && sip->sip_contact->m_params) {
if (msg_params_find(sip->sip_supported->k_items, "gruu") != nullptr){ if (msg_params_find(sip->sip_supported->k_items, "gruu") != nullptr){
const char *instance_param = msg_params_find(sip->sip_contact->m_params, "+sip.instance"); const char *instance_param = msg_params_find(sip->sip_contact->m_params, "+sip.instance");
if (instance_param) { if (instance_param) {
string instance(instance_param); string gr = uniqueIdToGr(instance_param);
if (instance.find("\"<") != string::npos) { if (!gr.empty()){/* assign a public gruu address to this contact */
ostringstream stream; msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
instance = instance.substr(instance.find("\"<") + strlen("\"<")); su_sprintf(home.home(), "pub-gruu=\"%s;gr=%s\"", url_as_string(home.home(), sip->sip_from->a_url), gr.c_str() ) );
instance = instance.substr(0, instance.find(">")); gruu_assigned = true;
stream << "gr=" << instance;
url_param_add(home.home(), sip->sip_contact->m_url, stream.str().c_str());
} }
} }
} }
} }
if (!gruu_assigned){
/* Set an empty pub-gruu meaning that this client hasn't requested any pub-gruu from this server.
* This is to preserve compatibility with previous RegistrarDb storage, where only gr parameter was stored.
* This couldn't work because a client can use a "gr" parameter in its contact uri.*/
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
su_sprintf(home.home(), "pub-gruu"));
}
int countSipContacts = count_sip_contacts(sip->sip_contact); int countSipContacts = count_sip_contacts(sip->sip_contact);
if (countSipContacts > Record::getMaxContacts()) { if (countSipContacts > Record::getMaxContacts()) {
...@@ -1152,6 +1175,27 @@ void RegistrarDb::bind(const url_t *from, const sip_contact_t *contact, const Bi ...@@ -1152,6 +1175,27 @@ void RegistrarDb::bind(const url_t *from, const sip_contact_t *contact, const Bi
msg_unref(msg); msg_unref(msg);
} }
/* Transforms the unique id to a "gr" parameter value. */
string RegistrarDb::uniqueIdToGr(const string &uid){
string ret;
size_t begin = uid.find('<');
if (begin != string::npos){
size_t end = uid.find('>', begin + 1);
if (end != string::npos){
begin++; //skip '<'
ret = uid.substr(begin, end - begin);
}
}
return ret;
}
string RegistrarDb::grToUniqueId(const string &gr){
ostringstream uid;
uid << "\"<" << gr << ">\"";
return uid.str();
}
class AgregatorRegistrarDbListener : public ContactUpdateListener { class AgregatorRegistrarDbListener : public ContactUpdateListener {
private: private:
shared_ptr<ContactUpdateListener> mOriginalListener; shared_ptr<ContactUpdateListener> mOriginalListener;
......
...@@ -26,6 +26,9 @@ class StringUtils { ...@@ -26,6 +26,9 @@ class StringUtils {
public: public:
static std::vector<std::string> split (const std::string &str, const std::string &delimiter); static std::vector<std::string> split (const std::string &str, const std::string &delimiter);
static std::string unquote(const std::string & str){
return strip(str, '"');
}
static std::string strip(const char *str, char c); static std::string strip(const char *str, char c);
static std::string strip(const std::string &str, char c); static std::string strip(const std::string &str, char c);
static void strip(std::string::const_iterator &start, std::string::const_iterator &end, char c); static void strip(std::string::const_iterator &start, std::string::const_iterator &end, char c);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment