forked from asipto/kamailio-devel-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
c16moduledev.xml
1543 lines (1483 loc) · 47 KB
/
c16moduledev.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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<chapter id="c16moduledev">
<title>Module Development</title>
<para>
The easiest way to write extensions for &kamailio; is to extend existing modules or create new ones. Most of the features
available in the configuration file are exported via module functions.
</para>
<para>
&kamailio; modules in a pretty simple concept, are objects that export a set of parameters to control the
internals and a set of functions that can be used in the configuration file. In fact, they are shared library files.
</para>
<para>
There are no modules to be automatically loaded, the configuration file must explicitly include the directive to
load a module.
</para>
<programlisting format="linespecific">
...
loadmodule "/path/to/module.so"
...
</programlisting>
<para>
Each module has to export a structure <emphasis role="strong">struct module_exports</emphasis> with the name
<emphasis role="strong">exports</emphasis>.
</para>
<section id="c16t_module_exports">
<title>module_exports type</title>
<para>
The main structure that has to be exported by a module. It is defined in file
<emphasis role="strong">sr_module.h</emphasis>.
</para>
<example id="c16ex_module_exports">
<title>module_exports definition</title>
<programlisting format="linespecific">
...
struct module_exports{
char* name; /* null terminated module name */
unsigned int dlflags; /* flags for dlopen */
cmd_export_t* cmds; /* null terminated array of the exported
commands */
param_export_t* params; /* null terminated array of the exported
module parameters */
stat_export_t* stats; /* null terminated array of the exported
module statistics */
mi_export_t* mi_cmds; /* null terminated array of the exported
MI functions */
pv_export_t* items; /* null terminated array of the exported
module items (pseudo-variables) */
proc_export_t* procs; /* null terminated array of the additional
processes reqired by the module */
init_function init_f; /* Initialization function */
response_function response_f; /* function used for responses,
returns yes or no; can be null */
destroy_function destroy_f; /* function called when the module should
be "destroyed", e.g: on kamailio exit */
child_init_function init_child_f;/* function called by all processes
after the fork */
};
...
</programlisting>
</example>
<para>
The comments in the definition are explanatory, each internal structure and data type is detailed in the next
sections.
</para>
<para>
Starting with version 3.0, there are two module interfaces: one specific to Kamailio flavour and the other
one specific for SER flavour. A third one will merge the two in the near future. At this moment, each
module has to specify in the Makefile what kind of interface implements. In this chapter, the focus is on
writing modules implementing Kamailio specific module interface.
</para>
</section>
<section id="c16t_cmd_export_t">
<title>cmd_export_t type</title>
<para>
The structure corresponds to a function exported by modules
</para>
<programlisting format="linespecific">
...
struct cmd_export_ {
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 */
free_fixup_function
free_fixup; /* pointer to the function called to free the
"fixed" parameters */
int flags; /* Function flags */
};
typedef struct cmd_export_ cmd_export_t;
...
</programlisting>
<para>
Flags can be a bit mask of:
</para>
<itemizedlist>
<listitem>
<para>
REQUEST_ROUTE - the function can be used in request route blocks
</para>
</listitem>
<listitem>
<para>
FAILURE_ROUTE - the function can be used in failure_route blocks
</para>
</listitem>
<listitem>
<para>
ONREPLY_ROUTE - the function can be used in onreply_route blocks
</para>
</listitem>
<listitem>
<para>
BRANCH_ROUTE - the function can be used in branch_route blocks
</para>
</listitem>
<listitem>
<para>
ONSEND_ROUTE - the function can be used in onsend_route block
</para>
</listitem>
<listitem>
<para>
ANY_ROUTE - the function can be used in any route block
</para>
</listitem>
</itemizedlist>
</section>
<section id="c16t_param_export_t">
<title>param_export_t type</title>
<para>
The structure specifies a parameter exported by a module.
</para>
<programlisting format="linespecific">
...
struct param_export_ {
char* name; /* null terminated param. name */
modparam_t type; /* param. type */
void* param_pointer; /* pointer to the param. memory location or to function to set the parameter */
};
typedef struct param_export_ param_export_t;
...
</programlisting>
<para>
The type can be:
</para>
<itemizedlist>
<listitem>
<para>
STR_PARAM - parameter takes a string value
</para>
</listitem>
<listitem>
<para>
INT_PARAM - parameter takes an integer value
</para>
</listitem>
<listitem>
<para>
USE_FUNC_PARAM - this must be used in combination with one from the above. Means that internally there is
a function called every time the parameter is set, instead of setting the value to a variable.
</para>
</listitem>
</itemizedlist>
<para>
When using <emphasis role="strong">USE_FUNC_PARAM</emphasis> flag, the <emphasis role="strong">param_pointer</emphasis>
must be set to a function with the following type:
</para>
<programlisting format="linespecific">
...
typedef int (*param_func_t)( modparam_t type, void* val);
...
</programlisting>
<para>
Parameters are:
</para>
<itemizedlist>
<listitem>
<para>
type - the type of value set to the parameter in the config file
</para>
</listitem>
<listitem>
<para>
val - pointer to the value set in the configuration file
</para>
</listitem>
</itemizedlist>
<para>
The function has to return <emphasis role="strong">0</emphasis> in case of success.
</para>
</section>
<section id="c16_proc_export_t">
<title>proc_export_t type</title>
<para>
This field is no longer active, it is kept for no-error at compilation time during
a transition period and will be removed in the future. To create new application
processes, you have to use a two steps mechanism that ensures inheriting proper
TCP/TLS handling.
</para>
<para>
First you have to declare in mod_init() how many processes you want to start, the
fork new processes in init_child() for RANK_PROC_MAIN:
</para>
<programlisting format="linespecific">
...
<![CDATA[
static int mod_init(void)
{
...
/* add space for one extra process */
register_procs(1);
...
}
...
static int child_init(int rank)
{
int pid;
...
if (rank==PROC_MAIN) {
pid=fork_process(PROC_NOCHLDINIT, "MY PROC DESCRIPTION", 1);
if (pid<0)
return -1; /* error */
if(pid==0){
/* child */
/* initialize the config framework */
if (cfg_child_init())
return -1;
my_process_main_function(...);
}
}
...
return 0;
}
]]>
...
</programlisting>
<para>
register_procs(no) takes as parameter the number of processes to be created.
fork_process(...) takes as parameters: flag specifying wheter to execute
child_init() functions for the new process; string with description of
the process; flag specifying whether to create internal unix sockets or not
for the new process (needed for TCP/TLS communication, use 1 to be safe always).
</para>
<para>
Typical module implementations for such functionality are the MI transports module. They require a special process
to listen to the MI transport layer.
</para>
</section>
<section id="c16t_stat_export_t">
<title>stat_export_t type</title>
<para>
The structure allow to export statistics variables from your module.
</para>
<programlisting format="linespecific">
...
typedef struct stat_export_ {
char* name; /* null terminated statistic name */
int flags; /* flags */
stat_var** stat_pointer; /* pointer to the variable's mem location *
* NOTE - it's in shm mem */
} stat_export_t;
...
</programlisting>
<para>
This field is currently in passive mode inside module_exports structure. You have
to explicitely register the statistics inside mod_init() via register_module_stats().
For example in <emphasis role="strong">modules_k/msilo</emphasis>:
</para>
<programlisting format="linespecific">
...
<![CDATA[
stat_export_t msilo_stats[] = {
{"stored_messages" , 0, &ms_stored_msgs },
{"dumped_messages" , 0, &ms_dumped_msgs },
{"failed_messages" , 0, &ms_failed_msgs },
{"dumped_reminders" , 0, &ms_dumped_rmds },
{"failed_reminders" , 0, &ms_failed_rmds },
{0,0,0}
};
...
static int mod_init(void)
{
...
/* register statistics */
if (register_module_stats( exports.name, msilo_stats)!=0 ) {
LM_ERR("failed to register core statistics\n");
return -1;
}
...
}
...
</programlisting>
<para>
For more see the chapter <emphasis role="strong">Statistics</emphasis>.
</para>
</section>
<section id="c16t_mi_export_t">
<title>mi_export_t type</title>
<para>
The structure to export MI commands. For more see the chapter <emphasis role="strong">Management Interface</emphasis>.
</para>
<programlisting format="linespecific">
...
typedef struct mi_export_ {
char *name; /* name of MI command */
mi_cmd_f *cmd; /* function to be executed for the MI command */
unsigned int flags; /* flags associated to the MI command */
void *param; /* parameter to be given to the MI command */
mi_child_init_f *init_f; /* function to be executed at MI process initialization in order to
* have function 'cmd' working properly */
}mi_export_t;
]]>
...
</programlisting>
</section>
<section id="c16t_pv_export_t">
<title>pv_export_t</title>
<para>
The structure to export pseudo-variables from module. See the chapter
<emphasis role="strong">Pseudo Variables</emphasis> for detailed description.
</para>
<programlisting format="linespecific">
...
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;
...
</programlisting>
<para>
An example of module that exports pseudo-variables is
<emphasis role="strong">modules/mqueue</emphasis>:
</para>
<programlisting format="linespecific">
...
static pv_export_t mod_pvs[] = {
{ {"mqk", sizeof("mqk")-1}, PVT_OTHER, pv_get_mqk, 0,
pv_parse_mqk_name, 0, 0, 0 },
{ {"mqv", sizeof("mqv")-1}, PVT_OTHER, pv_get_mqv, 0,
pv_parse_mqv_name, 0, 0, 0 },
{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
};
...
truct module_exports exports = {
"mqueue",
DEFAULT_DLFLAGS, /* dlopen flags */
cmds,
params,
0,
0, /* exported MI functions */
mod_pvs, /* exported pseudo-variables */
0, /* extra processes */
mod_init, /* module initialization function */
0, /* response function */
mod_destroy, /* destroy function */
0 /* per child init function */
};
...
</programlisting>
</section>
<section id="c16t_functions_types">
<title>Functions Types</title>
<para>
These are the types of functions used in the structure <emphasis role="strong">module_exports</emphasis>.
</para>
<programlisting format="linespecific">
...
typedef int (*cmd_function)(struct sip_msg*, char*, char*, char*, char*, char*, char*);
typedef int (*fixup_function)(void** param, int param_no);
typedef int (*free_fixup_function)(void** param, int param_no);
typedef int (*response_function)(struct sip_msg*);
typedef void (*destroy_function)();
typedef int (*init_function)(void);
typedef int (*child_init_function)(int rank);
...
</programlisting>
<para>
Description:
</para>
<itemizedlist>
<listitem>
<para>
cmd_function - is the type for functions implementing the commands exported to configuration file
</para>
</listitem>
<listitem>
<para>
fixup_function - is the type for function to be used to pre-compile the parameters at startup
</para>
</listitem>
<listitem>
<para>
free_fixup_function - is the type for function to be used to free the structure resulted after pre-compile
processing
</para>
</listitem>
<listitem>
<para>
response_function - is the type for the functions to be register to automatically be called when a SIP
reply is received by &kamailio;
</para>
</listitem>
<listitem>
<para>
destroy_function - is the type for the function to be executed at shut down time, to clean up the resources
used during run time (e.g., shared memory, locks, connections to database)
</para>
</listitem>
<listitem>
<para>
init_function - is the type for the function to be executed at start up, before forking children processes
</para>
</listitem>
<listitem>
<para>
child_init_function - is the type for the function to be executed for each children process, immediately after
forking
</para>
</listitem>
</itemizedlist>
</section>
<section id="c16cmd_function">
<title>Command Functions</title>
<para>
These are the functions implemented by the module that can be invoked from the configuration file. It has a strict
prototype. First parameter is the pointer to structure with the current processed SIP message. Next are
<emphasis role="strong">char*</emphasis>. Most existing command functions have up to two
<emphasis role="strong">char*</emphasis> parameters, recent extensions allow up to six such parameters.
</para>
<para>
It means that in the configuration file you can give only <emphasis role="strong">char*</emphasis> values as
parameter. &kamailio; provides the mechanisms to convert the values to something more meaningful for the module,
during &kamailio; start up, via <emphasis role="strong">fixup functions</emphasis>.
</para>
<para>
When calling from the configuration file, the structure <emphasis role="strong">sip_msg</emphasis> is not given
as parameter, it is added by the config interpreter when calling the C function. The name of the function available
in the configuration file may be different that the name of the C function. There can be different C functions behind
the same config file function, when the number of the parameters is different.
</para>
<section id="c16return_values">
<title>Return Values</title>
<para>
Returning values from the command functions have a special meaning in the configuration file. The command functions
return an integer value, and the config file interpreter use it as follows:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis role="strong">if <0</emphasis> - evaluation of the return code is FALSE
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">if 0</emphasis> - the interpreter stop executing the configuration file
</para>
</listitem>
<listitem>
<para>
<emphasis role="strong">if >0</emphasis> - evaluation of the return code is TRUE
</para>
</listitem>
</itemizedlist>
</section>
<section id="c16fixup_functions">
<title>Fixup Functions</title>
<para>
As the parameters of the functions exported by modules to configuration file are strings, converting the parameters
to internal structures every time a module function is executed is not optimal. Most of the functions do not
need the parameters as a string, but as integer, pseudo-variable names or pseudo-variables values, or even more
complex structures.
</para>
<para>
Here are the fixup functions. These functions convert from plain null-terminated strings to what the developer
needs. Such a function gets a pointer to the initial value and the index of the parameter for that function. Inside
it the value can processed and replaced with a new structure.
</para>
<para>
Next is a fixup function that converts the string value given in configuration file to an unsigned integer.
</para>
<programlisting format="linespecific">
...
<![CDATA[
int fixup_uint(void** param)
{
unsigned int ui;
str s;
s.s = (char*)*param;
s.len = strlen(s.s);
if(str2int(&s, &ui)==0)
{
pkg_free(*param);
*param=(void *)(unsigned long)ui;
return 0;
}
LM_ERR("bad number <%s>\n", (char *)(*param));
return E_CFG;
}
/**
* fixup for functions that get one parameter
* - first parameter is converted to unsigned int
*/
int fixup_uint_null(void** param, int param_no)
{
if(param_no != 1)
{
LM_ERR("invalid parameter number %d\n", param_no);
return E_UNSPEC;
}
return fixup_uint(param);
}
]]>
...
</programlisting>
<para>
<emphasis role="strong">fixup_uint(...)</emphasis> is a helper function,
<emphasis role="strong">fixup_uint_null(...)</emphasis> is a fixup function that can be used for config
function that get one <emphasis role="strong">char*</emphasis> parameter that need to be interpreted
as unsigned integer.
</para>
<para>
The files <emphasis role="strong">mod_fix.{c,h}</emphasis> implement a set of common fixup functions you
can. Check that files before implementing a new fixup function.
</para>
<para>
Recent work is focusing to add free fixup functions, that will help to clean up properly at shut down and
use exported functions dynamically at run time from linked applications.
</para>
</section>
</section>
<section id="c16_devel_new_module">
<title>Developing a new module</title>
<para>
Here we show the steps to develop new modules, exemplifying with code from different modules.
</para>
<para>
Prior starting writing code, check with developers whether that functionality is already implemented. Also try to
identify whether the extension fits better in an existing module or needs to be created a new one.
</para>
<section id="c16naming">
<title>Naming the module</title>
<para>
The first decision to be taken. It must be suggestive for the functionality. There are some rules to be
followed when implementing certain modules.
</para>
<itemizedlist>
<listitem>
<para>
when writing a DB driver module, the module name should start with <emphasis role="strong">db_</emphasis>.
</para>
</listitem>
<listitem>
<para>
when writing a MI transport, the module name should start with <emphasis role="strong">mi_</emphasis>
</para>
</listitem>
<listitem>
<para>
when writing a Presence Server extension, the name should start with
<emphasis role="strong">presence_</emphasis>
</para>
</listitem>
<listitem>
<para>
when writing a PUA extension, the name should start with <emphasis role="strong">pua_</emphasis>
</para>
</listitem>
</itemizedlist>
<para>
The rules are enforced for coherence in grouping related functionalities.
</para>
<para>
Create the directory for your new module.
</para>
<programlisting format="linespecific">
...
mkdir modules/my_new_module
...
</programlisting>
</section>
<section id="c16makefile">
<title>Module Makefile</title>
<para>
Source code for a module has to be placed in a directory inside subfolders: modules, modules_k or modules_s.
In each module directory you have to create a Makefile that specify the dependencies of the module (e.g.,
compile flags and internal/external linking libraries) as well as module interface type.
</para>
<para>
For example, <emphasis role="strong">modules_k/regex</emphasis> implements Kamailio module
interface and depends on external libpcre library and internal kmi library. Its Makefile
looks like:
</para>
<programlisting format="linespecific">
...
include ../../Makefile.defs
auto_gen=
NAME=regex.so
BUILDER = $(shell which pcre-config)
ifeq ($(BUILDER),)
PCREDEFS=-I$(LOCALBASE)/include -I/usr/local/include -I/opt/include \
-I/usr/sfw/include
PCRELIBS=-L$(LOCALBASE)/lib -L/usr/local/lib -L/usr/sfw/lib \
-L/opt/lib -lpcre
else
PCREDEFS = $(shell pcre-config --cflags)
PCRELIBS = $(shell pcre-config --libs)
endif
DEFS+=$(PCREDEFS)
LIBS=$(PCRELIBS)
DEFS+=-DOPENSER_MOD_INTERFACE
SERLIBPATH=../../lib
SER_LIBS+=$(SERLIBPATH)/kmi/kmi
include ../../Makefile.modules
...
</programlisting>
<para>The NAME is specifying the name of shared object file for module. Follows a section
where it tries to discover the location of external shared library libpcre and its
compile time flags. These are added to Makefile variables DEFS and LIBS. To the DEFS
variable has to be added also the type of interface - for &kamailio; this is
<emphasis role="strong">-DOPENSER_MOD_INTERFACE</emphasis>. For SER module interface
it is <emphasis role="strong">-DSER_MOD_INTERFACE</emphasis>.
</para>
<para>
The internal library dependencies are provided via SER_LIBS variable, as a space separated
list of the paths to libraries. In this case it is a dependency on library kmi, located
at ../../lib/kmi/.
</para>
<para>
First and last lines include common Makefiles needed to build the core and modules - they
have to be preserved as they are in this example.
</para>
<para>
A very simple and pretty standard template to start building you module Makefile:
</para>
<programlisting format="linespecific">
...
include ../../Makefile.defs
auto_gen=
NAME=my_new_module.so
LIBS=
DEFS+=-DOPENSER_MOD_INTERFACE
include ../../Makefile.modules
...
</programlisting>
</section>
<section id="c17mainfile">
<title>Main File</title>
<para>
The main file of the modules is where you place the structure <emphasis role="strong">module_exports</emphasis>.
The common naming formats are:
</para>
<itemizedlist>
<listitem>
<para>
my_new_module.c
</para>
</listitem>
<listitem>
<para>
my_new_module_mod.c
</para>
</listitem>
</itemizedlist>
<para>
In this file you must include the macro <emphasis role="strong">MODULE_VERSION</emphasis> to allow &kamailio;
to detect whether core and the module are same version and compiled with same flags. You just simply add next line
after all header files includes.
</para>
<programlisting format="linespecific">
...
MODULE_VERSION
...
</programlisting>
</section>
<section id="c16_add_parameter">
<title>Add Module Parameter</title>
<para>
In the configuration file, can be set integer or string values for a module parameter. The type is specified
in the <emphasis role="strong">param_export_t</emphasis> structure.
</para>
<para>
We exemplify the parameters exported by the modules <emphasis role="strong">modules_k/cfgutils</emphasis>
and <emphasis role="strong">modules_k/pv</emphasis> - showing one integer parameter, one string parameter
and another string parameter that is set via a function.
</para>
<para>
For the parameters stored directly in a variable, you have to declare C variables of type
<emphasis role="strong">int</emphasis> or <emphasis role="strong">char*</emphasis>.
</para>
<programlisting format="linespecific">
...
static int initial = 10;
static char* hash_file = NULL;
static param_export_t params[]={
...
{"initial_probability", INT_PARAM, &initial},
{"hash_file", STR_PARAM, &hash_file },
...
{"shvset", STR_PARAM|USE_FUNC_PARAM, (void*)param_set_shvar },
...
{0,0,0}
};
...
</programlisting>
<para>
In the config, one can set many times the value for a parameter. In case of parameters stored in a variable, the
last one is taken. For those that use a function, it is up to the implementation what to do with each value.
Actually here is the real benefit of using a function.
</para>
<para>
The <emphasis role="strong">param_set_shvar(...)</emphasis> function sets the initial value for a shared config
file variable <emphasis role="strong">$shv(name)</emphasis>. The function is implemented in the file
<emphasis role="strong">modules_k/pv/pv_shv.c</emphasis>. Check the readme of the module to see the format
of the parameter value - it includes the name of the shared variable as well as the value. So the function
parses the value given from the configuration file, splits in name and value and store in a local structure.
</para>
<programlisting format="linespecific">
...
<![CDATA[
int param_set_xvar( modparam_t type, void* val, int mode)
{
str s;
char *p;
int_str isv;
int flags;
int ival;
script_var_t *pkv;
sh_var_t *shv;
if(!shm_initialized()!=0)
{
LM_ERR("shm not initialized - cannot set value for PVs\n");
goto error;
}
s.s = (char*)val;
if(s.s == NULL || s.s[0] == '\0')
goto error;
p = s.s;
while(*p && *p!='=') p++;
if(*p!='=')
goto error;
s.len = p - s.s;
if(s.len == 0)
goto error;
p++;
flags = 0;
if(*p!='s' && *p!='S' && *p!='i' && *p!='I')
goto error;
if(*p=='s' || *p=='S')
flags = VAR_VAL_STR;
p++;
if(*p!=':')
goto error;
p++;
isv.s.s = p;
isv.s.len = strlen(p);
if(flags != VAR_VAL_STR) {
if(str2sint(&isv.s, &ival)<0)
goto error;
isv.n = ival;
}
if(mode==0) {
pkv = add_var(&s);
if(pkv==NULL)
goto error;
if(set_var_value(pkv, &isv, flags)==NULL)
goto error;
} else {
shv = add_shvar(&s);
if(shv==NULL)
goto error;
if(set_shvar_value(shv, &isv, flags)==NULL)
goto error;
}
return 0;
error:
LM_ERR("unable to set shv parame [%s]\n", s.s);
return -1;
}
int param_set_shvar( modparam_t type, void* val)
{
return param_set_xvar(type, val, 1);
}
]]>
...
</programlisting>
<para>
So, actually, setting the parameter <emphasis role="strong">setshv</emphasis> for module
<emphasis role="strong">pv</emphasis> produces a set of operations behind.
</para>
<programlisting format="linespecific">
...
modparam("pv", "shvset", "debug=i:1")
...
</programlisting>
<para>
By setting the parameter as above results in a variable <emphasis role="strong">$shv(debug)</emphasis> initialized
to <emphasis role="strong">1</emphasis>.
</para>
</section>
<section id="c16_mod_init">
<title>Module Init Function</title>
<para>
The function is executed after setting the module parameters, config file is parsed completely, shared memory and
locking system are initialized.
</para>
<para>
The main purpose of this function is to check the sanity of the module parameter, load data from storage systems,
initialize the structured to be used at runtime. Here is the example from modules_k/cfgutils module:
</para>
<programlisting format="linespecific">
...
<![CDATA[
static int mod_init(void)
{
if(register_mi_mod(exports.name, mi_cmds)!=0)
{
LM_ERR("failed to register MI commands\n");
return -1;
}
if (!hash_file) {
LM_INFO("no hash_file given, disable hash functionality\n");
} else {
if (MD5File(config_hash, hash_file) != 0) {
LM_ERR("could not hash the config file");
return -1;
}
LM_DBG("config file hash is %.*s", MD5_LEN, config_hash);
}
if (initial_prob > 100) {
LM_ERR("invalid probability <%d>\n", initial_prob);
return -1;
}
LM_DBG("initial probability %d percent\n", initial_prob);
probability=(int *) shm_malloc(sizeof(int));
if (!probability) {
LM_ERR("no shmem available\n");
return -1;
}
*probability = initial_prob;
gflags=(unsigned int *) shm_malloc(sizeof(unsigned int));
if (!gflags) {
LM_ERR(" no shmem available\n");
return -1;
}
*gflags=initial_gflags;
if(_cfg_lock_size>0 && _cfg_lock_size<=10)
{
_cfg_lock_size = 1<<_cfg_lock_size;
_cfg_lock_set = lock_set_alloc(_cfg_lock_size);
if(_cfg_lock_set==NULL || lock_set_init(_cfg_lock_set)==NULL)
{
LM_ERR("cannot initiate lock set\n");
return -1;
}
}
return 0;
}
]]>
...
</programlisting>
<para>
First in the function is registering MI commands and then is the handling of the config hashing.
If the appropriate parameter is not set, it is initialized to the config file used by &kamailio;.
Then is computed the hash value that will be used for
comparison, later at runtime. Next is checking the probability parameter and create the variable in share memory
to store it. At the end it initializes the variables for global flags and lock sets.
</para>
<para>
The module init function must return <emphasis role="strong">0</emphasis> in case of success.
</para>
</section>
<section id="c16_child_init">
<title>Module Child Init Function</title>
<para>
This is the function called just after &kamailio; forks its worker processes. If &kamailio; is set in non-fork
module, the function is called for the main process after calling the module init function.
</para>
<para>
In this function must be added the operations that has to be taken for each worker or special processes only
once during the runtime, at the start up time. Example of such operations are to open the connection to
database, set the intial values for local variables per process.
</para>
<para>
The function gets as parameter the rank of the child process. The rank is a positive number if it is a worker
process and negative for special processes like timer processes or TCP attendant. The defines with these
special ranks are in file <emphasis role="strong">sr_module.h</emphasis>.
</para>
<para>
As an example, we show the <emphasis role="strong">child_init</emphasis> function of the module
<emphasis role="strong">speeddial</emphasis>. The operations there are for opening the connection to database.
</para>
<programlisting format="linespecific">
...
<![CDATA[
static int child_init(int rank)
{
if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
return 0; /* do nothing for the main process */
db_handle = db_funcs.init(&db_url);
if (!db_handle)
{
LM_ERR("failed to connect database\n");
return -1;
}
return 0;
}
]]>
...
</programlisting>
<para>
The child init function must return <emphasis role="strong">0</emphasis> in case of success.
</para>
</section>
<section id="c16_mod_destroy">
<title>Module Destroy Function</title>
<para>
It is the function to be called when &kamailio; is stopped. The main purpose is to clean up the resources created
and used at initialization and/or runtime. For the module <emphasis role="strong">cfgutils</emphasis> means to
free the variable allocated in shared memory for keeping the probability and destroying the global flags
and lock sets.
</para>
<programlisting format="linespecific">
...
static void mod_destroy(void)
{
if (probability)
shm_free(probability);
if (gflags)
shm_free(gflags);
if(_cfg_lock_set!=NULL)
{
lock_set_destroy(_cfg_lock_set);
lock_set_dealloc(_cfg_lock_set);
}
}
...
</programlisting>
</section>
<section id="c16_add_cmd_function">
<title>Add Command Function</title>
<para>
The module <emphasis role="strong">cfgutils</emphasis> exports a functions stop and wait for a period of
time the execution of the configuration file. It is an interface the the standard C function
<emphasis role="strong">sleep(...)</emphasis>. Takes as parameter the number of the seconds to wait.
</para>
<para>
As the parameter is given as string, but it is actually an integer value, a fixup function is used. It is
in the list of the fixup functions exported by <emphasis role="strong">mod_fix.h</emphasis>. The fixup
function <emphasis role="strong">fixup_uint_null(...)</emphasis> is shown few sections above.
</para>
<programlisting format="linespecific">
...
static cmd_export_t cmds[]={
...
{"sleep", (cmd_function)m_sleep, 1, fixup_uint_null, 0,