Skip to content

Commit

Permalink
Merge pull request #3328 from carstenbock/usrloc_kv_store
Browse files Browse the repository at this point in the history
Usrloc kv store
  • Loading branch information
liviuchircu committed Apr 10, 2024
2 parents 1a50d66 + c841104 commit 0f6b411
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 5 deletions.
144 changes: 139 additions & 5 deletions modules/usrloc/doc/usrloc_admin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ modparam("usrloc", "cluster_mode", "federation-cachedb")
cluster-based restart persistency. Following a restart,
an OpenSIPS cluster node will search for a healthy "donor" node
from which to mirror the entire user location dataset via
direct cluster sync (TCP-based, binary-encoded data transfer).
direct cluster sync (TCP-based, binary-encoded data transfer).
Depending on the clustering mode and cluster topology, this will
require the configuration of one or multiple "seed" nodes in the cluster.
Choosing this value will make the
Expand Down Expand Up @@ -1475,9 +1475,143 @@ modparam("usrloc", "contact_refresh_timer", true)

<section id="exported_functions" xreflabel="exported_functions">
<title>Exported Functions</title>
<para>
There are no exported functions that could be used in scripts.
</para>

<section id="func_ul_add_key" xreflabel="ul_add_key(domain, aor, key_name[, key_value])">
<title>
<function moreinfo="none">ul_add_key(domain, aor, key_name, [key_value])</function>
</title>
<para>
Append a Key/Value to the Key-Value-Store of a Usrloc-Record.
</para>
<para>
Returns false, if no record is found is usrloc.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
<listitem>
<para><emphasis>domain (string)</emphasis> - Domain of the
AOR, e.g. "location"
</para>
</listitem>
<listitem>
<para><emphasis>aor (string)</emphasis> - Address-of-Record,
save the key for a specific (registered) user.
</para>
</listitem>
<listitem>
<para><emphasis>key (string)</emphasis> - The name of the
key to be stored.
</para>
</listitem>
<listitem>
<para><emphasis>value (string, optional)</emphasis>
- The value to be stored. Not providing the value or
by providing an empty value, will delete the entry.
</para>
</listitem>
</itemizedlist>
<para>
This function can be used in ANY route.
</para>
<example>
<title><function>ul_add_key</function> usage</title>
<programlisting format="linespecific">
...
ul_add_key("location", "$tU@$td", "service_route", "$hdr(Service-Route)");
...
</programlisting>
</example>
</section>

<section id="func_ul_get_key" xreflabel="ul_get_key(domain, aor, key_name, destination)">
<title>
<function moreinfo="none">ul_get_key(domain, aor, key_name, destination)</function>
</title>
<para>
Retrieve a Key/Value from the Key-Value-Store of a Usrloc-Record.
</para>
<para>
Returns false, if no record is found is usrloc or no according key is found.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
<listitem>
<para><emphasis>domain (string)</emphasis> - Domain of the
AOR, e.g. "location"
</para>
</listitem>
<listitem>
<para><emphasis>aor (string)</emphasis> - Address-of-Record,
save the key for a specific (registered) user.
</para>
</listitem>
<listitem>
<para><emphasis>key (string)</emphasis> - The name of the
key to be retrieved.
</para>
</listitem>
<listitem>
<para><emphasis>destination (variable)</emphasis>
- A variable, where to store the retrieved key.
</para>
</listitem>
</itemizedlist>
<para>
This function can be used in ANY route.
</para>
<example>
<title><function>ul_get_key</function> usage</title>
<programlisting format="linespecific">
...
if (ul_get_key("location", "$tU@$td", "service_route", "$avp(service_route)")) {
append_to_reply("Service-Route: $avp(service_route)\r\n");
}
...
</programlisting>
</example>
</section>

