Documentation

Documentation.Development-Manual-ModAPI-Usrloc-3-1 History

Hide minor edits - Show changes to output

January 12, 2021, at 06:32 PM by liviu -
Changed line 35 from:
* create, update or delete Addresses-of-Record
to:
* create, update or delete Addresses-of-Record (which are stored within a domain)
January 12, 2021, at 06:31 PM by liviu -
Changed line 23 from:
LM_ERR("failed to load user location API\n");
to:
LM_ERR("failed to load the user location API\n");
January 12, 2021, at 06:31 PM by liviu -
Changed line 15 from:
The ''user location API'' can be accessed by importing the '''modules/usrloc/usrloc.h''' header file. Once imported in your OpenSIPS module, you will then have to declare a '''struct usrloc_api''' and bind its values in the ''module initialization'' phase. Sample code:
to:
The ''user location API'' can be accessed by importing the '''modules/usrloc/usrloc.h''' header file. Once imported in your OpenSIPS module, you will then have to declare a '''struct usrloc_api''' and fill in its values in the ''module initialization'' phase. Sample code:
January 12, 2021, at 06:25 PM by liviu -
Added line 33:
* take various decisions based on the runtime configurations of the user location module
January 12, 2021, at 06:24 PM by liviu -
Added lines 14-41:

The ''user location API'' can be accessed by importing the '''modules/usrloc/usrloc.h''' header file. Once imported in your OpenSIPS module, you will then have to declare a '''struct usrloc_api''' and bind its values in the ''module initialization'' phase. Sample code:

(:source lang=C -link -getcode :)
struct usrloc_api ul;

static int mod_init(void)
{
if (load_ul_api(&ul) < 0) {
LM_ERR("failed to load user location API\n");
return -1;
}
}
(:sourceend:)

\\

From here onward, you can make full use of the API, in order to:

* define new user location domains or access existing ones
* create, update or delete Addresses-of-Record
* create, update or delete contacts (which are stored within an Address-of-Record)
* subscribe to AoR events: creation / update / deletion / expiration
* subscribe to contact events: creation / update / deletion / expiration

\\

The C API is fully described in the '''usrloc.h''' file:
January 12, 2021, at 06:16 PM by liviu -
Changed lines 13-392 from:
(:toc-float Table of Content:)
to:
(:toc-float Table of Content:)

