Login | Register

Documentation

Documentation -> Development Manual -> Management Interface API

This page has been visited 195 times.



Management Interface API

The Management Interface is the abstract layer that is commonly used to control and monitor OpenSIPS. The MI Interface supports multiple actual back-ends ( eg. FIFO, Datagram, XMLRPC, HTTP GET JSON, etc ) - due to the modularity of the interface and also due to the clear separation between the logic and the transport layer, the developer just defines the functions to be externally called, and then it is up to the OpenSIPS script writer to chose what transport he will actually use for controlling OpenSIPS.
The MI interface heavily uses trees :

  • the Interface will provide as input a tree with the parameters provided by the user
  • an MI function has to also return a tree, which will then be converted by the transport module to it's specific representation


Further on we will focus on the core MI functions, with a specific focus on the debug function. Note that modules can ( an commonly ) also export MI functions - see the Modules Development MI functions topic for more information on that.
The structures commonly used for exporting MI functions are found in mi/mi.h :

typedef struct mi_export_ {
        /* the name of the function ( users will call this from their transport of choice */
        char *name;
        /* short description of the usage of this function */
        char *help;
        /* actual function that will get called */
        mi_cmd_f *cmd;
        /* flags for this function. Currently options are :
             - MI_ASYNC_RPL_FLAG - the function has an asynchronous behaviour ( eg: MI functions that send SIP messages and wait for their reply )
             - MI_NO_INPUT_FLAG - the function does not receive any parameters
        */

        unsigned int flags;
        /* parameter that will be passed when the cmd function gets called */
        void *param;
        /* the initialization function to be called by OpenSIPS ( one time ) */
        mi_child_init_f *init_f;
}mi_export_t;

/* Example of core MI exported function */
static mi_export_t mi_core_cmds[] = {
        { "uptime", "prints various time information about OpenSIPS - "
                "when it started to run, for how long it runs",
                mi_uptime,     MI_NO_INPUT_FLAG,  0,  init_mi_uptime },
        { "version", "prints the version string of a runningOpenSIPS",
                mi_version,    MI_NO_INPUT_FLAG,  0,  0 },
        { "pwd", "prints the working directory of OpenSIPS",
                mi_pwd,        MI_NO_INPUT_FLAG,  0,  0 },
...
...
...
/* For exporting the populated array of MI functions
Parameters :
      mod_name : the name of the module exporting these functions
      mis : the array of exported MI functions
Returns :
      0 on success, negative in case of error
*/

int register_mi_mod( char *mod_name, mi_export_t *mis);

/* Example of usage */
if (register_mi_mod( "core", mi_core_cmds)<0) {
      LM_ERR("unable to register core MI cmds\n");
      return -1;  
}


The structures commonly used for implementing MI functions are also found in mi/mi.h :

/*
Parameters :
      input : the tree that contains the command paramenters
      param : the parameter provided at function registration
Returns :
      A mi_root tree containing the function reply
*/

typedef struct mi_root* (mi_cmd_f)(struct mi_root *input, void *param);

/* below are the used structures for representing the tree root and the tree nodes */
struct mi_root {
      /* int code - similar to SIP or HTTP code */
      unsigned int       code;
      /* string reason for code - similar to SIP or HTTP reason */
      str                reason;
      /* handler in case of asynchronous MI commands */
      struct mi_handler  *async_hdl;
      /* the actual root node in our tree */
      struct mi_node     node;
};

struct mi_node {
      str value;
      str name;
      unsigned int flags;
      struct mi_node *kids;
      struct mi_node *next;
      struct mi_node *last;
      struct mi_attr *attributes;
};      

struct mi_attr{
        str name;
        str value;
        struct mi_attr *next;
};


As can be noted from the above tree definition, a node has a name and a value associated to it,it can have one or multiple children ( stored in kids pointer ), and also it can have a list of key-value attributes associated to it.
For building the output MI tree, mi/tree.h and mi/attr.h expose the following functions :

/* Use for creating a new output reply tree
Parameters :
      code : success code for this tree ( >=200<300 for success, anything else for errors )
      reason : string reasons representation for the code
      reason_len : length of the reason parameter
Returns :
      A new mi_root tree, or NULL in case of error. Note that this function will allocate the node in PKG and it typically has to be returned - the freeing will be done in the MI core, after the output tree is written by the transport module */

struct mi_root *init_mi_tree(unsigned int code, char *reason, int reason_len);

/* Adding a new child node to our tree - typically first called to mi_root->node.kids
Parameters :
      parent : the parent node for our newly added node
      flags : Current options are :
                   MI_DUP_NAME : the name of this node needs to be duplicated in PKG
                   MI_DUP_VALUE : the value of the current node needs to be duplicated in PKG
      name : the name of the current node
      name_len : length of the node's name
      value : the value of the current node
      value_len : length of the node's value
*/

struct mi_node *add_mi_node_child(struct mi_node *parent, int flags,
        char *name, int name_len, char *value, int value_len);
/* Adding a new sibling node to one of our nodes
Parameters :
      brother : the brother node for our newly added node
      flags : Current options are :
                   MI_DUP_NAME : the name of this node needs to be duplicated in PKG
                   MI_DUP_VALUE : the value of the current node needs to be duplicated in PKG
      name : the name of the current node
      name_len : length of the node's name
      value : the value of the current node
      value_len : length of the node's value
*/

struct mi_node *add_mi_node_sibling(struct mi_node *brother, int flags,
        char *name, int name_len, char *value, int value_len);
/* Adding a new attribute to one of our nodes
      node : the node we will be adding the key-value attribute to
      flags : Current options are :
                   MI_DUP_NAME : the name of this attribute needs to be duplicated in PKG
                   MI_DUP_VALUE : the value of the current attribute needs to be duplicated in PKG
      name : the name of the current attribute
      name_len : length of the node's attribute name
      value : the value of the current value
      value_len : length of the node's attribute value
*/

struct mi_attr *add_mi_attr(struct mi_node *node, int flags,                                      
        char *name, int name_len, char *value, int value_len)


Further on, we will follow the implementation of the debug MI function. If called with no parameters, the function will return the current debug level in OpenSIPS. If called with one integer parameter, then the function will set the current debug level to the provided parameter.

struct mi_root *mi_debug(struct mi_root *cmd, void *param)
{
      struct mi_root *rpl_tree;
      struct mi_node *node;
      char *p;
      int len;
      int new_debug;

      /* check the kids member of our root node -
      if the input root node has kids, our command was called with parameters */

      node = cmd->node.kids;
      if (node!=NULL) {
            /* take the node's value and convert it to int, to make sure the parameter is valid */
            if (str2sint( &node->value, &new_debug) < 0)
                  /* if failed to convert to int, still return a RPL tree with an >=400 code and reason */
                  return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
      } else
            new_debug = *debug;

      /* all is good so far, initialize a new output ROOT tree which has a 200 OK code & reason */
      rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
      if (rpl_tree==0)
              return 0;

      p = sint2str((long)new_debug, &len);
      /* add a new node to our output tree, which the current debug level */
      node = add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE,
             MI_SSTR("DEBUG"),p, len);
      if (node==0) {
              free_mi_tree(rpl_tree);
              return 0;
      }

      /* if all was successful, overwrite the actual debug level, and return our tree */
      *debug = new_debug;
      return rpl_tree;
}


For more generic information on the MI Interface as well as some examples used for running MI commands with the opensipsctl utility, see the MI Interface documentation page.


Page last modified on May 31, 2024, at 09:55 AM