Tamkovich.com: Телеком/VoIP блог
Современные технологии: Asterisk, SIP, Kamailio, Linux, Cisco, Linksys
Kamailio. Функции child_init(rank) и mod_init()
25 августа, 2010 by Сергей Тамкович
Программирование, Разное KamailioКаждый IP телефонист рано или поздно приходит к мысли, а не написать ли мне свой модуль для Asterisk, ну что бы делал всё что мне нужно быстро и без 2х страниц диалплана? Когда модуль для Asterisk написан, возникает желание написать модуль и для SIP-proxy, например для Kamailio. Программировать под Kamailio, на мой взгляд, несколько сложнее чем под Asterisk. Дело в том, что пользовательская база у SIP-proxy серверов (SER, OpenSER, Kamailio, OpenSIPS и т.д.) гораздо меньше пользовательской базы у Asterisk — со всеми последствиями вытекающими отсюда, такими как: малое количество онлайн документации, малое количество форумов/списков рассылки и, самое главное, малое количество заданных и ещё меньшее количество отвеченных вопросов в интернете.
Если вы начали программировать модуль для Kamailio, вы уже наверняка ознакомились с замечательным документом KAMAILIO (OPENSER) Devel Guide — если нет, рекомендую сделать это прямо сейчас. Содержимое документа будет актуально и пользователям OpenSIPS.
В двух словах о функциях child_init(rank) и mod_init(). Обе эти функции используются для инициализации вашего модуля, с небольшим различием. Функция mod_init() выполняется сразу после того как Kamailio инициализирует параметры вашего модуля, установленные из конфига с помощью директив modparam(). Очень важно обратить внимание на то, что mod_init() выполняется только один раз. mod_init() подходящее место для инициализации переменных находящихся в общей (разделяемой) памяти. Для распараллеливания вычислений используется старый-добрый fork() т.е. Kamailio создаёт несколько копий процесса, часть из этих копий используются для служебных целей, а остальные — обрабатывают SIP сообщения в соответствии с конфигурационным файлом. Сразу после форка, вызывается функция child_init(rank). В отличие от mod_init(), child_init(rank) выполняется не 1 раз а несколько — по одному разу для каждого нового процесса. Для того, что бы отличить, что за процесс вызвал child_init(rank) используется единственный параметр этой функции — целочисленный rank. В «KAMAILIO (OPENSER) Devel Guide» — опущен вопрос о том, какие значения он может принимать. Но, как известно, лучшая документация это исходный код. Возможные специальные значения параметра rank перечислены в файле sr_module.h:
#define PROC_MAIN 0 /* Main ser process */ #define PROC_TIMER -1 /* Timer attendant process */ #define PROC_RPC -2 /* RPC type process */ #define PROC_FIFO PROC_RPC /* FIFO attendant process */ #define PROC_TCP_MAIN -4 /* TCP main process */ #define PROC_UNIXSOCK -5 /* Unix socket server */ #define PROC_ATTENDANT -10 /* main "attendant process */ #define PROC_INIT -127 /* special rank, the context is the main ser // process, but this is guaranteed to be executed // before any process is forked, so it can be used // to setup shared variables that depend on some // after mod_init available information (e.g. // total number of processes). // WARNING: child_init(PROC_MAIN) is again called // in the same process (main), but latter // (before tcp), so make sure you don't init things // twice, bot in PROC_MAIN and PROC_INT */ #define PROC_NOCHLDINIT -128 /* no child init functions will be called // if this rank is used in fork_process() */ #define PROC_MIN PROC_NOCHLDINIT /* Minimum process rank */ |
Кроме специальных значений rank <= 0, так же имеются положительные, последовательно начиная с 1. Эти значения получают процессы работники — которые заняты непосредственно обработкой SIP сообщений. Таким образом, если для работы вашего модуля необходимо соединение с БД, целесообразно открыть его из функции child_init(rank) для процессов, у которых rank > 0. Например вот так:
static int child_init(int rank) { srand((11+rank)*getpid()*7); if (rank > 0) { if(init_db()!= 0) { LM_ERR("could not initiate a connection to the database\n"); return -1; } LM_ERR("Rank: %d, PID: %d. Connecting to DB.\n", rank, getpid()); if (db_bind_mod(&db_url, &dbf) < 0) { LM_ERR("Unable to bind to a database driver\n"); return -1; } db_handle = dbf.init(&db_url); } else { LM_ERR("Rank: %d, PID: %d. NOT Connecting to DB.\n", rank, getpid()); } return 0; } |
При запуске Kamailio с модулем содержащим подобную инициализацию, мы увидим в сислоге:
Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[21995]: ERROR: lb [lb.c:345]: Rank: -127, PID: 21995. NOT Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[21996]: ERROR: lb [lb.c:338]: Rank: 1, PID: 21996. Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[21999]: ERROR: lb [lb.c:338]: Rank: 3, PID: 21999. Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[22001]: ERROR: lb [lb.c:345]: Rank: -1, PID: 22001. NOT Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[22002]: ERROR: lb [lb.c:345]: Rank: -1, PID: 22002. NOT Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[21995]: ERROR: lb [lb.c:345]: Rank: 0, PID: 21995. NOT Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[21998]: ERROR: lb [lb.c:338]: Rank: 2, PID: 21998. Connecting to DB. Aug 25 13:21:04 sipproxy /usr/local/sbin/kamailio[22000]: ERROR: lb [lb.c:338]: Rank: 4, PID: 22000. Connecting to DB. |
Программирование, Разное Kamailio