Documentation |
Documentation.Development-Manual-API-Script-Func-3-1 HistoryHide minor edits - Show changes to markup December 11, 2019, at 06:51 PM
by
- Added lines 1-276:
Documentation -> Development Manual 3.1 -> Extending the Configuration FileThis page has been visited 1834 times. (:title OpenSIPS Development - Extending the Configuration File:) (:allVersions Development-Manual-API-Config-File 3.1:)
(:toc-float Table of Content:) OpenSIPS uses flex and bison in order to parse the configuration file and then build the entire action tree that a SIP message will go through once it is read from network level. Adding a core parameterIn the following step by step tutorial, we will follow the implementation of the udp_workers core parameter, which is an integer controlling the number of OpenSIPS processes per UDP interface.
Adding a core functionIn the following step by step tutorial, we will follow the implementation of the xlog core function, which is used to print information to the logging facility. Note that xlog can receive either a single parameter (the string to be printed), or two parameters (the log level and then the string to be printed). First, we extend the lexer file with the new word. Under cfg.lex, we have: (:source lang=C -link -getcode :) XLOG "xlog" (:sourceend:)
| XLOG LPAREN STRING RPAREN { mk_action1($$, XLOG_T, STR_ST, $3); } | XLOG LPAREN folded_string RPAREN { mk_action1($$, XLOG_T, STR_ST, $3); } | XLOG LPAREN STRING COMMA STRING RPAREN { mk_action2($$, XLOG_T, STR_ST, STR_ST, $3, $5); } | XLOG LPAREN STRING COMMA folded_string RPAREN { mk_action2($$, XLOG_T, STR_ST, STR_ST, $3, $5); } (:sourceend:)
case XLOG_T: s.s = (char*)t->elem[1].u.data; if (s.s == NULL) { /* commands have only one parameter */ s.s = (char *)t->elem[0].u.data; s.len = strlen(s.s); if(s.len==0) { LM_ERR("param is empty string!\n"); return E_CFG; } if(pv_parse_format(&s ,&model) || model==NULL) { LM_ERR("wrong format [%s] for value param!\n", s.s); ret=E_BUG; goto error; } t->elem[0].u.data = (void*)model; t->elem[0].type = SCRIPTVAR_ELEM_ST; } else { /* there are two parameters */ (:sourceend:)
script_trace("core", "xlog", msg, a->file, a->line) ; if (a->elem[1].u.data != NULL) { if (a->elem[1].type != SCRIPTVAR_ELEM_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type); ret=E_BUG; break; } if (a->elem[0].type != STR_ST) { LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type); ret=E_BUG; break; } ret = xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data); if (ret < 0) { LM_ERR("error while printing xlog message\n"); break; } } else { (:sourceend:) Adding a core Pseudo-VariableAll the OpenSIPS core pseudo-variables are defined in pvar.c : (:source lang=C -link -getcode :) static pv_export_t _pv_names_table[] = { {{"avp", (sizeof("avp")-1)}, PVT_AVP, pv_get_avp, pv_set_avp, pv_parse_avp_name, pv_parse_index, 0, 0}, {{"hdr", (sizeof("hdr")-1)}, PVT_HDR, pv_get_hdr, 0, pv_parse_hdr_name, pv_parse_index, 0, 0}, {{"hdrcnt", (sizeof("hdrcnt")-1)}, PVT_HDRCNT, pv_get_hdrcnt, 0, pv_parse_hdr_name, 0, 0, 0}, {{"var", (sizeof("var")-1)}, PVT_SCRIPTVAR, pv_get_scriptvar, pv_set_scriptvar, pv_parse_scriptvar_name, 0, 0, 0}, {{"ai", (sizeof("ai")-1)}, /* */ PVT_PAI_URI, pv_get_pai, 0, 0, 0, 0, 0}, {{"au", (sizeof("au")-1)}, /* */ PVT_AUTH_USERNAME, pv_get_authattr, 0, 0, 0, pv_init_iname, 1}, ...
...
...
(:sourceend:)
(:source lang=C -link -getcode :) /*! \brief * PV spec format: * - $class_name * - $class_name(inner_name) * - $(class_name[index]) * - $(class_name(inner_name)[index]) * - $(class_name{transformation}) * - $(class_name(inner_name){transformation}) * - $(class_name[index]{transformation}) * - $(class_name(inner_name)[index]{transformation}) */ typedef struct _pv_export { str name; /*!< class name of PV */ pv_type_t type; /*!< type of PV */ pv_getf_t getf; /*!< function to get the value */ pv_setf_t setf; /*!< function to set the value */ pv_parse_name_f parse_name; /*!< function to parse the inner name */ pv_parse_index_f parse_index; /*!< function to parse the index of PV */ pv_init_param_f init_param; /*!< function to init the PV spec */ int iparam; /*!< parameter for the init function */ } pv_export_t;
(:sourceend:)
(:source lang=C -link -getcode :) {{"ru", (sizeof("ru")-1)}, /* */ PVT_RURI, pv_get_ruri, pv_set_ruri, 0, 0, 0, 0}, (:sourceend:) Our new pvar will be accessible from script by using $ru. Read access from the script will lead to pv_get_ruri getting called, while write requests to $ru will make a call to pv_set_ruri.
msg - the message context to evaluate the current pvar param - the parameter provided for evaluating the pvar res - the output value of our pvar Returns : 0 in case of success, negative in case of error
static int pv_get_ruri(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { if(msg==NULL || res==NULL) return -1; if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */ return pv_get_null(msg, param, res); if(msg->parsed_uri_ok==0 /* R-URI not parsed*/ && parse_sip_msg_uri(msg)<0) { LM_ERR("failed to parse the R-URI\n"); return pv_get_null(msg, param, res); } if (msg->new_uri.s!=NULL) return pv_get_strval(msg, param, res, &msg->new_uri); return pv_get_strval(msg, param, res, &msg->first_line.u.request.uri); }
(:sourceend:)
For all read access on the PVARs from contexts where the PVAR does not have any meaningful value (eg. Request-URI from a Reply Context), make sure to use pv_get_null to signal this to the script writer.
msg - the SIP message to apply the changes to param - the parameter provided for evaluating the pvar op - further indication on the type of write access to be done val - value to be pushed to our pvar Returns : 0 in case of success, negative in case of error
int pv_set_ruri(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) { if(msg==NULL || param==NULL || val==NULL) { LM_ERR("bad parameters\n"); return -1; } /* type checking, we can only push strings to R-URI */ if(!(val->flags&PV_VAL_STR)) { LM_ERR("str value required to set R-URI\n"); goto error; } /* populate the message R-URI with the string value from the provided val */ if (set_ruri( msg, &val->rs)!=0) { LM_ERR("failed to set RURI\n"); goto error; } return 0; error: return -1; } (:sourceend:) |