<section id="func_ul_del_key" xreflabel="ul_del_key(domain, aor, key_name)">
<title>
<function moreinfo="none">ul_del_key(domain, aor, key_name)</function>
</title>
<para>
Deletes a Key/Value from the Key-Value-Store of a Usrloc-Record.
</para>
<para>
Returns false, if no record is found is usrloc.
</para>
<para>Meaning of the parameters is as follows:</para>
<itemizedlist>
<listitem>
<para><emphasis>domain (string)</emphasis> - Domain of the
AOR, e.g. "location"
</para>
</listitem>
<listitem>
<para><emphasis>aor (string)</emphasis> - Address-of-Record,
save the key for a specific (registered) user.
</para>
</listitem>
<listitem>
<para><emphasis>key (string)</emphasis> - The name of the
key to be deleted.
</para>
</listitem>
</itemizedlist>
<para>
This function can be used in ANY route.
</para>
<example>
<title><function>ul_del_key</function> usage</title>
<programlisting format="linespecific">
...
ul_del_key("location", "$tU@$td", "service_route");
...
</programlisting>
</example>
</section>

</section>


Expand Down Expand Up @@ -1784,7 +1918,7 @@ modparam("usrloc", "contact_refresh_timer", true)
registration message.(empty string if not present)
</para></listitem>
<listitem><para>
<emphasis>qval</emphasis> - The Q value (priority) of the
<emphasis>qval</emphasis> - The Q value (priority) of the
contact (as integer value from 0 to 10).
</para></listitem>
<listitem><para>
Expand Down
96 changes: 96 additions & 0 deletions modules/usrloc/kv_store.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include "../../lib/cJSON.h"
#include "../../lib/osips_malloc.h"
#include "urecord.h"

int_str_t *kv_get(map_t _store, const str* _key)
{
Expand Down Expand Up @@ -238,3 +239,98 @@ void store_destroy(map_t _store)
if (_store)
map_destroy(_store, destroy_kv_store_val);
}


int w_add_key(struct sip_msg* _m, void* _d, str* aor, str* key, str* value)
{
urecord_t *r;
udomain_t *domain = (udomain_t*)_d;
int_str_t insert_value;

lock_udomain(domain, aor);
get_urecord(domain, aor, &r);
if (r) {
if (value->len > 0) {
insert_value.is_str = 1;
insert_value.s = *value;
if (!kv_put(r->kv_storage, key, &insert_value)) {
unlock_udomain(domain, aor);
LM_ERR("failed to store KV\n");
return -1;
}
} else {
kv_del(r->kv_storage, key);
}
} else {
unlock_udomain(domain, aor);
LM_WARN("No record found - not inserting key into KV store - user not registered?\n");
return -1;
}

unlock_udomain(domain, aor);
return 1;
}

int w_get_key(struct sip_msg* _m, void* _d, str* aor, str* key, pv_spec_t* destination)
{
urecord_t *r;
udomain_t *domain = (udomain_t*)_d;
int_str_t * key_value;
pv_value_t out_val;

lock_udomain(domain, aor);
get_urecord(domain, aor, &r);

if (r) {
key_value = kv_get(r->kv_storage, key);
if (key_value) {
if (key_value->is_str) {
out_val.flags = PV_VAL_STR;
out_val.rs = key_value->s;
if (pv_set_value(_m, destination, 0, &out_val) != 0) {
unlock_udomain(domain, aor);
LM_ERR("failed to write to destination variable\n");
return -1;
}
} else {
out_val.flags = PV_VAL_INT;
out_val.ri = key_value->i;
if (pv_set_value(_m, destination, 0, &out_val) != 0) {
unlock_udomain(domain, aor);
LM_ERR("failed to write to destination variable\n");
return -1;
}
}
} else {
unlock_udomain(domain, aor);
LM_WARN("Key not found in record - unable to retrieve value from KV store\n");
return -1;
}
} else {
unlock_udomain(domain, aor);
LM_WARN("No record found - unable to retrieve value from KV store - user not registered?\n");
return -1;
}

unlock_udomain(domain, aor);
return 1;
}

