– Kamailio SIP Server –

Writing OpenSER module

My interest is mostly in writing new Modules for OpenSER at this time. I could not find a lot of information about it, so I started this page set. Please if you find I am going down the wrong path, correct me and these pages. I will try to only include correct information, but I am learning as I go.

Introduction

The code and APIs are based off the current 1.1.x source base.

When starting a new module, there are a few things you must do. Listed below will get you started with the template module structured code example:

Template Module

#include "../../sr_module.h"
 
MODULE_VERSION/*Module */
 
static int mod_init(void);
static void mod_destroy(void);
static int child_init(int);
 
/*
 * Script commands we export.
 */
static cmd_export_t cmds[]={
  {0,0,0,0,0}
};
 
/*
 * Script parameters
 */
static param_export_t mod_params[]={
  { 0,0,0 }
};
 
/*
 * Export the statistics we have
 */
static stat_export_t mod_stats[] = {
  {0,0,0}
};
 
struct module_exports exports= {
  "MyMod",	/* module's name */
  cmds,         /* exported functions */
  mod_params,   /* param exports */
  mod_stats,    /* exported statistics */
  modInit,      /* module initialization function */
  0,            /* reply processing function FIXME Not sure when this is used */
  modDestroy,   /* Destroy function */
  childInit     /* per-child init function */
};
 
/**
 * @return 0 to continue to load the OpenSER, -1 to stop the loading
 * and abort OpenSER.
 */
static int modInit(void) {
  return(0);
}
 
/**
 * Called only once when OpenSER is shuting down to clean up module
 * resources.
 */
static void modDestroy() {
  return;
}
 
/**
 * The rank will be o for the main process calling this function,
 * or 1 through n for each listener process. The rank can have a negative
 * value if it is a special process calling the child init function.
 * Other then the listeners, the rank will equal one of these values:
 * PROC_MAIN      0  Main ser process
 * PROC_TIMER    -1  Timer attendant process 
 * PROC_FIFO     -2  FIFO attendant process
 * PROC_TCP_MAIN -4  TCP main process
 * PROC_UNIXSOCK -5  Unix domain socket server processes
 *
 * If this function returns a nonzero value the loading of OpenSER will
 * stop.
 */
static int childInit(int rank) {
  int rtn = 0;
 
  return(rtn);
}
  • The sr_module.h file must be included
  • You must include the MODULE_VERSION macro. This tells OpenSER the module was built for the correct version of the running OpenSER when the module is loaded. If the version number does not match, the load will fail.
  • Declare your local initialization and destructor functions.
  • Fill out the following data structures to export the modules functionality.
    • cmd_export_t - This structure is where you export the script functions. (more on it later)
    • param_export_t structure is used to export the modules parameters that can be set in the script (openser.cfg)
    • stat_export_t If your module wants to track statistics this is where you declare and export them.
    • module_exports - This is where you tie all the exported information together to define your new Module.
      • The module name. A char * that uniquely identifies your module.
      • The pointer to the cmd_export_t (or NULL if none defined)
      • The pointer to the param_export_t (or NULL if none defined)
      • The pointer to the stat_export_t (or NULL if none defined)
      • The module initialization function pointer. FIXME Function prototype needed here. (rw)
      • FIXME Need more information on this function pointer.
      • The module destroy function pointer. FIXME Need prototype here. (rw)
      • FIXME Need the child init function explained and included in the example. (rw)

You should be able to cut and paste the code above into your first module “C” file. To build the module, read the Module Makefile section.

Module export structure

cmd_export_t

struct cmd_export_t {
	char* name;             /* null terminated command name */
	cmd_function function;  /* pointer to the corresponding function */
	int param_no;           /* number of parameters used by the function */
	fixup_function fixup;   /* pointer to the function called to "fix" the
				   parameters */
	int flags;              /* Function flags */
};
  • name char * - A null terminated command name.
  • function int (*cmd_function)(struct sip_msg*, char*, char*) - The C function pointer to bind to the named script function.
  • param_no int - The number of parameters to pass to the C function (the function argument count)
  • fixup int (*fixup_function)(void * * param, int param_no); - FIXME Need more information on this function.
  • flags int - Can't have a structure without flags! The flags tell the script when it is legal to call the function. The flag values can be “or'ed” together if the function can be called from more then one routing section of the openser.cfg script. i.e. REQUEST_ROUTE | ONREPLY_ROUTE
    • REQUEST_ROUTE - The function can be called in the request route section of the openser.cfg script.
    • FAILURE_ROUTE - The function can be called in the failure route section of the openser.cfg script.
    • ONREPLY_ROUTE - The function can be called in the reply route section of the openser.cfg script.
    • BRANCH_ROUTE - The function can be called in the branch route section of the openser.cfg script.

Hints & Tips

Because the module is written in “C” you must be carefull about naming your functions. The function field in the cmd_export_t structure can be file scope (static) if you want to define the real handler in the same file as you define the cmd_export_t structure. In most cases you will want to define all your handlers in a separate file like MyMod_handlers.c. In this case, make sure you add your module name to the begining of the function named to ensure there is no namespace collisions. i.e. MyMod_func1().

Licensing of Modules

The relevant part of the GPL concerning distribution of proprietary modules is the bottom of section 2, here quoted:

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

So, if you are writing a closed module that washes the dog, walks the dishes, and controls the light in your aquarium within the larger context of the openSER framework, without modifying the framework, directing people who wish source code to the openSER web site to obtain the GPL'd portions of a proprietary and commercial VOIP-controlled dog-washing, dish-walking, aquarium-light-controlling appliance is sufficent, although RMS will probably not share his ravs with you should the opportunity arise. Your module's main focus – home automation with regard to dogs, dishes, and pet fish – is not the main focus of openSER, and although your module plugs into the openSER framework, it could just as well plug into some other framework instead of openSER.

The GPL would not force distribution of your trade secrets involved in your dog/dish/fish component.

Addition of a module does not constitute a modification of openSER, nor does selection of openSER as a product's framework for interfacing with VOIP necessarily make the resulting composite work a derivative work of openSER.

Said home automation system would not be “based on” openSER. Said home automation system would include openSER for VOIP functionality.

Adherence to the provided and documented module API fulfills the “arm's length” requirement discussed at http://www.gnu.org/licenses/gpl-faq.html#TOCGPLInProprietarySystem even though the module and the framework will be linked into a single binary executable file, which is a technical detail.