Peerstate Module

Serdar Güçlüer

   Netgsm ICT Inc.
   <serdar.gucluer@hotmail.com>

   Copyright © 2025 Netgsm ICT Inc., http://www.netgsm.com.tr
     __________________________________________________________________

   Table of Contents

   1. Admin Guide

        1. Overview
        2. How it works
        3. Peer states
        4. Dependencies

              4.1. Kamailio Modules
              4.2. External Libraries or Applications

        5. Parameters

              5.1. cache_hash_size (integer)
              5.2. cache_expire (integer)
              5.3. cache_cleanup_interval (integer)
              5.4. use_avps (integer)
              5.5. caller_avp (string)
              5.6. callee_avp (string)
              5.7. reg_avp (string)
              5.8. enable_notify_on_trying (integer)
              5.9. disable_caller_notify_flag (integer)
              5.10. disable_callee_notify_flag (integer)
              5.11. disable_reg_notify (integer)
              5.12. disable_dlg_notify (integer)

        6. RPC Commands

              6.1. peerstate.get_peer
              6.2. peerstate.stats
              6.3. peerstate.list
              6.4. peerstate.dump

        7. Event Routes

              7.1. event_route[peerstate:state_changed]

   2. Developer Guide

        1. Available Functions

              1.1. bind_peerstate(peerstate_api_t *api)
              1.2. register_peerstate_callback(int event_types,
                      peerstate_cb_f callback, void *param)

   List of Examples

   1.1. Set cache_hash_size parameter
   1.2. Set cache_expire parameter
   1.3. Set cache_cleanup_interval parameter
   1.4. Set use_avps parameter
   1.5. Set caller_avp parameter
   1.6. Set callee_avp parameter
   1.7. Set reg_avp parameter
   1.8. Set enable_notify_on_trying parameter
   1.9. Set disable_caller_notify_flag parameter
   1.10. Set disable_callee_notify_flag parameter
   1.11. Set disable_reg_notify parameter
   1.12. Set disable_dlg_notify parameter
   1.13. event_route[peerstate:state_changed] usage
   2.1. Callback registration example

Chapter 1. Admin Guide

   Table of Contents

   1. Overview
   2. How it works
   3. Peer states
   4. Dependencies

        4.1. Kamailio Modules
        4.2. External Libraries or Applications

   5. Parameters

        5.1. cache_hash_size (integer)
        5.2. cache_expire (integer)
        5.3. cache_cleanup_interval (integer)
        5.4. use_avps (integer)
        5.5. caller_avp (string)
        5.6. callee_avp (string)
        5.7. reg_avp (string)
        5.8. enable_notify_on_trying (integer)
        5.9. disable_caller_notify_flag (integer)
        5.10. disable_callee_notify_flag (integer)
        5.11. disable_reg_notify (integer)
        5.12. disable_dlg_notify (integer)

   6. RPC Commands

        6.1. peerstate.get_peer
        6.2. peerstate.stats
        6.3. peerstate.list
        6.4. peerstate.dump

   7. Event Routes

        7.1. event_route[peerstate:state_changed]

1. Overview

   The peerstate module provides peer state tracking for the Kamailio SIP
   proxy. It monitors both dialog events (call states) and registration
   events (usrloc) to maintain an accurate view of each peer's current
   status.

   For example, a common need in call center applications is to track
   agent availability in real-time. In order to monitor agent states, it
   is necessary for the proxy to be aware of both call activity and
   registration status. This is just one common application; there are
   many others such as presence services, load balancing, and concurrent
   call limiting.

   The module exports RPC commands for monitoring and management, provides
   an event route mechanism for custom logic execution, and offers a
   callback API for other Kamailio modules.

2. How it works

   The peerstate module registers callbacks with the dialog and usrloc
   modules. When dialog state changes (EARLY, CONFIRMED, TERMINATED) or
   registration events (REGISTER/UNREGISTER) occur, the module updates its
   internal cache and determines if a peer's state has changed.

   Peer state is maintained in a shared memory hash table. Each peer entry
   contains current state, active call count, registration flag, and
   timestamp.

   State transitions:
     * EARLY events increment call count and set peer to RINGING (or keep
       INUSE if already in call)
     * CONFIRMED events set peer to INUSE
     * TERMINATED events decrement call count; peer returns to NOT_INUSE
       (if registered) or UNAVAILABLE (if not registered) when call count
       reaches zero
     * REGISTER events set registration flag and may transition from
       UNAVAILABLE to NOT_INUSE
     * UNREGISTER events clear registration flag and may transition from
       NOT_INUSE to UNAVAILABLE (if no active calls)

   When a peer's state changes, the module triggers notifications via
   event routes and callback functions.