int w_delete_key(struct sip_msg* _m, void* _d, str* aor, str* key)
{
urecord_t *r;
udomain_t *domain = (udomain_t*)_d;

lock_udomain(domain, aor);
get_urecord(domain, aor, &r);
if (r) {
kv_del(r->kv_storage, key);
} else {
unlock_udomain(domain, aor);
LM_WARN("No record found - not deleting value from KV store - user not registered?\n");
return -1;
}

unlock_udomain(domain, aor);
return 1;
}
5 changes: 5 additions & 0 deletions modules/usrloc/kv_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#define __KV_STORE_H__

#include "../../map.h"
#include "../../pvar.h"

int_str_t *kv_get(map_t _store, const str* _key);
int_str_t *kv_put(map_t _store, const str* _key, const int_str_t* _val);
Expand All @@ -46,4 +47,8 @@ map_t store_deserialize(const str *input);

void store_destroy(map_t _store);

int w_add_key(struct sip_msg* _m, void* _d, str* aor, str* key, str* value);
int w_get_key(struct sip_msg* _m, void* _d, str* aor, str* key, pv_spec_t* destination);
int w_delete_key(struct sip_msg* _m, void* _d, str* aor, str* key);

#endif /* __KV_STORE_H__ */
47 changes: 47 additions & 0 deletions modules/usrloc/ul_mod.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "../../globals.h" /* is_main */
#include "../../ut.h" /* str_init */
#include "../../ipc.h"
#include "../../pvar.h"

#include "ul_mod.h"
#include "dlist.h" /* register_udomain */
Expand All @@ -61,6 +62,7 @@
#include "ul_mi.h"
#include "ul_callback.h"
#include "usrloc.h"
#include "kv_store.h"

#define CONTACTID_COL "contact_id"
#define USER_COL "username"
Expand Down Expand Up @@ -91,6 +93,9 @@ int ul_check_config(void);
int ul_check_db(void);
int ul_deprec_shp(modparam_t _, void *modparam);

/*! \brief Fixup functions */
static int domain_fixup(void** param);

//static int add_replication_dest(modparam_t type, void *val);

extern int bind_usrloc(usrloc_api_t* api);
Expand Down Expand Up @@ -187,6 +192,26 @@ int latency_event_min_us;
*/
static const cmd_export_t cmds[] = {
{"ul_bind_usrloc", (cmd_function)bind_usrloc, {{0,0,0}},0},
{"ul_add_key", (cmd_function)w_add_key, {
{CMD_PARAM_STR|CMD_PARAM_STATIC, domain_fixup, 0},
{CMD_PARAM_STR, 0, 0},
{CMD_PARAM_STR, 0, 0},
{CMD_PARAM_STR|CMD_PARAM_OPT, 0, 0},
{0,0,0}},
ALL_ROUTES},
{"ul_get_key", (cmd_function)w_get_key, {
{CMD_PARAM_STR|CMD_PARAM_STATIC, domain_fixup, 0},
{CMD_PARAM_STR, 0, 0},
{CMD_PARAM_STR, 0, 0},
{CMD_PARAM_VAR, 0, 0},
{0,0,0}},
ALL_ROUTES},
{"ul_del_key", (cmd_function)w_delete_key, {
{CMD_PARAM_STR|CMD_PARAM_STATIC, domain_fixup, 0},
{CMD_PARAM_STR, 0, 0},
{CMD_PARAM_STR, 0, 0},
{0,0,0}},
ALL_ROUTES},
{0,0,{{0,0,0}},0}
};

Expand Down Expand Up @@ -933,3 +958,25 @@ int ul_check_db(void)

return 0;
}

/*! \brief
* Convert char* parameter to udomain_t* pointer
*/
static int domain_fixup(void** param)
{
udomain_t* d;
str d_nt;

if (pkg_nt_str_dup(&d_nt, (str*)*param) < 0)
return E_OUT_OF_MEM;

if (register_udomain(d_nt.s, &d) < 0) {
LM_ERR("failed to register domain\n");
return E_UNSPEC;
}

pkg_free(d_nt.s);

*param = (void*)d;
return 0;
}

0 comments on commit 0f6b411

Please sign in to comment.