Login | Register

Documentation

Documentation -> Development Manual 3.1 -> Usrloc Module API

This page has been visited 1013 times.


Pages for other versions: devel 3.4 3.3 3.2 3.1 Older versions:


Usrloc Module API

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:

struct usrloc_api ul;

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


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

  • take various decisions based on the runtime configurations of the user location module
  • define new user location domains or access existing ones
  • create, update or delete Addresses-of-Record (which are stored within a domain)
  • 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:

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;

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