3. Peer states

   Peer states tracked by the module:
     * 0 : NOT_INUSE - Peer is registered and idle (no active calls)
     * 1 : INUSE - Peer is in an active call (dialog confirmed)
     * 2 : RINGING - Peer has incoming or outgoing call ringing (early
       dialog)
     * 3 : UNAVAILABLE - Peer is not registered
     * 4 : NA - Not applicable or unknown state

   State transitions are designed to accurately reflect the peer's
   availability:
     * A peer transitions to RINGING when receiving or making a call
     * A peer transitions to INUSE when the call is answered
     * A peer returns to NOT_INUSE when all calls end and the peer is
       still registered
     * A peer transitions to UNAVAILABLE when unregistering with no active
       calls
     * Active calls are preserved during registration changes

4. Dependencies

   4.1. Kamailio Modules
   4.2. External Libraries or Applications

4.1. Kamailio Modules

   The following modules must be loaded before this module:
     * Dialog - Dialog tracking module
     * Usrloc - User location module

4.2. External Libraries or Applications

   The following libraries or applications must be installed before
   running Kamailio with this module loaded:
     * None.

5. Parameters

   5.1. cache_hash_size (integer)
   5.2. cache_expire (integer)
   5.3. cache_cleanup_interval (integer)
   5.4. use_avps (integer)
   5.5. caller_avp (string)
   5.6. callee_avp (string)
   5.7. reg_avp (string)
   5.8. enable_notify_on_trying (integer)
   5.9. disable_caller_notify_flag (integer)
   5.10. disable_callee_notify_flag (integer)
   5.11. disable_reg_notify (integer)
   5.12. disable_dlg_notify (integer)

5.1. cache_hash_size (integer)

   The size of the hash table internally used to keep the peer state
   information. A larger table is much faster but consumes more memory.
   The hash size must be a power of two.

   Default value is “4096”.

   Example 1.1. Set cache_hash_size parameter
...
modparam("peerstate", "cache_hash_size", 8192)
...

5.2. cache_expire (integer)

   The time in seconds after which inactive peer entries are removed from
   the cache. Set to 0 to disable automatic expiration. This helps
   conserve memory by removing stale peer information. Minimum allowed
   value is 60 seconds (when enabled).

   Default value is “3600” (1 hour).

   Example 1.2. Set cache_expire parameter
...
modparam("peerstate", "cache_expire", 7200)
...

5.3. cache_cleanup_interval (integer)

   The interval in seconds between automatic cache cleanup runs. Must be
   less than or equal to cache_expire. Set to 0 to disable automatic
   cleanup. During cleanup, expired entries are removed from the cache.
   Minimum allowed value is 10 seconds (when enabled).

   Default value is “300” (5 minutes).

   Example 1.3. Set cache_cleanup_interval parameter
...
modparam("peerstate", "cache_cleanup_interval", 600)
...

5.4. use_avps (integer)

   Enable or disable the use of AVPs for peer identification instead of
   extracting peer information from SIP headers. When enabled, the module
   will use the AVPs specified by caller_avp, callee_avp, and reg_avp
   parameters to identify peers.

   If set to 0, the module extracts peer information from From/To headers.
   If set to 1, AVPs must be set by the routing script.

   Default value is “0” (disabled).

   Example 1.4. Set use_avps parameter
...
modparam("peerstate", "use_avps", 1)
...

5.5. caller_avp (string)

   The specification of an AVP that contains the caller's peer identifier.
   Only used when use_avps is set to 1. The AVP should contain the peer
   identifier in the format "peer@domain".

   Default value is “NULL”.

   Example 1.5. Set caller_avp parameter
...
modparam("peerstate", "caller_avp", "$avp(caller_peer)")
...

5.6. callee_avp (string)

   The specification of an AVP that contains the callee's peer identifier.
   Only used when use_avps is set to 1. The AVP should contain the peer
   identifier in the format "peer@domain".

   Default value is “NULL”.

   Example 1.6. Set callee_avp parameter
