Commit fffad7f5 authored by Timothée Jaussoin's avatar Timothée Jaussoin

Add a REGISTRAR_GET to get directly Record objects from the Registrar

Use RecordSerializerJson to serialise the Records
Add user_agent to the serializer
Rename cli registrar commands
Implement REGISTRAR_DELETE
parent 29ea1e6e
Pipeline #12152 failed with stages
in 86 minutes and 31 seconds
......@@ -79,7 +79,7 @@ struct ExtendedContact {
bool mAlias;
bool mUsedAsRoute; /*whether the contact information shall be used as a route when forming a request, instead of
replacing the request-uri*/
bool mIsFallback = false; // boolean indicating whether this ExtendedContact is a fallback route or not. There is no need for it to be serialized to database.
const char *callId() const {
......@@ -215,7 +215,7 @@ class Record {
Record(const url_t *aor);
//Get address of record
const url_t *getAor()const;
void insertOrUpdateBinding(const std::shared_ptr<ExtendedContact> &ec, const std::shared_ptr<ContactUpdateListener> &listener);
const std::shared_ptr<ExtendedContact> extractContactByUniqueId(std::string uid);
sip_contact_t *getContacts(su_home_t *home, time_t now);
......@@ -438,7 +438,7 @@ class RegistrarDb {
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 notifyStateListener () const;
RegistrarDb(Agent *ag);
virtual ~RegistrarDb();
std::multimap<std::string, std::shared_ptr<ContactRegisteredListener>> mContactListenersMap;
......
......@@ -20,6 +20,8 @@ def parse_args():
'CONFIG_GET': {'help': 'Get the value of an internal variable of Flexisip.'},
'CONFIG_SET': {'help': 'Set the value of an internal variable of Flexisip.'},
'CONFIG_LIST': {'help': 'List all the available parameters of a section.'},
'REGISTRAR_GET': {'help': 'Return a JSON serialized object from the registrar database.'},
'REGISTRAR_DELETE': {'help': 'Remove a user client from the registrar database.'},
'REGISTRAR_CLEAR': {'help': 'Remove a user from the registrar database.'}
}
......@@ -45,13 +47,16 @@ def parse_args():
help='The name of the section. The list of all available sections is returned if no section name is given.'
)
commands['REGISTRAR_CLEAR']['parser'].add_argument('uri', help='SIP URI of the user.')
commands['REGISTRAR_GET']['parser'].add_argument('uri', help='SIP URI of the user.')
commands['REGISTRAR_DELETE']['parser'].add_argument('uri', help='SIP URI of the user.')
commands['REGISTRAR_DELETE']['parser'].add_argument('uuid', help='Client identifier.')
return parser.parse_args()
def getpid(serverType):
from subprocess import check_output, CalledProcessError
procName = 'flexisip-' + serverType
pidFile = '/var/run/{procName}.pid'.format(procName=procName)
......@@ -59,7 +64,7 @@ def getpid(serverType):
return int(check_output(['cat', pidFile]))
except CalledProcessError:
pass
try:
return int(check_output(['pidof', '-s', procName]))
except CalledProcessError:
......@@ -77,6 +82,11 @@ def formatMessage(args):
messageArgs.append(args.section_name)
elif args.command == 'REGISTRAR_CLEAR':
messageArgs.append(args.uri)
elif args.command == 'REGISTRAR_GET':
messageArgs.append(args.uri)
elif args.command == 'REGISTRAR_DELETE':
messageArgs.append(args.uri)
messageArgs.append(args.uuid)
return ' '.join(messageArgs)
......@@ -101,11 +111,11 @@ def main():
socket_path_server = 'proxy-'
serverType = args.server
pid = args.pid
if pid == 0:
pid = getpid(serverType)
socket = socket_path_base + socket_path_server + str(pid)
message = formatMessage(args)
sendMessage(socket, message)
......
......@@ -27,6 +27,7 @@
#include <poll.h>
#include "cli.hh"
#include "recordserializer.hh"
#include <flexisip/common.hh>
#include <flexisip/logmanager.hh>
#include <flexisip/registrardb.hh>
......@@ -208,7 +209,7 @@ void CommandLineInterface::run() {
pfd[0].events = POLLIN;
pfd[1].fd = mControlFds[0];
pfd[1].events = POLLIN;
int ret = poll(pfd, 2, -1);
if (ret == -1) {
if (errno != EINTR)
......@@ -277,7 +278,7 @@ std::string CommandLineInterface::printEntry(GenericEntry *entry, bool printHelp
auto gstruct = dynamic_cast<GenericStruct *>(entry);
bool isNode = (gstruct != nullptr);
std::string answer;
if (printHelpInsteadOfValue) {
if (isNode)
answer += "[";
......@@ -320,6 +321,103 @@ void *CommandLineInterface::threadfunc(void *arg) {
ProxyCommandLineInterface::ProxyCommandLineInterface(const std::shared_ptr<Agent> &agent) : CommandLineInterface("proxy"), mAgent(agent) {}
void ProxyCommandLineInterface::handle_registrar_get_command(unsigned int socket, const std::vector<std::string> &args) {
if (args.size() < 1) {
answer(socket, "Error: a SIP address argument is expected for the REGISTRAR_GET command");
return;
}
class RawListener : public ContactUpdateListener {
public:
RawListener(ProxyCommandLineInterface *cli, unsigned int socket)
: mCli(cli), mSocket(socket) {}
void onRecordFound(const shared_ptr<Record> &r) override {
std::string serialized;
RecordSerializerJson::get()->serialize(r.get(), serialized);
mCli->answer(mSocket, serialized);
}
void onError() override {
mCli->answer(mSocket, "ERROR");
}
void onInvalid() override {
mCli->answer(mSocket, "INVALID");
}
// Mandatory since we inherit from ContactUpdateListener
void onContactUpdated(const std::shared_ptr<ExtendedContact> &ec) override {}
private:
ProxyCommandLineInterface *mCli = nullptr;
unsigned int mSocket = 0;
};
auto listener = std::make_shared<RawListener>(this, socket);
std::string arg = args.front();
SofiaAutoHome home;
url_t *url = url_make(home.home(), arg.data());
RegistrarDb::get()->fetch(url, listener, false);
}
void ProxyCommandLineInterface::handle_registrar_delete_command(unsigned int socket, const std::vector<std::string> &args) {
if (args.size() < 2) {
answer(socket, "Error: an URI arguments is expected for the REGISTRAR_DELETE command");
return;
}
class DeleteListener : public ContactUpdateListener {
public:
DeleteListener(ProxyCommandLineInterface *cli, unsigned int socket)
: mCli(cli), mSocket(socket) {}
void onRecordFound(const shared_ptr<Record> &r) override {
std::string serialized;
RecordSerializerJson::get()->serialize(r.get(), serialized);
mCli->answer(mSocket, serialized);
}
void onError() override {
mCli->answer(mSocket, "ERROR");
}
void onInvalid() override {
mCli->answer(mSocket, "INVALID");
}
// Mandatory since we inherit from ContactUpdateListener
void onContactUpdated(const std::shared_ptr<ExtendedContact> &ec) override {}
private:
ProxyCommandLineInterface *mCli = nullptr;
unsigned int mSocket = 0;
};
std::string from = args.at(0);
std::string uuid = args.at(1);
auto msg = nta_msg_create(mAgent->getSofiaAgent(), 0);
msg_header_add_dup(
msg,
nullptr,
reinterpret_cast<msg_header_t*>(sip_request_make(msg_home(msg), "MESSAGE sip:abcd SIP/2.0\r\n"))
);
BindingParameters parameter;
parameter.globalExpire = 0;
// We forge a fake SIP message
auto sip = sip_object(msg);
sip->sip_from = sip_from_create(msg_home(msg), (url_string_t *)from.c_str());
sip->sip_contact = sip_contact_create(
msg_home(msg),
(url_string_t *)from.c_str(), string("+sip.instance=").append(uuid).c_str(),
nullptr
);
sip->sip_call_id = sip_call_id_make(msg_home(msg), "foobar");
auto listener = std::make_shared<DeleteListener>(this, socket);
RegistrarDb::get()->bind(sip, parameter, listener);
}
void ProxyCommandLineInterface::handle_registrar_clear_command(unsigned int socket, const std::vector<std::string> &args) {
if (args.size() < 1) {
answer(socket, "Error: a SIP address argument is expected for the REGISTRAR_CLEAR command");
......@@ -360,6 +458,10 @@ void ProxyCommandLineInterface::handle_registrar_clear_command(unsigned int sock
void ProxyCommandLineInterface::parseAndAnswer(unsigned int socket, const std::string &command, const std::vector<std::string> &args) {
if (command == "REGISTRAR_CLEAR")
handle_registrar_clear_command(socket, args);
else if (command == "REGISTRAR_DELETE")
handle_registrar_delete_command(socket, args);
else if (command == "REGISTRAR_GET")
handle_registrar_get_command(socket, args);
else
CommandLineInterface::parseAndAnswer(socket, command, args);
}
......@@ -52,7 +52,7 @@ private:
std::string agregate(const std::vector<std::string> &args, size_t from_pos);
static void *threadfunc(void *arg);
std::string mName;
pthread_t mThread = 0;
int mControlFds[2] = { 0, 0 };
......@@ -65,6 +65,8 @@ public:
private:
void handle_registrar_clear_command(unsigned int socket, const std::vector<std::string> &args);
void handle_registrar_delete_command(unsigned int socket, const std::vector<std::string> &args);
void handle_registrar_get_command(unsigned int socket, const std::vector<std::string> &args);
void parseAndAnswer(unsigned int socket, const std::string &command, const std::vector<std::string> &args) override;
std::shared_ptr<Agent> mAgent;
......
......@@ -117,6 +117,7 @@ bool RecordSerializerJson::serialize(Record *r, string &serialized, bool log) {
if (ec->line())
cJSON_AddStringToObject(c, "line_value_copy", ec->line());
cJSON_AddStringToObject(c, "contact_id", ec->contactId());
cJSON_AddStringToObject(c, "user_agent", ec->getUserAgent().c_str());
cJSON_AddNumberToObject(c, "update_time", ec->mUpdatedTime);
cJSON_AddStringToObject(c, "call_id", ec->callId());
cJSON_AddNumberToObject(c, "cseq", ec->mCSeq);
......
......@@ -668,10 +668,10 @@ void RegistrarDbRedisAsync::sBindRetry(void *unused, su_timer_t *t, void *ud){
goto fail;
}
if (data->mIsUnregister) goto fail; /* Re-submitting the HDEL is not implemented.*/
self->serializeAndSendToRedis(data, sHandleBindFinish);
return;
fail:
LOGE("Unrecoverable error while updating record fs:%s : no connection", data->mRecord->getKey().c_str());
if (data->listener) data->listener->onError();
......
......@@ -315,7 +315,7 @@ void ExtendedContact::extractInfoFromHeader(const char *urlHeaders) {
reinterpret_cast<msg_common_t*>(headers)->h_class->hc_name) {
string valueStr;
string keyStr = reinterpret_cast<msg_common_t*>(headers)->h_class->hc_name;
valueStr.resize(reinterpret_cast<msg_common_t*>(headers)->h_len + 1);
size_t written = msg_header_field_e(&valueStr[0], reinterpret_cast<msg_common_t*>(headers)->h_len, headers, 0);
valueStr.resize(written);
......@@ -328,7 +328,7 @@ void ExtendedContact::extractInfoFromHeader(const char *urlHeaders) {
if (path){
mPath.push_back(url_as_string(home.home(), path->r_url));
}else{
LOGE("ExtendedContact::extractInfoFromHeader(): bad path [%s]", valueStr.c_str());
LOGE("ExtendedContact::extractInfoFromHeader(): bad path [%s]", valueStr.c_str());
}
} else if (keyStr == "accept") {
mAcceptHeader.push_back(valueStr);
......@@ -487,7 +487,7 @@ void ExtendedContact::extractInfoFromUrl(const char* full_url) {
} else {
url = temp_contact->m_url;
}
if (url == nullptr) {
LOGE("ExtendedContact::extractInfoFromUrl() url is null.");
return;
......@@ -560,7 +560,7 @@ void Record::update(const sip_t *sip, int globalExpire, bool alias, int version,
ostringstream contactId;
string transport;
string uniqueId = extractUniqueId(contacts);
if (url_param(contacts->m_url[0].url_params, "transport", buffer, sizeof(buffer) - 1) > 0) {
transport = buffer;
}
......@@ -570,6 +570,7 @@ void Record::update(const sip_t *sip, int globalExpire, bool alias, int version,
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;
insertOrUpdateBinding(exc, listener);
contacts = contacts->m_next;
}
applyMaxAor();
......@@ -636,7 +637,7 @@ url_t *Record::getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t
char gr_value[256] = {0};
url_t *gruu_addr = NULL;
const char *pub_gruu_value = msg_header_find_param((msg_common_t*)ec->mSipContact, "pub-gruu");
if (pub_gruu_value){
if (pub_gruu_value[0] == '\0'){
/*
......@@ -649,15 +650,15 @@ url_t *Record::getPubGruu(const std::shared_ptr<ExtendedContact> &ec, su_home_t
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.
* 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);
if (result > 0) {
gruu_addr = url_hdup(home, mAor);
url_param_add(home, gruu_addr, su_sprintf(home, "gr=%s", gr_value));
......@@ -1137,7 +1138,7 @@ void RegistrarDb::bind(const sip_t *sip, const BindingParameters &parameter, con
if (instance_param) {
string gr = UriUtils::uniqueIdToGr(instance_param);
if (!gr.empty()){/* assign a public gruu address to this contact */
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
su_sprintf(home.home(), "pub-gruu=\"%s;gr=%s\"", url_as_string(home.home(), sip->sip_from->a_url), gr.c_str() ) );
gruu_assigned = true;
}
......@@ -1148,7 +1149,7 @@ void RegistrarDb::bind(const sip_t *sip, const BindingParameters &parameter, con
/* 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,
msg_header_replace_param(home.home(), (msg_common_t *) sip->sip_contact,
su_sprintf(home.home(), "pub-gruu"));
}
......
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