$Revision$ $Date$
Extend select framework with module related functions If you want to extend functions which select framework can call with some dependent on module you have to follow next steps: define working functions create module's select parsing table in module's mod_init call register_select_table
Define your working functions Working functions are the piece of code, which is called as when SER needs get result of select function (defined as @name.foo[2].bar[5]). The working copy has following definition: int select_function_name(str* res, struct select *s, struct sip_msg *msg) Pointer to the string result workspace res, don't allocate memory for the string, but use static buffer. There is no way to free the allocated memory. Pointer to the parsed select structure s. Holds all names, numbers divided by the dot and square bracket notation. Use that if any of the part used CONSUME_NEXT_STR or CONSUME_NEXT_INT to get the value. Pointer to the processed message structure msg. FIXUP CALL: If you set FIXUP_CALL flag for the final function, the fixup call will be done immediatelly after function resolution. Such call is indicated with res==NULL && msg==NULL. Such call can convert any of the select's parameter into internal data (can hold one pointer), if you do that, set param_type to SEL_PARAM_DATA. Result code of the function declares if the call was successful and if the result is valid string or empty string. -1 error 0 success, res contains non-empty string 1 success, result of select call is empty string (res can be left unchanged)
Create module's select parsing table Define static table of select_row_t type and initialize it directly. The table is representation of tree (or oriented graph if you want), where first column represents current (up-to now) resolved function (starting with NULL), next two columns define if next parameter is integer or particullar string, next column is new resolved function which will be tested in next round and the last column is set of flags. So in the previous example, the first line will accept syntax @test and set the resolved function to select_test. In the next round, all rows with the select_test in the first column will be used to match, so the next two lines are candidates to match depending on the next part of select syntax. If it matches @test.value, the function is resolved to select_test_val, if it matches @test.echo.anystring, it is resolved into select_test_echo. Flag CONSUME_NEXT_STR will accept any string at the 3rd position. As the OPTIONAL flag is not present, it won't accept just the @test.echo syntax. The table ends with the NULL in the 1st and 4th column, other columns are not checked (the notation in the example suits well). At the resolving time all function names must be already defined. For functions which are not leaves, you can use macro ABSTRACT_F(name) to define empty function, for working function you can use advance definition using SELECT_F(name) macro.
Register the created table In the module initialization function call register_select_table(table) where table is the parsing tree/table you have defined in previous step. This call ensures, that the table will become part of the parsing logic for all select framework calls defined in the script file or called by another module's parse_select. NOTE: The tables are inserted into the beginning of the list, so the core's table (and thus parseable names and definitions) can be overrided by module's function, if it is defined with the same name. To avoid such situation, the best practice is to start module's select with the module's name. E.g in our example code both select functions start with @test...
Example - module defining select extension Example module test, which defines two select function. @test.value - returns value passed as modules parameter "value" @test.echo.xxx - returns xxx regardless of what you put as xxx (shows CONSUME_NEXT_STR option) test.c #include "../../sr_module.h" #include "../../str.h" #include "../../dprint.h" #include "../../select.h" MODULE_VERSION static cmd_export_t cmds[] = { {0, 0, 0, 0, 0} }; static char* value=NULL; static param_export_t params[] = { {"value", STR_PARAM, &value}, {0, 0, 0} }; int select_test_val(str* res, struct select* s, struct sip_msg* msg) { DBG("SELECT_TEST_VAL called test_val=%s\n", value); res->s=value; res->len=strlen(value); return 0; } int select_test_echo(str* res, struct select* s, struct sip_msg* msg) { DBG("SELECT_TEST_ECHO called\n"); if (s->params[s->n-1].type==SEL_PARAM_STR) { *res=s->params[s->n-1].v.s; return 0; } else return -1; } ABSTRACT_F(select_test) static select_row_t test_sel[] = { { NULL, SEL_PARAM_STR, STR_STATIC_INIT("test"), select_test, 0}, { select_test, SEL_PARAM_STR, STR_STATIC_INIT("value"), select_test_val, 0}, { select_test, SEL_PARAM_STR, STR_STATIC_INIT("echo"), select_test_echo, CONSUME_NEXT_STR}, { NULL, SEL_PARAM_INT, STR_NULL, NULL, 0} }; static int init(void) { register_select_table(test_sel); return 0; }; struct module_exports exports = { "test", cmds, /* Exported commands */ 0, /* RPC methods */ params, /* Exported parameters */ init, /* module initialization function */ 0, /* response function*/ 0, /* destroy function */ 0, /* oncancel function */ 0 /* per-child init function */ }; ]]>