Coverage Report

Created: 2026-09-03 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/sr_module.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 * History:
21
 * --------
22
 *  2003-03-10  switched to new module_exports format: updated find_export,
23
 *               find_export_param, find_module (andrei)
24
 *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
25
 *  2003-03-19  Support for flags in find_export (janakj)
26
 *  2003-03-29  cleaning pkg_mallocs introduced (jiri)
27
 *  2003-04-24  module version checking introduced (jiri)
28
 *  2004-09-19  compile flags are checked too (andrei)
29
 *  2006-03-02  added find_cmd_export_t(), killed find_exportp() and
30
 *              find_module() (bogdan)
31
 *  2006-11-28  added module_loaded() (Jeffrey Magder - SOMA Networks)
32
 */
33
34
/*!
35
 * \file
36
 * \brief modules/plug-in structures declarations
37
 */
38
39
40
#include "sr_module.h"
41
#include "dprint.h"
42
#include "error.h"
43
#include "globals.h"
44
#include "db/pi_framework.h"
45
#include "mem/mem.h"
46
#include "pt.h"
47
#include "ut.h"
48
#include "daemonize.h"
49
50
#include <strings.h>
51
#include <stdlib.h>
52
#include <string.h>
53
#include <glob.h>
54
55
#include <sys/types.h>
56
#include <sys/stat.h>
57
#include <unistd.h>
58
59
#include "net/api_proto.h"
60
#include "net/proto_udp/proto_udp_handler.h"
61
#include "net/proto_tcp/proto_tcp_handler.h"
62
63
#include "test/unit_tests.h"
64
65
#include "libgen.h"
66
67
struct sr_module* modules=0;
68
int in_tree_mode;
69
70
#ifdef STATIC_EXEC
71
  extern struct module_exports exec_exports;
72
#endif
73
#ifdef STATIC_TM
74
  extern struct module_exports tm_exports;
75
#endif
76
77
#ifdef STATIC_MAXFWD
78
  extern struct module_exports maxfwd_exports;
79
#endif
80
81
#ifdef STATIC_AUTH
82
  extern struct module_exports auth_exports;
83
#endif
84
85
#ifdef STATIC_RR
86
  extern struct module_exports rr_exports;
87
#endif
88
89
#ifdef STATIC_USRLOC
90
  extern struct module_exports usrloc_exports;
91
#endif
92
93
#ifdef STATIC_SL
94
  extern struct module_exports sl_exports;
95
#endif
96
97
0
#define MPATH_LEN 256
98
struct mpath {
99
  char buf[MPATH_LEN + 1];
100
  int len;
101
  struct mpath *next;
102
};
103
static struct mpath *mpaths, *last_mpath;
104
105
static void add_local_mpath(void)
106
0
{
107
0
  static int done;
108
0
  glob_t files;
109
110
0
  if (!in_tree_mode || done)
111
0
    return;
112
0
  done = 1;
113
114
0
  if (glob("./modules/*/*.so", 0, NULL, &files) != 0)
115
0
    return;
116
0
  globfree(&files);
117
118
0
  LM_INFO("using local './modules' directory as module path fallback\n");
119
0
  add_mpath("./modules");
120
0
}
121
122
/* initializes statically built (compiled in) modules*/
123
int register_builtin_modules(void)
124
0
{
125
0
  int ret;
126
127
0
  ret=0;
128
#ifdef STATIC_TM
129
  ret=register_module(&tm_exports,"built-in", 0);
130
  if (ret<0) return ret;
131
#endif
132
133
#ifdef STATIC_EXEC
134
  ret=register_module(&exec_exports,"built-in", 0);
135
  if (ret<0) return ret;
136
#endif
137
138
#ifdef STATIC_MAXFWD
139
  ret=register_module(&maxfwd_exports, "built-in", 0);
140
  if (ret<0) return ret;
141
#endif
142
143
#ifdef STATIC_AUTH
144
  ret=register_module(&auth_exports, "built-in", 0);
145
  if (ret<0) return ret;
146
#endif
147
148
#ifdef STATIC_RR
149
  ret=register_module(&rr_exports, "built-in", 0);
150
  if (ret<0) return ret;
151
#endif
152
153
#ifdef STATIC_USRLOC
154
  ret=register_module(&usrloc_exports, "built-in", 0);
155
  if (ret<0) return ret;
156
#endif
157
158
#ifdef STATIC_SL
159
  ret=register_module(&sl_exports, "built-in", 0);
160
  if (ret<0) return ret;
161
#endif
162
163
0
  return ret;
164
0
}
165
166
/* registers a module,  register_f= module register  functions
167
 * returns <0 on error, 0 on success */
