-
Notifications
You must be signed in to change notification settings - Fork 3
/
c08config.xml
338 lines (334 loc) · 11.1 KB
/
c08config.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
<chapter id="c08config">
<title>Extending configuration file</title>
<para>
<emphasis role="strong"><ulink url="http://flex.sourceforge.net/">flex</ulink></emphasis> and
<emphasis role="strong"><ulink url="http://www.gnu.org/software/bison/">bison</ulink></emphasis>
are used to parse the configuration file and build the actions tree that are executed at run
time for each SIP message. <emphasis role="strong">Bison</emphasis> is the GNU implementation
compatible with Yacc (Yet Another Compiler Compiler), but also Yacc or Byacc can be used instead of it.
</para>
<para>
Extending the configuration file can be done by adding a new core parameter or a new core functions.
Apart of these, one can add new routing blocks, keywords or init and runtime instructions.
</para>
<para>
Starting with release series 3.0, configuration file language has support for preprocessor
directives. They provide an easy way to define tokens to values or enable/disable parts of
configuration file.
</para>
<para>
The config file include two main categories of statements:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="strong">init statements</emphasis> - this category includes setting the global
parameters, loading modules and setting module parameters. These statements are executed only
one time, at startup.
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">runtime statements</emphasis> - this category includes the actions
executed many times, after &kamailio; initialization. These statements are grouped in route
blocks, there being different route types that get executed for certain events.
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="strong">route</emphasis> - is executed when a SIP request is received
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">onreply_route</emphasis> - is executed when a SIP reply is
received
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">error_route</emphasis> - is executed when some errors
(mainly related to message parsing) are encountered
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">failure_route</emphasis> - is executed when a negative reply
was received for a transaction that armed the handler for the failure event.
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">branch_route</emphasis> - is executed for each destination branch
of the transaction that armed the handler for it.
</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>
In the next section we will present how to add a core parameter and add a routing action -- core function.
You need to have knowledge of <emphasis role="strong">flex</emphasis> and
<emphasis role="strong">bison</emphasis>.
</para>
<section id="c08add_parameters">
<title>Adding a core parameter</title>
<para>
Some of the core parameters correspond to global variables in &kamailio; sources. Others induce
actions to be taken during statup.
</para>
<para>
Let's follow step by step the definition and usage of the core parameter
<emphasis role="strong">log_name</emphasis>. It is a string parameter that specifies the
value to be printed as application name in syslog messages.
</para>
<para>
First is the declaration of the variable in the C code. The <emphasis role="strong">log_name</emphasis>
is defined in <emphasis role="strong">main.c</emphasis> and initialized to
<emphasis role="strong">0</emphasis> (when set to <emphasis role="strong">o</emphasis>,
it is printed the &kamailio; name (including path) in the syslog).
</para>
<programlisting format="linespecific">
...
char *log_name = 0;
...
</programlisting>
<para>
Next is to define the token in the <emphasis role="strong">flex</emphasis> file:
<emphasis role="strong">cfg.lex</emphasis>.
</para>
<programlisting format="linespecific">
...
LOGNAME log_name
...
</programlisting>
<para>
The association of a token ID and extending the grammar of the configuration file is done
in the <emphasis role="strong">bison</emphasis> file:
<emphasis role="strong">cfg.y</emphasis>.
</para>
<programlisting format="linespecific">
...
%token LOGNAME
...
assign_stm: ...
| LOGNAME EQUAL STRING { log_name=$3; }
| LOGNAME EQUAL error { yyerror("string value expected"); }
...
</programlisting>
<para>
The grammar was extended with a new assign statement, that allows to write in the configuration
file an expression like:
</para>
<programlisting format="linespecific">
...
log_name = "kamailio123"
...
</programlisting>
<para>
When having a line like above one in the configuration file, the variable
<emphasis role="strong">log_name</emphasis> in C code will be initialized to the string
in the right side of the equal operator.
</para>
</section>
<section id="c08add_functions">
<title>Adding a core function</title>
<para>
To introduce new functions in &kamailio; core that are exported to the configuration file
the grammar have to be extended (<emphasis role="strong">bison</emphasis> and
<emphasis role="strong">flex</emphasis> files), the interpreter must be enhanced to be
able to run the new actions.
</para>
<para>
Behind each core function resides an action structure. This data type is defined in
<emphasis role="strong">route_struct.h</emphasis>:
</para>
<programlisting format="linespecific">
...
typedef struct {
action_param_type type;
union {
long number;
char* string;
struct _str str;
void* data;
avp_spec_t* attr;
select_t* select;
} u;
} action_u_t;
/* maximum internal array/params
* for module function calls val[0] and val[1] store a pointer to the
* function and the number of params, the rest are the function params
*/
#define MAX_ACTIONS (2+6)
struct action{
int cline;
char *cfile;
enum action_type type; /* forward, drop, log, send ...*/
int count;
struct action* next;
action_u_t val[MAX_ACTIONS];
};
...
</programlisting>
<para>
Each action is identified by a type. The types of actions are defined in same header
file. For example, the <emphasis role="strong">strip(...)</emphasis> function has
the type <emphasis role="strong">STRIP_T</emphasis>, the functions exported by
modules have the type <emphasis role="strong">MODULE_T</emphasis>.
</para>
<para>
To each action may be given a set of parameters, so called action elements. In case of
functions exported by modules, the first element is the pointer to the function, next are the
parameters given to that function in configuration file.
</para>
<para>
For debugging and error detection, the action keeps the line number in configuration file
where it is used.
</para>
<para>
Next we discuss how <emphasis role="strong">setflag(...)</emphasis> config function was
implemented.
</para>
<section id="c08extend_grammar">
<title>Extending the grammar</title>
<para>
Define the token in <emphasis role="strong">flex</emphasis> file:
<emphasis role="strong">cfg.lex</emphasis>.
</para>
<programlisting format="linespecific">
...
SETFLAG "setflag"
...
</programlisting>
<para>
Assign a token ID and extend the <emphasis role="strong">bison</emphasis> grammar.
</para>
<programlisting format="linespecific">
<![CDATA[
...
%token SETFLAG
...
cmd: ...
| SETFLAG LPAREN NUMBER RPAREN {
if (check_flag($3)==-1)
yyerror("bad flag value");
$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
(void*)$3);
set_cfg_pos($$);
}
| SETFLAG LPAREN flag_name RPAREN {
i_tmp=get_flag_no($3, strlen($3));
if (i_tmp<0) yyerror("flag not declared");
$$=mk_action(SETFLAG_T, 1, NUMBER_ST,
(void*)(long)i_tmp);
set_cfg_pos($$);
}
| SETFLAG error { $$=0; yyerror("missing '(' or ')'?"); }
...
]]>
</programlisting>
<para>
First grammar specification says that <emphasis role="strong">setflag(...)</emphasis>
can have one parameter of type <emphasis role="strong">number</emphasis>. The other
rule for grammar is to detect error cases.
</para>
</section>
<section id="c08extend_interpreter">
<title>Extending the interpreter</title>
<para>
First step is to add a new action type in <emphasis role="strong">route_struct.h</emphasis>.
</para>
<para>
Then add a new case in the switch of action types, file
<emphasis role="strong">action.c</emphasis>, function
<emphasis role="strong"></emphasis>
</para>
<programlisting format="linespecific">
<![CDATA[
...
case SETFLAG_T:
if (a->val[0].type!=NUMBER_ST) {
LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n",
a->val[0].type );
ret=E_BUG;
goto error;
}
if (!flag_in_range( a->val[0].u.number )) {
ret=E_CFG;
goto error;
}
setflag( msg, a->val[0].u.number );
ret=1;
break;
...
]]>
</programlisting>
<para>
The C function <emphasis role="strong">setflag(...)</emphasis> is defined and implemented
in <emphasis role="strong">flags.{c,h}</emphasis>. It simply sets the bit in
<emphasis role="strong">flags</emphasis>
attribute of <emphasis role="strong">sip_msg</emphasis> at the position given by
the parameter.
</para>
<programlisting format="linespecific">
...
int setflag( struct sip_msg* msg, flag_t flag ) {
msg->flags |= 1 << flag;
return 1;
}
...
</programlisting>
<para>
We are not done yet. &kamailio; does a checking of the actions tree after all configuration
file was loaded. It does sanity checks and optimization for run time. For our case, it does
a double-check that the parameter is a number and it is in the range of
<emphasis role="strong">0...31</emphasis> to fit in the bits size of an integer value. See
function <emphasis role="strong">fix_actions(...)</emphasis> in
<emphasis role="strong">route.c</emphasis>.
</para>
<para>
Next example is given just to show how such fixup can look like, it is no longer used for
flag operations functions.
</para>
<programlisting format="linespecific">
...
case SETFLAG_T:
case RESETFLAG_T:
case ISFLAGSET_T:
if (t->elem[0].type!=NUMBER_ST) {
LM_CRIT("bad xxxflag() type %d\n", t->elem[0].type );
ret=E_BUG;
goto error;
}
if (!flag_in_range( t->elem[0].u.number )) {
ret=E_CFG;
goto error;
}
break;
...
</programlisting>
<para>
Last thing you have to add is to complete the function
<emphasis role="strong">print(action(...)</emphasis> with a new case for your action
that will be used to print the actions tree -- for debugging purposes. See it in file
<emphasis role="strong">route_struct.c</emphasis>.
</para>
<programlisting format="linespecific">
...
case SETFLAG_T:
LM_DBG("setflag(");
break;
...
</programlisting>
<para>
From now on, you can use in your configuration file the function
<emphasis role="strong">setflag(_number_)</emphasis>.
</para>
<para>
Don't forget to add documentation in
<emphasis role="strong">&kamailio; Core Cookbook</emphasis>.
</para>
</section>
</section>
</chapter>