-
Notifications
You must be signed in to change notification settings - Fork 3
/
c12transformations.xml
260 lines (256 loc) · 8.82 KB
/
c12transformations.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
<chapter id="c12transformations">
<title>Transformations</title>
<para>
The transformations are strictly related to pseudo-variables. They are properties that
can be associated to instances of pseudo-variables. A transformation produces changes to the
value returned by a pseudo-variable. There can be a chain of transformations assigned to same
instance of a pseudo-variable.
</para>
<para>
An example of a transformation is to get a substring from the value returned by a
pseudo-variable. Another one is to get the length of the values returned by a pseudo-variable.
</para>
<para>
The value of a pseudo-variable with a chain of transformations is evaluated as:
</para>
<itemizedlist>
<listitem>
<para>
get the value of the pseudo-variable
</para>
</listitem>
<listitem>
<para>
apply the operation specified by the first transformation to the value returned by
the pseudo-variable
</para>
</listitem>
<listitem>
<para>
apply the operation specified by the current transformation to the value returned by
the previous transformation. Go to next transformation.
</para>
</listitem>
<listitem>
<para>
the value returned by the last transformation is returned to script or to calling C code.
</para>
</listitem>
</itemizedlist>
<para>
Behind each transformation it is a function that does value (pv_value_t) manipulation. It has as input
such a value and as output another value, stored over the input value. The transformation are
implemented mainly in &kamailio; modules, data structures and API are in file
<emphasis role="strong">pvar.h</emphasis>. Many transformations are effectively implemented in
<emphasis role="strong">modules_k/pv/pv_trans.{c,h}</emphasis>.
</para>
<section id="c12naming_format">
<title>Naming Format</title>
<para>
The transformations are given in between the pharantesis around the parenthesis of a pseudo-variable.
The transformation name and parameters are enclosed in between curly brackets
<emphasis role="strong">{ }</emphasis>. The grammar for a transformation specifier:
</para>
<programlisting format="linespecific">
...
'{' classname '.' innername ( ',' parameter )* '}'
...
</programlisting>
<para>
The tokens are:
</para>
<itemizedlist>
<listitem>
<para>
classname - string identifying the class of transformation. For example:
</para>
<itemizedlist>
<listitem>
<para>
's' - string transformations
</para>
</listitem>
<listitem>
<para>
'uri' - URI transformations
</para>
</listitem>
<listitem>
<para>
'param' - parameter transformations
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
innername - string identifying the operation within the class of transformations
</para>
</listitem>
<listitem>
<para>
parameter - the parameter to the transformation. There can be transformation with no
parameters, one or more parameters.
</para>
</listitem>
</itemizedlist>
<para>
Example of existing transformations:
</para>
<programlisting format="linespecific">
...
{s.substr,1,2} - return the string with second and the third characters (substring of length 2 from the
second character)
{uri.user} - return the user part of the SIP URI stored in the pseudo-variable on which this transformation
is applied
...
</programlisting>
</section>
<section id="c12data_structures">
<title>Data Structures</title>
<para>
Internally, to the classname of a transformation it is associated type, an integer number, and to
the innername a subtype, also an integer number. Constants and definitions are in file
<emphasis role="strong">transformations.h</emphasis>
</para>
<programlisting format="linespecific">
...
typedef struct _tr_param {
int type; /* type of the parameter value */
union {
int n; /* the integer value of the parameter */
str s; /* the string value of the parameter */
void *data; /* pseudo-variable spec of the parameter */
} v;
struct _tr_param *next; /* link to next parameter */
} tr_param_t, *tr_param_p;
typedef int (*tr_func_t) (struct sip_msg *, tr_param_t*, int, pv_value_t*);
typedef struct _trans {
str name; /* full name of the transformation */
int type; /* the id of the transformation class */
int subtype; /* the id of the transformation inner name */
tr_func_t trf; /* the function to be executed when applying the transformation */
tr_param_t *params; /* the parameters for this transformation */
struct _trans *next; /* link to next transformation to be applied to same pseudo-variable */
} trans_t, *trans_p;
...
</programlisting>
<para>
The parameters of the function to be executed for a transformation:
</para>
<itemizedlist>
<listitem>
<para>
msg - the SIP message currently processed
</para>
</listitem>
<listitem>
<para>
param - the list with the parameters of the transformation
</para>
</listitem>
<listitem>
<para>
subtype - the subtype of the transformation
</para>
</listitem>
<listitem>
<para>
value - pointer to the value (pv_value_t) to apply transformation on it and store the result
</para>
</listitem>
</itemizedlist>
<para>
There is one function for each transformation class, the exact operation to be applied is given
via subtype. The structure <emphasis role="strong">trans_t</emphasis> is what stands behind each
transformation occurrence.
</para>
</section>
<section id="c12adding_transformation">
<title>Adding a Transformation</title>
<para>
The transformation framework keeps for each transformation class a function to parse the innername
and the parameters, plus a function to execute when the transformation need to be applied. To add
new transformations, you have to implement the two functions.
</para>
<para>
Exemplifying with transformation <emphasis role="strong">s.len</emphasis> - it returns the length
of the string value of a pseudo-variable. The type <emphasis role="strong">TR_STRING</emphasis>
and subtype <emphasis role="strong">TR_S_LEN</emphasis> are added in file
<emphasis role="strong">modules_k/pv/pv_trans.h</emphasis> - these are internal IDs used for
runtime optimizations.
</para>
<para>
The function <emphasis role="strong">tr_parse_string()</emphasis> in file
<emphasis role="strong">modules_k/pv/pv_trans.c</emphasis> is implementing the parser of the class
<emphasis role="strong">s</emphasis>. In this function, if the inner name
is <emphasis role="strong">len</emphasis> it sets the subtype accordingly.
</para>
<programlisting format="linespecific">
...
if(name.len==3 && strncasecmp(name.s, "len", 3)==0)
{
t->subtype = TR_S_LEN;
return p;
}
...
</programlisting>
<para>
The transformation parser is now extended. Next is the interpreter, the function
<emphasis role="strong">tr_eval_str(...)</emphasis> - the evaluation function will be
associated to string transformation by the parser function
<emphasis role="strong">tr_parse_string()</emphasis>.
</para>
<programlisting format="linespecific">
...
switch(subtype)
{
case TR_S_LEN:
if(!(val->flags&PV_VAL_STR))
val->rs.s = int2str(val->ri, &val->rs.len);
val->flags = PV_TYPE_INT|PV_VAL_INT|PV_VAL_STR;
val->ri = val->rs.len;
val->rs.s = int2str(val->ri, &val->rs.len);
break;
...
</programlisting>
<para>
The content of the pv_value_t variable is replaced with the length of the string representation
of its initial value. An example of usage is shown next - get the length of request URI:
</para>
<programlisting format="linespecific">
...
$var(x) = $(ru{s.len});
...
</programlisting>
<para>
To make the transformations available to the core API, you have to register them. You can do it
via <emphasis role="strong">mod_register(...)</emphasis> function. Note that this function is
executed when the module is loaded, making possible to use the transformation in module
parameters and configuration file operations. See
<emphasis role="strong">modules_k/pv/pv.c</emphasis>:
</para>
<programlisting format="linespecific">
...
static tr_export_t mod_trans[] = {
{ {"s", sizeof("s")-1}, /* string class */
tr_parse_string },
{ {"nameaddr", sizeof("nameaddr")-1}, /* nameaddr class */
tr_parse_nameaddr },
{ {"uri", sizeof("uri")-1}, /* uri class */
tr_parse_uri },
{ {"param", sizeof("param")-1}, /* param class */
tr_parse_paramlist },
{ {"tobody", sizeof("tobody")-1}, /* param class */
tr_parse_tobody },
{ { 0, 0 }, 0 }
};
...
int mod_register(char *path, int *dlflags, void *p1, void *p2)
{
return register_trans_mod(path, mod_trans);
}
...
</programlisting>
</section>
</chapter>