168
int register_module(const struct module_exports* e, char* path, void* handle)
169
0
{
170
0
  int ret;
171
0
  struct sr_module* mod;
172
173
0
  ret=-1;
174
175
  /* add module to the list */
176
0
  if ((mod=pkg_malloc(sizeof(struct sr_module)))==0){
177
0
    LM_ERR("no more pkg memory\n");
178
0
    ret=E_OUT_OF_MEM;
179
0
    goto error;
180
0
  }
181
0
  memset(mod,0, sizeof(struct sr_module));
182
0
  mod->path=path;
183
0
  mod->handle=handle;
184
0
  mod->exports=e;
185
0
  mod->next=modules;
186
0
  modules=mod;
187
188
  /* register module pseudo-variables */
189
0
  if (e->items) {
190
0
    LM_DBG("register_pv: %s\n", e->name);
191
0
    if (register_pvars_mod(e->name, e->items)!=0) {
192
0
      LM_ERR("failed to register pseudo-variables for module %s\n",
193
0
        e->name);
194
0
      pkg_free(mod);
195
0
      return -1;
196
0
    }
197
0
  }
198
199
  /* register module transformations */
200
0
  if (e->trans) {
201
0
    LM_DBG("register_trans: %s\n", e->name);
202
0
    if (register_trans_mod(e->name, e->trans) !=0) {
203
0
      LM_ERR("failed to register transformations for module %s\n",
204
0
        e->name);
205
0
      pkg_free(mod);
206
0
      return -1;
207
0
    }
208
0
  }
209
210
  /* register all module dependencies */
211
0
  if (e->deps) {
212
0
    ret = add_module_dependencies(mod);
213
0
    if (ret != 0) {
214
0
      LM_CRIT("failed to add module dependencies [%d]\n", ret);
215
0
      return ret;
216
0
    }
217
0
  }
218
219
0
  return 0;
220
0
error:
221
0
  return ret;
222
0
}
223
224
225
static inline int version_control(const struct module_exports* exp, char *path)
226
0
{
227
0
  const char *hint = "(try `make clean all modules' and reinstall everything)";
228
0
  const char *scm_nm = "version control system";
229
0
  int len;
230
0
  if ( !exp->ver_info.version ) {
231
0
    LM_CRIT("BUG - version not defined in module <%s>\n", path );
232
0
    return 0;
233
0
  }
234
0
  if ( !exp->ver_info.compile_flags ) {
235
0
    LM_CRIT("BUG - compile flags not defined in module <%s>\n", path );
236
0
    return 0;
237
0
  }
238
0
  if ( !exp->ver_info.scm.type ) {
239
0
    LM_CRIT("BUG - %s type not defined in module <%s> %s\n",
240
0
      scm_nm, path, hint );
241
0
    return 0;
242
0
  }
243
0
  if ( !exp->ver_info.scm.rev ) {
244
0
    LM_CRIT("BUG - %s revision not defined in module <%s> %s\n",
245
0
      scm_nm, path, hint );
246
0
    return 0;
247
0
  }
248
249
0
  if (strcmp(OPENSIPS_FULL_VERSION, exp->ver_info.version)!=0) {
250
0
    LM_CRIT("module version mismatch for %s; core: %s; module: %s\n",
251
0
      exp->name, OPENSIPS_FULL_VERSION, exp->ver_info.version );
252
0
    return 0;
253
0
  }
254
0
  if (strcmp(OPENSIPS_COMPILE_FLAGS, exp->ver_info.compile_flags)!=0) {
255
0
    LM_CRIT("module compile flags mismatch for %s "
256
0
      " \ncore: %s \nmodule: %s\n", exp->name,
257
0
      OPENSIPS_COMPILE_FLAGS, exp->ver_info.compile_flags);
258
0
    return 0;
259
0
  }
260
0
  if (strcmp(core_scm_ver.type, exp->ver_info.scm.type) != 0) {
261
0
    LM_CRIT("module %s type mismatch for %s "
262
0
      " \ncore: %s \nmodule: %s %s\n", scm_nm, exp->name,
263
0
      core_scm_ver.type, exp->ver_info.scm.type, hint);
264
0
    return 0;
265
0
  }
266
0
  if (!in_tree_mode) {
267
0
    len = (strlen(core_scm_ver.rev) < strlen(exp->ver_info.scm.rev))?
268
0
      strlen(core_scm_ver.rev): strlen(exp->ver_info.scm.rev);
269
0
    if (strncmp(core_scm_ver.rev, exp->ver_info.scm.rev, len) != 0) {
270
0
      LM_CRIT("module %s revision mismatch for %s "
271
0
          " \ncore: %s \nmodule: %s %s\n", scm_nm, exp->name,
272
0
          core_scm_ver.rev, exp->ver_info.scm.rev, hint);
273
0
      return 0;
274
0
    }
275
0
  }
276
0
  return 1;
277
0
}
278
279
280
281
/* returns 0 on success , <0 on error */
282
int sr_load_module(char* path)
283
0
{
284
0
  void* handle;
285
0
  unsigned int moddlflags;
286
0
  char* error;
287
0
  const struct module_exports* exp;
288
0
  struct sr_module* t;
289
290
  /* load module */
291
0
  handle=dlopen(path, OPENSIPS_DLFLAGS); /* resolve all symbols now */
292
0
  if (handle==0){
293
0
    LM_ERR("could not open module <%s>: %s\n", path, dlerror() );
294
0
    goto error;
295
0
  }
296
297
  /* check for duplicates */
298
0
  for(t=modules;t; t=t->next){
299
0
    if (t->handle==handle){
300
0
      LM_WARN("attempting to load the same module twice (%s)\n", path);
301
0
      goto skip;
302
0
    }
303
0
  }
304
305
  /* import module interface */
306
0
  exp = (const struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
307
0
  if ( (error =(char*)dlerror())!=0 ){
308
0
    LM_ERR("load_module: %s\n", error);
309
0
    goto error1;
310
0
  }
311
  /* version control */
312
0
  if (!version_control(exp, path)) {
313
0
    exit(1);
314
0
  }
315
0
  if(exp->dlflags!=DEFAULT_DLFLAGS && exp->dlflags!=OPENSIPS_DLFLAGS) {
316
0
    moddlflags = exp->dlflags;
317
0
    dlclose(handle);
318
0
    LM_DBG("reloading module %s with flags %d\n", path, moddlflags);
319
0
    handle = dlopen(path, moddlflags);
320
0
    if (handle==0){
321
0
      LM_ERR("could not open module <%s>: %s\n", path, dlerror() );
322
0
      goto error;
323
0
    }
324
0
    exp = (const struct module_exports*)dlsym(handle, DLSYM_PREFIX "exports");
325
0
    if ( (error =(char*)dlerror())!=0 ){
326
0
      LM_ERR("failed to load module : %s\n", error);
327
0
      goto error1;
328
0
    }
329
0
  }
330
331
0
  if (exp->load_f && exp->load_f() < 0) {
332
0
    LM_ERR("could not initialize module %s\n", path);
333
0
    goto error1;
334
0
  }
335
336
  /* launch register */
337
0
  if (register_module(exp, path, handle)<0) goto error1;
338
0
  return 0;
339
340
0
error1:
341
0
  dlclose(handle);
342
0
error:
343
0
skip:
344
0
  return -1;
345
0
}
346
347
/* built-in modules with static exports */
348
struct static_modules {
349
  str name;
350
  struct module_exports *exp;
351
};
352
353
struct static_modules static_modules[] = {
354
  { str_init(PROTO_PREFIX "udp"), &proto_udp_exports },
355
  { str_init(PROTO_PREFIX "tcp"), &proto_tcp_exports },
356
};
357
358
static int load_static_module(char *path)
359
0
{
360
0
  int len = strlen(path);
361
0
  char *end = path + len;
362
0
  struct sr_module* t;
363
0
  unsigned int i;
364
365
  /* eliminate the .so, if found */
366
0
  if (len > 3 && strncmp(end - 3, ".so", 3)==0) {
367
0
    end -= 3;
368
0
    len -= 3;
369
0
  }
370
  /* we check whether the protocol is found within the static_modules */
371
0
  for (i = 0; i < (sizeof(static_modules)/sizeof(static_modules[0])); i++) {
372
0
    if (len >= static_modules[i].name.len &&
373
        /* the path ends in the module's name */
374
0
        memcmp(end - static_modules[i].name.len,
375
0
          static_modules[i].name.s, static_modules[i].name.len) == 0 &&
376
        /* check if the previous char is '/' or nothing */
377
0
        (len == static_modules[i].name.len || (*(end-len-1) == '/'))) {
378
379
      /* yey, found the module - check if it was loaded twice */
380
0
      for(t=modules;t; t=t->next){
381
0
        if (t->handle==static_modules[i].exp){
382
0
          LM_WARN("attempting to load the same module twice (%s)\n", path);
383
0
          return 0;
384
0
        }
385
0
      }
386
387
      /* version control */
388
0
      if (!version_control(static_modules[i].exp, path)) {
389
0
        exit(0);
390
0
      }
391
392
      /* launch register */
393
0
      if (register_module(static_modules[i].exp, path, static_modules[i].exp)<0)
394
0
        return -1;
395
0
      return 0;
396
0
    }
397
0
  }
398
399
0
  return -1;
400
0
}
401
402
void add_mpath(const char *new_mpath)
403
0
{
404
0
  struct mpath *nmpath;
405
0
  int len = strlen(new_mpath);
406
0
  if (len >= MPATH_LEN) {
407
0
    LM_ERR("mpath %s too long!\n", new_mpath);
408
0
    return;
409
0
  }
410
0
  nmpath = pkg_malloc(sizeof *nmpath);
411
0
  if (!nmpath) {
412
0
    LM_ERR("could not allocate space for %s mpath!\n", new_mpath);
413
0
    return;
414
0
  }
415
0
  memset(nmpath, 0, sizeof *nmpath);
416
  /* link it in the list */
417
0
  if (last_mpath)
418
0
    last_mpath->next = nmpath;
419
0
  else
420
0
    mpaths = nmpath;
421
0
  last_mpath = nmpath;
422
0
  memcpy(nmpath->buf, new_mpath, len);
423
0
  nmpath->len = len;
424
0
  if (nmpath->len == 0 || nmpath->buf[nmpath->len - 1] != '/') {
425
0
    nmpath->buf[nmpath->len] = '/';
426
0
    nmpath->len++;
427
0
  }
428
0
  nmpath->buf[nmpath->len] = '\0';
429
0
}
430
431
static struct {
432
 char *module;
433
 char *name;
434
 unsigned int flags;
435
} module_warnings[] = {
436
  { "rabbitmq", "'rabbitmq' module has been dropped - please use 'event_rabbitmq' instead!", MOD_WARN_EXIT },
437
  { "event_route", "'event_route' module has been integrated in core file. You no longer need to load the module.", MOD_WARN_SKIP }
438
};
439
440
/* returns 0 on success , <0 on error */
441
int load_module(char* name)
442
0
{
443
0
  int i_tmp, len;
444
0
  struct stat statf;
445
0
  struct mpath *mp;
446
0
  int module_warnings_len;
447
0
  char *base_name;
448
449
0
  base_name = basename(name);
450
0
  len = strlen(base_name);
451
0
  if (strstr(base_name, ".so"))
452
0
    len -= 3;
453
454
0
  module_warnings_len = sizeof(module_warnings) / sizeof(module_warnings[0]);
455
456
0
  for (i_tmp = 0; i_tmp < module_warnings_len; i_tmp++) {
457
0
    if (strncmp(base_name, module_warnings[i_tmp].module, len) == 0) {
458
0
      switch (module_warnings[i_tmp].flags)
459
0
      {
460
0
        case MOD_WARN_EXIT:
461
0
          LM_ERR("%s\n", module_warnings[i_tmp].name);
462
0
          return -1;
463
464
0
        case MOD_WARN_SKIP:
465
0
          LM_WARN("%s\n", module_warnings[i_tmp].name);
466
0
          return 0;
467
468
0
        default:
469
0
          break;
470
0
      }
471
0
    }
472
0
  }
473
474
  /* if this is a static module, load it directly */
475
0
  if (load_static_module(name) == 0)
476
0
    return 0;
477
478
  /* A development tree keeps built modules under ./modules/<name>/ */
479
0
  add_local_mpath();
480
481
0
  if (*name=='/' || mpaths==NULL) {
482
0
    LM_DBG("loading module %s\n", name);
483
0
    if (sr_load_module(name)!=0){
484
0
      LM_ERR("failed to load module\n");
485
0
      return -1;
486
0
    }
487
0
    return 0;
488
0
  }
489
0
  for (mp = mpaths; mp; mp = mp->next) {
490
0
    len = strlen(name);
491
0
    if (len + mp->len >= MPATH_LEN)
492
0
      continue;
493
0
    memcpy(mp->buf + mp->len, name, len);
494
0
    mp->buf[mp->len + len] = '\0';
495
0
    if (stat(mp->buf, &statf) == -1 || S_ISDIR(statf.st_mode)) {
496
0
      i_tmp = strlen(mp->buf);
497
0
      if(strchr(name, '/')==NULL &&
498
0
        strncmp(mp->buf+i_tmp-3, ".so", 3)==0)
499
0
      {
500
0
        if(i_tmp+len<MPATH_LEN)
501
0
        {
502
0
          strcpy(mp->buf+i_tmp-3, "/");
503
0
          strcpy(mp->buf+i_tmp-2, name);
504
0
          if (stat(mp->buf, &statf) == -1) {
505
0
            mp->buf[mp->len]='\0';
506
0
            LM_DBG("module '%s' not found in '%s'\n",
507
0
                name, mp->buf);
508
0
            goto next;
509
0
          }
510
0
        } else {
511
0
          LM_DBG("failed to load module '%s' from '%s' - path too long\n", name, mp->buf);
512
0
          goto next;
513
0
        }
514
0
      } else {
515
0
        goto next;
516
0
      }
517
0
    }
518
0
    LM_DBG("trying module %s\n", mp->buf);
519
0
    if (sr_load_module(mp->buf)!=0) {
520
0
      LM_DBG("failed to load module '%s'\n", mp->buf);
521
0
    } else {
522
0
      mp->buf[mp->len]='\0';
523
0
      return 0;
524
0
    }
525
0
next:
526
0
    mp->buf[mp->len]='\0';
527
0
  }
528
0
  LM_ERR("failed to load module '%s' - not found\n", name);
529
0
  return -1;
530
0
}
531
532
533
534
/* searches the module list and returns pointer to the "name" function or
535
 * 0 if not found
536
 * flags parameter is OR value of all flags that must match
537
 */
538
cmd_function find_export(const char* name, int flags)
539
0
{
540
0
  const cmd_export_t* cmd;
541
542
0
  cmd = find_mod_cmd_export_t(name, flags);
543
0
  if (cmd==0)
544
0
    return 0;
545
546
0
  return cmd->function;
547
0
}
548
549
550
551
/* Searches the module list for the "name" cmd_export_t structure.
552
 */
553
const cmd_export_t* find_mod_cmd_export_t(const char* name, int flags)
554
0
{
555
0
  struct sr_module* t;
556
0
  const cmd_export_t* cmd;
557
558
0
  for(t=modules;t;t=t->next){
559
0
    for(cmd=t->exports->cmds; cmd && cmd->name; cmd++){
560
0
      if((strcmp(name, cmd->name)==0)&&((cmd->flags & flags) == flags)){
561
0
        LM_DBG("found <%s> in module %s [%s]\n",
562
0
            name, t->exports->name, t->path);
563
0
        return cmd;
564
0
      }
565
0
    }
566
0
  }
567
568
0
  LM_DBG("<%s> not found \n", name);
569
0
  return 0;
570
0
}
571
572
573
574
/* Searches the module list for the "name" acmd_export_t structure.
575
 */
576
const acmd_export_t* find_mod_acmd_export_t(const char* name)
577
0
{
578
0
  struct sr_module* t;
579
0
  const acmd_export_t* cmd;
580
581
0
  for(t=modules;t;t=t->next){
582
0
    for(cmd=t->exports->acmds; cmd && cmd->name; cmd++){
583
0
      if((strcmp(name, cmd->name)==0)){
584
0
        LM_DBG("found <%s> in module %s [%s]\n",
585
0
            name, t->exports->name, t->path);
586
0
        return cmd;
587
0
      }
588
0
    }
589
0
  }
590
0
  LM_DBG("async <%s> not found \n", name);
591
0
  return 0;
592
0
}
593
594
/*
595
 * searches the module list and returns pointer to "name" function in module
596
 * "mod" or 0 if not found
597
 * flags parameter is OR value of all flags that must match
598
 */
599
cmd_function find_mod_export(const char* mod, const char* name, int flags)
600
0
{
601
0
  struct sr_module* t;
602
0
  const cmd_export_t* cmd;
603
604
0
  for (t = modules; t; t = t->next) {
605
0
    if (strcmp(t->exports->name, mod) == 0) {
606
0
      for (cmd = t->exports->cmds;  cmd && cmd->name; cmd++) {
607
0
        if ((strcmp(name, cmd->name) == 0) &&
608
0
            ((cmd->flags & flags) == flags)
609
0
           ){
610
0
          LM_DBG("found <%s> in module %s [%s]\n",
611
0
              name, t->exports->name, t->path);
612
0
          return cmd->function;
613
0
        }
614
0
      }
615
0
    }
616
0
  }
617
618
0
  LM_DBG("<%s> in module %s not found\n", name, mod);
619
0
  return 0;
620
0
}
621
622
623
624
void* find_param_export(const char* mod, const char* name, modparam_t type)
625
0
{
626
0
  struct sr_module* t;
627
0
  const param_export_t* param;
628
629
0
  for(t = modules; t; t = t->next) {
630
0
    if (strcmp(mod, t->exports->name) == 0) {
631
0
      for(param=t->exports->params;param && param->name ; param++) {
632
0
        if ((strcmp(name, param->name) == 0) &&
633
0
            (param->type == type)) {
634
0
          LM_DBG("found <%s> in module %s [%s]\n",
635
0
            name, t->exports->name, t->path);
636
0
          return param->param_pointer;
637
0
        }
638
0
      }
639
0
    }
640
0
  }
641
0
  LM_DBG("parameter <%s> or module <%s> not found\n", name, mod);
642
0
  return 0;
643
0
}
644
645
646
static void destroy_module(struct sr_module *m, int skip_others)
647
0
{
648
0
  struct sr_module_dep *dep;
649
650
0
  if (!m)
651
0
    return;
652
653
  /* destroy the modules in script load order using backwards iteration */
654
0
  if (!skip_others)
655
0
    destroy_module(m->next, 0);
656
657
0
  if (m->destroy_done || !m->exports)
658
0
    return;
659
660
  /* make sure certain modules get destroyed before this one */
661
0
  for (dep = m->sr_deps_destroy; dep; dep = dep->next)
662
0
    if (!dep->mod->destroy_done)
663
0
      destroy_module(dep->mod, 1);
664
665
0
  if (m->init_done && m->exports->destroy_f)
666
0
    m->exports->destroy_f();
667
668
0
  m->destroy_done = 1;
669
0
}
670
671
672
void destroy_modules(void)
673
0
{
674
0
  struct sr_module *mod, *aux;
675
676
0
  destroy_module(modules, 0);
677
0
  free_module_dependencies(modules);
678
679
0
  mod = modules;
680
0
  while (mod) {
681
0
    aux = mod;
682
0
    mod = mod->next;
683
0
    pkg_free(aux);
684
0
  }
685
0
}
686
687
688
/* recursive module child initialization; (recursion is used to
689
   process the module linear list in the same order in
690
   which modules are loaded in config file
691
*/
692
693
static int init_mod_child( struct sr_module* m, int rank, char *type,
694
                          int skip_others)
695
0
{
696
0
  struct sr_module_dep *dep;
697
698
0
  if (!m || m->init_child_done)
699
0
    return 0;
700
701
  /* iterate through the list; if error occurs,
702
     propagate it up the stack */
703
0
  if (!skip_others && init_mod_child(m->next, rank, type, 0) != 0)
704
0
    return -1;
705
706
0
  for (dep = m->sr_deps_cinit; dep; dep = dep->next)
707
0
    if (!dep->mod->init_child_done)
708
0
      if (init_mod_child(dep->mod, rank, type, 1) != 0)
709
0
        return -1;
710
711
0
  if (m->init_child_done)
712
0
    return 0;
713
714
0
  if (m->exports && m->exports->init_child_f) {
715
0
    LM_DBG("type=%s, rank=%d, module=%s\n",
716
0
        type, rank, m->exports->name);
717
0
    if (m->exports->init_child_f(rank)<0) {
718
0
      LM_ERR("failed to initializing module %s, rank %d\n",
719
0
        m->exports->name,rank);
720
0
      return -1;
721
0
    }
722
0
  }
723
724
0
  m->init_child_done = 1;
725
0
  return 0;
726
0
}
727
728
729
/*
730
 * per-child initialization
731
 */
732
int init_child(int rank)
733
0
{
734
0
  char* type;
735
0
  int rc;
736
737
0
  type = 0;
738
739
0
  switch(rank) {
740
0
  case PROC_MAIN:     type = "PROC_MAIN";     break;
741
0
  case PROC_TIMER:    type = "PROC_TIMER";    break;
742
0
  case PROC_MODULE:   type = "PROC_MODULE";   break;
743
0
  case PROC_TCP_MAIN: type = "PROC_TCP_MAIN"; break;
744
0
  }
745
746
0
  if (!type) {
747
0
    if (rank>0)
748
0
      type = "CHILD";
749
0
    else
750
0
      type = "UNKNOWN";
751
0
  }
752
753
0
  rc = init_mod_child(modules, rank, type, 0);
754
0
  if (rc == 0)
755
0
    rc = pi_framework_child_init();
756
0
  ready_time = time(NULL);
757
0
  ready_delay = ready_time - startup_time;
758
759
0
  return rc;
760
0
}
761
762
763
764
/* recursive module initialization; (recursion is used to
765
   process the module linear list in the same order in
766
   which modules are loaded in config file
767
*/
768
769
static int init_mod( struct sr_module* m, int skip_others)
770
0
{
771
0
  struct sr_module_dep *dep;
772
773
0
  if (m) {
774
    /* iterate through the list; if error occurs,
775
       propagate it up the stack
776
     */
777
0
    if (!skip_others && init_mod(m->next, 0) != 0)
778
0
      return -1;
779
780
    /* our module might have been already init'ed through dependencies! */
781
0
    if (m->init_done)
782
0
      return 0;
783
784
0
    if (!m->exports)
785
0
      return 0;
786
787
    /* make sure certain modules get loaded before this one */
788
0
    for (dep = m->sr_deps_init; dep; dep = dep->next) {
789
0
      if (!dep->mod->init_done)
790
0
        if (init_mod(dep->mod, 1) != 0)
791
0
          return -1;
792
0
    }
793
794
0
    if (m->exports->init_f) {
795
0
      LM_DBG("initializing module %s\n", m->exports->name);
796
0
      if (m->exports->init_f()!=0) {
797
0
        LM_ERR("failed to initialize module %s\n", m->exports->name);
798
0
        return -1;
799
0
      }
800
0
    }
801
802
0
    m->init_done = 1;
803
804
    /* no init function -- proceed further */
805
0
#ifdef STATISTICS
806
0
    if (m->exports->stats) {
807
0
      LM_DBG("registering stats for %s\n", m->exports->name);
808
0
      if (register_module_stats(m->exports->name,m->exports->stats)!=0) {
809
0
        LM_ERR("failed to registering "
810
0
          "statistics for module %s\n", m->exports->name);
811
0
        return -1;
812
0
      }
813
0
    }
814
0
#endif
815
    /* register MI functions */
816
0
    if (m->exports->mi_cmds) {
817
0
      LM_DBG("register MI for %s\n", m->exports->name);
818
0
      if (register_mi_mod(m->exports->name,m->exports->mi_cmds)!=0) {
819
0
        LM_ERR("failed to register MI functions for module %s\n",
820
0
          m->exports->name);
821
0
      }
822
0
    }
823
824
    /* proceed with success */
825
0
    return 0;
826
0
  } else {
827
    /* end of list */
828
0
    return 0;
829
0
  }
830
0
}
831
832
/*
833
 * Initialize all loaded modules, the initialization
834
 * is done *AFTER* the configuration file is parsed
835
 */
836
int init_modules(void)
837
0
{
838
0
  struct sr_module *currentMod;
839
0
  int ret;
840
841
0
  if (testing_framework)
842
0
    init_unit_tests();
843
844
  /* pre-initialize all modules */
845
0
  for (currentMod=modules; currentMod; currentMod=currentMod->next) {
846
0
    if (currentMod->exports->preinit_f == NULL)
847
0
      continue;
848
0
    ret = currentMod->exports->preinit_f();
849
0
    if (ret < 0) {
850
0
      LM_ERR("could not pre-initialize module %s!\n",
851
0
          currentMod->exports->name);
852
0
      return ret;
853
0
    }
854
0
  }
855
856
0
  return init_mod(modules, 0);
857
0
}
858
859
860
/* Returns 1 if the module with name 'name' is loaded, and zero otherwise. */
861
int module_loaded(char *name)
862
0
{
863
0
  struct sr_module *currentMod;
864
865
0
  for (currentMod=modules; currentMod; currentMod=currentMod->next) {
866
0
    if (strcasecmp(name,currentMod->exports->name)==0) {
867
0
      return 1;
868
0
    }
869
870
0
  }
871
872
0
  return 0;
873
0
}
874
875
876
void *get_mod_handle(const char *name)
877
0
{
878
0
  struct sr_module *mod;
879
880
0
  for (mod = modules; mod; mod = mod->next)
881
0
    if (!strcasecmp(name, mod->exports->name))
882
0
      return mod->handle;
883
884
0
  return NULL;
885
0
}
886
887
888
/* Counts the additional the number of processes requested by modules */
889
int count_module_procs(int flags)
890
0
{
891
0
  struct sr_module *m;
892
0
  unsigned int cnt;
893
0
  unsigned int n;
894
895
0
  for( m=modules,cnt=0 ; m ; m=m->next) {
896
0
    if (m->exports->procs==NULL)
897
0
      continue;
898
0
    for ( n=0 ; m->exports->procs[n].name ; n++) {
899
0
      if (!m->exports->procs[n].no || !m->exports->procs[n].function)
900
0
        continue;
901
902
0
      if (!flags || (m->exports->procs[n].flags & flags))
903
0
        cnt+=m->exports->procs[n].no;
904
0
    }
905
0
  }
906
0
  LM_DBG("modules require %d extra processes\n",cnt);
907
0
  return cnt;
908
0
}
909
910
911
int start_module_procs(void)
912
0
{
913
0
  struct sr_module *m;
914
0
  unsigned int n;
915
0
  unsigned int l;
916
0
  unsigned int flags;
917
0
  int x;
918
919
0
  for( m=modules ; m ; m=m->next) {
920
0
    if (m->exports->procs==NULL)
921
0
      continue;
922
0
    for( n=0 ; m->exports->procs[n].name ; n++) {
923
0
      if ( !m->exports->procs[n].no || !m->exports->procs[n].function )
924
0
        continue;
925
      /* run pre-fork function */
926
0
      if (m->exports->procs[n].pre_fork_function)
927
0
        if (m->exports->procs[n].pre_fork_function()!=0) {
928
0
          LM_ERR("pre-fork function failed for process \"%s\" "
929
0
            "in module %s\n",
930
0
            m->exports->procs[n].name, m->exports->name);
931
0
          return -1;
932
0
        }
933
      /* fork the processes */
934
0
      for ( l=0; l<m->exports->procs[n].no ; l++) {
935
0
        LM_DBG("forking process \"%s\"/%d for module %s\n",
936
0
          m->exports->procs[n].name, l, m->exports->name);
937
        /* conver the module proc flags to internal proc flgas
938
         * NOTE that the PROC_FLAG_NEEDS_SCRIPT automatically
939
         * assumes PROC_FLAG_HAS_IPC - IPC is needed for script
940
         * reload */
941
0
        flags = OSS_PROC_IS_EXTRA;
942
0
        if (m->exports->procs[n].flags&PROC_FLAG_NEEDS_SCRIPT)
943
0
          flags |= OSS_PROC_NEEDS_SCRIPT;
944
0
        if ( (m->exports->procs[n].flags&PROC_FLAG_HAS_IPC)==0)
945
0
          flags |= OSS_PROC_NO_IPC;
946
0
        struct internal_fork_params ifp = {
947
0
          .proc_desc = m->exports->procs[n].name,
948
0
          .flags = flags,
949
0
          .type = TYPE_MODULE,
950
0
        };
951
0
        x = internal_fork(&ifp);
952
0
        if (x<0) {
953
0
          LM_ERR("failed to fork process \"%s\"/%d for module %s\n",
954
0
            m->exports->procs[n].name, l, m->exports->name);
955
0
          return -1;
956
0
        } else if (x==0) {
957
          /* new process */
958
          /* initialize the process for the rest of the modules */
959
0
          if ( m->exports->procs[n].flags&PROC_FLAG_INITCHILD ) {
960
0
            if (init_child(PROC_MODULE) < 0) {
961
0
              LM_ERR("error in init_child for PROC_MODULE\n");
962
0
              report_failure_status();
963
0
              exit(-1);
964
0
            }
965
966
0
            report_conditional_status( (!no_daemon_mode), 0);
967
0
          } else
968
0
            clean_write_pipeend();
969
970
          /* run the function */
971
0
          m->exports->procs[n].function(l);
972
          /* we shouldn't get here */
973
0
          exit(0);
974
0
        }
975
0
      }
976
      /* run post-fork function */
977
0
      if (m->exports->procs[n].post_fork_function)
978
0
        if (m->exports->procs[n].post_fork_function()!=0) {
979
0
          LM_ERR("post-fork function failed for process \"%s\" "
980
0
            "in module %s\n",
981
0
            m->exports->procs[n].name, m->exports->name);
982
0
          return -1;
983
0
        }
984
0
    }
985
0
  }
986
987
0
  return 0;
988
0
}
989
990
991
int modules_validate_reload(void)
992
0
{
993
0
  struct sr_module *m;
994
0
  int ret = 1;
995
996
0
  for( m=modules ; m ; m=m->next) {
997
0
    if (m->exports->reload_ack_f==NULL)
998
0
      continue;
999
0
    if (!m->exports->reload_ack_f()) {
1000
0
      LM_ERR("module <%s> did not validated the cfg file\n",
1001
0
        m->exports->name);
1002
0
      ret = 0;
1003
0
    }
1004
0
  }
1005
1006
0
  return ret;
1007
0
}