...
modparam("peerstate", "callee_avp", "$avp(callee_peer)")
...

5.7. reg_avp (string)

   The specification of an AVP that contains the registered peer
   identifier for usrloc events. Only used when use_avps is set to 1.

   Default value is “NULL”.

   Example 1.7. Set reg_avp parameter
...
modparam("peerstate", "reg_avp", "$avp(reg_peer)")
...

5.8. enable_notify_on_trying (integer)

   Enable state change notifications for dialog TRYING state. By default,
   only EARLY, CONFIRMED, and TERMINATED states trigger notifications.
   When enabled, TRYING state will also trigger notifications.

   Default value is “0” (disabled).

   Example 1.8. Set enable_notify_on_trying parameter
...
modparam("peerstate", "enable_notify_on_trying", 1)
...

5.9. disable_caller_notify_flag (integer)

   Message flag to disable caller state change notifications for specific
   calls. When this flag is set on a message, state changes for the caller
   will not trigger notifications. Set to -1 to disable this feature.

   Default value is “-1” (feature disabled).

   Example 1.9. Set disable_caller_notify_flag parameter
...
modparam("peerstate", "disable_caller_notify_flag", 10)
...
# In routing script:
if ($rU == "1234567890") {
    setflag(10);  # Don't notify about emergency call callers
}
...

5.10. disable_callee_notify_flag (integer)

   Message flag to disable callee state change notifications for specific
   calls. When this flag is set on a message, state changes for the callee
   will not trigger notifications. Set to -1 to disable this feature.

   Default value is “-1” (feature disabled).

   Example 1.10. Set disable_callee_notify_flag parameter
...
modparam("peerstate", "disable_callee_notify_flag", 11)
...

5.11. disable_reg_notify (integer)

   Globally disable registration event processing. When set to 1, the
   module will not register callbacks with the usrloc module and will not
   process registration events.

   Default value is “0” (process registration events).

   Example 1.11. Set disable_reg_notify parameter
...
modparam("peerstate", "disable_reg_notify", 1)
...

5.12. disable_dlg_notify (integer)

   Globally disable dialog event processing. When set to 1, the module
   will not register callbacks with the dialog module and will not process
   dialog events.

   Default value is “0” (process dialog events).

   Example 1.12. Set disable_dlg_notify parameter
...
modparam("peerstate", "disable_dlg_notify", 1)
...

6. RPC Commands

   6.1. peerstate.get_peer
   6.2. peerstate.stats
   6.3. peerstate.list
   6.4. peerstate.dump

6.1.  peerstate.get_peer

   Get detailed state information for a specific peer. Returns the peer's
   current state, active call count, and registration status.

   Name: peerstate.get_peer

   Parameters:
     * peer - peer identifier in the format "peer@domain"

   RPC Command Format:
...
kamctl rpc peerstate.get_peer 1000@192.168.1.100
...

   The command returns a structure containing:
     * peer - peer identifier
     * state - current state (NOT_INUSE, INUSE, RINGING, UNAVAILABLE)
     * call_count - number of active calls
     * registered - registration status ("yes" or "no")

6.2.  peerstate.stats

   Get global cache statistics including total number of peers, number of
   peers in active calls, and number of registered peers.

   Name: peerstate.stats

   Parameters: none

   RPC Command Format:
...
kamctl rpc peerstate.stats
...

   The command returns a structure containing:
     * total_peers - total number of peers in cache
     * incall_peers - number of peers in INUSE or RINGING state
     * registered_peers - number of registered peers

6.3.  peerstate.list

   List all peers in a specific state. This command is useful for
   monitoring which peers are currently in a particular state.

   Name: peerstate.list

   Parameters:
     * state - state filter (NOT_INUSE, INUSE, RINGING, or UNAVAILABLE)

   RPC Command Format:
...
kamctl rpc peerstate.list INUSE
...

   The command returns a structure containing:
     * count - number of peers in the specified state
     * state - the state filter used
     * Peer - array of peer objects with name, state, call_count, and
       registered status

6.4.  peerstate.dump

   Dump all peers from the cache regardless of state. This command
   provides a complete view of all tracked peers.

   Name: peerstate.dump

   Parameters: none

   RPC Command Format:
...
kamctl rpc peerstate.dump
...

   The command returns a structure containing:
     * count - total number of peers
     * Peer - array of peer objects with name, state, call_count, and
       registered status