(:source lang=C -link -getcode :)
typedef struct usrloc_api {
int use_domain;

enum ul_cluster_mode cluster_mode;

/* whether the user location caches contacts in OpenSIPS memory */
int (*have_mem_storage) (void);

/* whether the user location makes use of contact ownership tags */
int (*tags_in_use) (void);

/* the NAT branch flag, as bitmask */
unsigned int nat_flag;

/**
* Register a new usrloc domain. If the domain already exists, a pointer
* to an existing structure will be returned.
* NOTE: may only be called before forking! (e.g., during mod_init())
*
* @name: name of the new domain (if using a DB, it is also the table name)
* @d: output variable holding the domain
*
* Return: 0 (success), negative otherwise
*/
int (*register_udomain) (const char *name, udomain_t **d);

/**
* Lock/Unlock the hash table entry of the given Address-of-Record.
* NOTE: you MUST always lock an AoR before using any AoR or contact
* manipulation functions of this API.
*
* @d: the usrloc domain to use
* @aor: the AoR to grab/release the entry for
*/
void (*lock_udomain) (udomain_t *d, str *aor);
void (*unlock_udomain) (udomain_t *d, str *aor);

/**
* Fetch a given AoR from an usrloc domain.
* NOTE: remember to @release_urecord() when you are done with it!
*
* @d: the domain to search within
* @aor: the AoR to fetch
* @r: will hold the returned object if found, NULL otherwise
*
* Return: 0 (found), 1 (not found) otherwise
*/
int (*get_urecord) (udomain_t *d, str *aor, struct urecord **r);

/**
* Fetch a given AoR from an usrloc domain, across multiple locations.
* Thus, this function is only relevant when using
* cluster_mode == CM_FEDERATION_CACHEDB. The function will return success
* if the AoR exists in at least one location.
*
* @d: the domain to search within
* @aor: the AoR to fetch
* @r: will hold the returned object if found, NULL otherwise
*
* Return: 0 (found), 1 (not found) otherwise
*/
int (*get_global_urecord) (udomain_t *d, str *aor, struct urecord **r);

/**
* Release an (urecord_t) object previously obtained through either
* @get_urecord or @get_global_urecord.
*
* @r: the usrloc record to release
* @skip_replication: set to true in order to avoid replicating an AoR
* deletion event, if any, to neighboring cluster nodes
*/
void (*release_urecord) (urecord_t *r, char skip_replication);

/**
* Create and insert a new Address-of-Record into the given domain.
* NOTE: will leak shared memory if the record already exists! Use
* @get_urecord accordingly beforehand to prevent this.
*
* @d: the domain to insert the record into
* @aor: the AoR to insert
* @r: will hold the newly created object
* @skip_replication: set to true in order to avoid replicating an AoR
* insertion event to neighboring cluster nodes
*
* Return: 0 (success), negative otherwise
*/
int (*insert_urecord) (udomain_t *d, str *aor, struct urecord **r,
char skip_replication);

/**
* Fetch a key from record-level storage.
* NOTE: remember to lock the urecord beforehand.
*
* @r: the record to search into
* @key: the key to locate
*
* Return: NULL on error/key not found, value pointer otherwise
*/
int_str_t *(*get_urecord_key) (urecord_t *r, const str *key);

/**
* Create or re-assign a key-value pair within record-level storage.
* NOTES:
* - remember to lock the urecord beforehand
* - both @key and @val will be duplicated in shared memory
*
* @r: the record to search into
* @key: the key to locate
* @val: the value to set
*
* Return: NULL on error, new value pointer otherwise
*/
int_str_t *(*put_urecord_key) (urecord_t *r, const str *key,
const int_str_t *val);

/**
* Delete a given AoR from an usrloc domain, along with all of its
* contacts.
*
* @d: the domain to search within
* @aor: the AoR to delete
* @r: optional, if available -- the exact object to delete
* @skip_replication: set to true in order to avoid replicating deletion
* events to neighboring cluster nodes for both contact
* and AoR deletions
*
* Return: 0 (success), negative otherwise
*/
int (*delete_urecord) (udomain_t *d, str *aor, struct urecord *r,
char skip_replication);

/**
* Match a contact against a list of contacts stored in an usrloc record.
*
* @r: the usrloc record to search for the contact
* @ct_uri: the contact URI to search
* @callid: the SIP Call-ID of the pending REGISTER message
* @cseq: the SIP CSeq of the pending REGISTER message
* @match: how to match the pending contact against existing bindings
* @c: will hold the returned contact if found or NULL
*
* Return:
* 0 - contact found and returned in @c
* 1 - contact not found
* -1 - contact found, however the given @cseq is too old and you
* should ignore this REGISTER
* -2 - contact found, however the given @cseq is equal to the existing
* one, so you should ignore this REGISTER (is it a retransmission?)
*/
int (*get_ucontact) (urecord_t *r, str *ct_uri, str *callid, int cseq,
struct ct_match *match, ucontact_t **c);

/**
* Fetch a ucontact from an usrloc domain using a contact ID.
* NOTE: on success, the urecord *lock will be grabbed*!
* Remember to @release_urecord, followed by @unlock_udomain!
*
* @d: the domain to search within
* @id: the contact ID, a 64-bit unsigned integer
* @r: will hold the contact's usrloc record, if found
*
* Return:
* NULL, if contact not found
* pointer to the contact, if found
*/
ucontact_t *(*get_ucontact_from_id) (udomain_t *d,
ucontact_id id, urecord_t **r);

/**
* Create and add a new contact to the list of contacts in @r. If
* @desc_time_order is on, the contact will be simply appended at the head
* of the list (most recent), otherwise in descending q-value order.
*
* @r: the usrloc record of the contact
* @ct_uri: the SIP URI of the contact
* @ci: various info pertaining to the contact, extract from the REGISTER
* message (and not only!)
* @c: will hold the contact, once created
* @skip_replication: set to true in order to avoid replicating an "insert"
* event to neighboring cluster nodes
*
* Return: 0 (success), negative otherwise
*/
int (*insert_ucontact) (urecord_t *r, str *ct_uri, ucontact_info_t *ci,
ucontact_t **c, char skip_replication);

/**
* Update the info of an existing usrloc contact, possibly on a re-REGISTER
*
* @r: the usrloc record of the contact
* @c: the usrloc contact to update
* @ci: various info pertaining to the contact to update
* @skip_replication: set to true in order to avoid replicating an "update"
* event to neighboring cluster nodes
*
* Return: 0 (success), negative otherwise
*/
int (*update_ucontact) (urecord_t *r, ucontact_t *c, ucontact_info_t *ci,
char skip_replication);

/**
* Fetch a key from contact-level storage.
* NOTE: remember to lock the urecord beforehand.
*
* @c: the usrloc contact to search into
* @key: the key to locate
*
* Return: NULL on error/key not found, value pointer otherwise
*/
int_str_t *(*get_ucontact_key) (ucontact_t *c, const str *key);

/**
* Create or re-assign a key-value pair within contact-level storage.
* NOTES:
* - remember to lock the urecord beforehand
* - both @key and @val will be duplicated in shared memory
*
* @c: the usrloc contact to search into
* @key: the key to locate
* @val: the value to set
*
* Return: NULL on error, new value pointer otherwise
*/
int_str_t *(*put_ucontact_key) (ucontact_t *c, const str *key,
const int_str_t *val);

/**
* Delete a contact from a given usrloc record.
*
* @r: the usrloc record
* @c: the usrloc contact to delete
* @skip_replication: set to true in order to avoid replicating a "delete"
* event to neighboring cluster nodes
*
* Return: 0 (success), negative otherwise
*/
int (*delete_ucontact) (urecord_t *r, ucontact_t *c,
char skip_replication);

/**
* Delete a contact from a given usrloc domain, using its hash table or
* SIP coordinates.
*
* @d: the usrloc domain to search within
* @coords: the contact ID or SIP coordinates of the contact
* (see @ucontact_coords for more info)
* @skip_replication: set to true in order to avoid replicating a "delete"
* event to neighboring cluster nodes
*
* Return: 0 (success), negative otherwise
*/
int (*delete_ucontact_from_coords) (udomain_t *d, ucontact_coords coords,
char skip_replication);

/**
* Compare @ucontact_coords structs @a and @b.
*
* Return: 0 if equal, -1 otherwise
*/
int (*ucontact_coords_cmp) (ucontact_coords a, ucontact_coords b);

/**
* Free an @ucontact_coords object.
*/
void (*free_ucontact_coords) (ucontact_coords coords);

/**
* Generate the next contact ID of a given record. Returns a different
* contact ID on each new call, rotating across CLABEL_MASK values.
*
* @r: the usrloc record
*
* Return: the next contact ID
*/
uint64_t (*next_contact_id) (urecord_t *r);

/**
* Update the SIP pinging latency of a contact, i.e. the round-trip delay
* of pinging a contact using a SIP OPTIONS message.
*
* @d: the usrloc domain to update
* @coords: the SIP coordinates of the contact
* @sipping_latency: new latency value, in microseconds
*
* Return: 0 (success), negative otherwise
*/
int (*update_sipping_latency) (udomain_t *d, ucontact_coords coords,
int sipping_latency);

/**
* Raise an async registration refresh event for an usrloc contact
*
* @ct: the usrloc contact
* @reason: short text denoting the reason for the refresh
* @req_callid: Call-ID of the pending SIP request or NULL if not available
*/
void (*raise_ev_ct_refresh) (const ucontact_t *ct, const str *reason,
const str *req_callid);

/**
* Easily iterate through all currently registered domains.
* @d: the last fetched domain. Use a NULL value to fetch the 1st domain.
*
* Return: the next domain or NULL if the end of list end has been reached.
*/
udomain_t *(*get_next_udomain) (udomain_t *d);

/**
* Low-level functions to lock/unlock a hash table bucket on a given domain
* @d: the domain to use
* @slot: the index of the bucket, must be less than @d->size
*/
void (*lock_ulslot) (udomain_t *d, int slot);
void (*unlock_ulslot) (udomain_t *d, int slot);

/**
* Return all contacts for all currently registered users in the given
* domain. The function expects a buffer of sufficient length to fit all
* contacts. If the buffer is exhausted, the function returns the
* estimated amount of additional space needed. In this case, the caller
* is expected to repeat the call using this value as the hint.
*
* @d: the usrloc domain to search within
* @buf: the input buffer
* @buf_len: the length of the buffer
* @flags: flag bitmask to be used as a filter (use 0 to skip)
* @part_idx / @part_max: partition the contact space. E.g.:
* * to only grab the top 25% of contacts, use: "0 / 4"
* * to grab all contacts, use: "0 / 1"
* @pack_coords: Set to 1 to include the contact coords in the buffer,
* otherwise 0. See @ucontact_coords for more info.
*
* The contact information is packed into the buffer as follows:
*
* +=======+======+=========+=======+=============+======+========+=======+
* |int |char[]|int |char[] |socket_info *|uint |proxy_l |uint64 |
* +=======+======+=========+=======+=============+======+========+=======+
* |ct1.len|ct1.s |path1.len|path1.s|sock1 |flags1|nx_hop1 |coords1|
* +-------+------+---------+-------+-------------+------+--------+-------+
* |ct2.len|ct2.s |path2.len|path2.s|sock2 |flags2|nx_hop2 |coords2|
* +-------+------+---------+-------+-------------+------+--------+-------+
* | ... | ... | ... | ... | ... | ... | ... | ... |
* +-------+------+---------+-------+-------------+------+--------+-------+
* |ctN.len|ctN.s |pathN.len|pathN.s|sockN |flagsN|nx_hopN |coordsN|
* +-------+------+---------+-------+-------------+------+--------+-------+
* |0000000|
* +-------+
*/
int (*get_domain_ucontacts) (udomain_t *d, void *buf, int buf_len,
unsigned int flags, unsigned int part_idx,
unsigned int part_max, int pack_coords);

/**
* Similar to @get_domain_ucontacts, except it works for all current usrloc
* domains, with the contacts of each domain being merged together, without
* the ability to discern the domain of a given contact anymore.
*/
int (*get_all_ucontacts) (void *buf, int buf_len, unsigned int flags,
unsigned int part_idx, unsigned int part_max,
int pack_coords);

/**
* Subscribe to various user location create/update/delete/expire events
* concerning records (AoRs) and contacts.
*
* @types: bitmask of callback types to register the @cb callback for
* @cb: The registered callback function. Explanation of its arguments:
* - @binding: depending on the callback type, you should cast it to
* either (ucontact_t *) or (urecord_t *)
* - @type: type of the invoked callback (e.g. UL_CONTACT_EXPIRE)
*
* Return: 0 (success), negative otherwise
*/
int (*register_ulcb) (ul_cb_type types,
void (*cb) (void *binding, ul_cb_type type));
} usrloc_api_t;
(:sourceend:)
December 11, 2019, at 07:24 PM by liviu -
Added lines 1-13:
!!!!!Documentation -> [[Documentation.Development-Manual-3-1|Development Manual 3.1]] -> Usrloc Module API
This page has been visited {$PageCount} times.
(:title OpenSIPS Development - Usrloc Module API:)
----
(:allVersions Development-Manual-ModAPI-Usrloc 3.1:)

\\

|| %color=#185662%[+'''Usrloc Module API'''+]%% ||

----

(:toc-float Table of Content:)

Page last modified on January 12, 2021, at 06:32 PM