7. Event Routes

   7.1. event_route[peerstate:state_changed]

7.1.  event_route[peerstate:state_changed]

   Executed when a peer's state changes. Provides access to state change
   information through AVP pseudo-variables.

   Available pseudo-variables:
     * $avp(ps_peer) - Peer identifier
     * $avp(ps_state) - Current state (NOT_INUSE, INUSE, RINGING,
       UNAVAILABLE)
     * $avp(ps_prev_state) - Previous state
     * $avp(ps_uniq_id) - Call-ID or RUID

   Example 1.13. event_route[peerstate:state_changed] usage
...
event_route[peerstate:state_changed] {
    xlog("L_INFO", "Peer $avp(ps_peer): $avp(ps_prev_state) -> $avp(ps_state)");

    # HTTP notification
    if ($avp(ps_state) == "INUSE") {
        http_async_query("http://api.local/state", "peer=$avp(ps_peer)&state=bus
y", "HTTP_REPLY");
    }
}
...

Chapter 2. Developer Guide

   Table of Contents

   1. Available Functions

        1.1. bind_peerstate(peerstate_api_t *api)
        1.2. register_peerstate_callback(int event_types, peerstate_cb_f
                callback, void *param)

1. Available Functions

   1.1. bind_peerstate(peerstate_api_t *api)
   1.2. register_peerstate_callback(int event_types, peerstate_cb_f
          callback, void *param)

1.1.  bind_peerstate(peerstate_api_t *api)

   Bind to the peerstate API and fill the provided structure with function
   pointers.

   Meaning of the parameters is as follows:
     * peerstate_api_t *api - pointer to API structure

   The API structure:
typedef struct peerstate_api {
    register_peerstate_cb_f register_callback;
} peerstate_api_t;

   Return value:
     * 0 - success
     * -1 - error

1.2.  register_peerstate_callback(int event_types, peerstate_cb_f callback,
void *param)

   Register a callback function for peer state change notifications.

   Meaning of the parameters is as follows:
     * int event_types - Bitmask of event types:
          + PEERSTATE_EVENT_DIALOG (1) - Dialog events
          + PEERSTATE_EVENT_REGISTRATION (2) - Registration events
     * peerstate_cb_f callback - Callback function with signature:
       void callback(peerstate_cb_ctx_t *ctx, void *param);
     * void *param - User parameter (can be NULL)

   The callback context structure:
typedef struct peerstate_cb_ctx {
    str peer;                      /* Peer identifier */
    ps_state_t current_state;        /* Current state */
    ps_state_t previous_state;       /* Previous state */
    int call_count;                /* Active call count */
    int is_registered;             /* Registration status */
    str uniq_id;                   /* Call-ID or RUID */
    peerstate_event_type_t event_type;  /* Event type */
} peerstate_cb_ctx_t;

   State enumeration:
typedef enum ps_state {
    NOT_INUSE,      /* Registered and idle */
    INUSE,          /* In active call */
    RINGING,        /* Ringing */
    UNAVAILABLE,    /* Not registered */
    NA              /* Unknown */
} ps_state_t;

   Return value:
     * 0 - success
     * -1 - error

   Example 2.1. Callback registration example
#include "../peerstate/peerstate_cb.h"

static peerstate_api_t peerstate_api;

/* Callback function */
static void my_state_callback(peerstate_cb_ctx_t *ctx, void *param) {
    LM_INFO("Peer %.*s: %s -> %s (calls=%d, reg=%s)\n",
            ctx->peer.len, ctx->peer.s,
            PS_STATE_TO_STR(ctx->previous_state),
            PS_STATE_TO_STR(ctx->current_state),
            ctx->call_count,
            ctx->is_registered ? "yes" : "no");
}

/* Module initialization */
static int mod_init(void) {
    bind_peerstate_f bind_peerstate;

    bind_peerstate = (bind_peerstate_f)find_export("bind_peerstate", 1, 0);
    if (!bind_peerstate || bind_peerstate(&peerstate_api) < 0) {
        LM_ERR("Cannot bind to peerstate module\n");
        return -1;
    }

    if (peerstate_api.register_callback(
            PEERSTATE_EVENT_DIALOG | PEERSTATE_EVENT_REGISTRATION,
            my_state_callback, NULL) < 0) {
        LM_ERR("Failed to register callback\n");
        return -1;
    }

    return 0;
}
