<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tamkovich.com: Телеком/VoIP блог &#187; Kamailio</title>
	<atom:link href="http://tamkovich.com/tag/kamailio/feed/" rel="self" type="application/rss+xml" />
	<link>http://tamkovich.com</link>
	<description>Современные технологии: Asterisk, SIP, Kamailio, Linux, Cisco, Linksys</description>
	<lastBuildDate>Mon, 30 Jan 2012 11:42:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Kamailio: загружаем много данных с помощью db_mysql</title>
		<link>http://tamkovich.com/2010/10/kamailio-how-to-load-big-table-with-db_mysql/</link>
		<comments>http://tamkovich.com/2010/10/kamailio-how-to-load-big-table-with-db_mysql/#comments</comments>
		<pubDate>Wed, 20 Oct 2010 09:42:38 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[ITSP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[Сделай сам]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1572</guid>
		<description><![CDATA[В Kamailio/OpenSIPS, как в любом взрослом проекте, имеется некоторое количество &#171;прокладочных&#187; интерфейсов. Задача этих интерфейсов &#8211; унификация. Например, с помощью mem/mem.h унифицирована работа с памятью. Интерфейс предоставляет набор вызовов pkg_malloc/pkg_free для работы с обычной памятью и shm_malloc/shm_free для работы с разделяемой памятью. Благодаря унификации работы с памятью &#8211; Kamailio портирован на множество различных платформ. Другим [...]]]></description>
			<content:encoded><![CDATA[<p align=justify>
В Kamailio/OpenSIPS, как в любом взрослом проекте, имеется некоторое количество &laquo;прокладочных&raquo; интерфейсов. Задача этих интерфейсов &#8211; унификация. Например, с помощью mem/mem.h унифицирована работа с памятью. Интерфейс предоставляет набор вызовов pkg_malloc/pkg_free для работы с обычной памятью и shm_malloc/shm_free для работы с разделяемой памятью. Благодаря унификации работы с памятью &#8211; Kamailio портирован на множество различных платформ. Другим интерфейсом-прокладкой является интерфейс работы с базами данных <a href=http://www.asipto.com/pub/kamailio-devel-guide/#c09database>DB API</a>. Базовая работа с этим интерфейсом хорошо описана в <a href=http://www.asipto.com/pub/kamailio-devel-guide/>KAMAILIO (OPENSER) Devel Guide</a>.
</p>
<p><span id="more-1572"></span></p>
<p align=justify>
Классическая операция получения данных из MySQL выглядит следующим образом:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">snprintf<span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        <span style="color: #ff0000;">&quot;select n.id,n.name,n.ip,n.port,n.capacity,COUNT(c.node) 
         from cluster_nodes n left join active_calls c on (n.name=c.node) 
         where online=1 group by n.name&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
sql_cmd.<span style="color: #202020;">s</span> <span style="color: #339933;">=</span> sqlcmd<span style="color: #339933;">;</span>
sql_cmd.<span style="color: #202020;">len</span> <span style="color: #339933;">=</span> strlen<span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
LOG<span style="color: #009900;">&#40;</span>L_DBG<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Trying to execute SQL: '%s'<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> sqlcmd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fres <span style="color: #339933;">=</span> dbf.<span style="color: #202020;">raw_query</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>sql_cmd<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>fres <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        total <span style="color: #339933;">=</span> RES_ROW_N<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>total <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> total<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        node <span style="color: #339933;">=</span> shm_malloc<span style="color: #009900;">&#40;</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> ci_li_node<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>node <span style="color: #339933;">==</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Could not allocate shared memory<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                        node<span style="color: #339933;">-&gt;</span>id <span style="color: #339933;">=</span> RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">int_val</span><span style="color: #339933;">;</span>
                        node<span style="color: #339933;">-&gt;</span>calls_init <span style="color: #339933;">=</span> RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">5</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">int_val</span><span style="color: #339933;">;</span>
                        node<span style="color: #339933;">-&gt;</span>calls_current <span style="color: #339933;">=</span> node<span style="color: #339933;">-&gt;</span>calls_init<span style="color: #339933;">;</span>
                        node<span style="color: #339933;">-&gt;</span>calls_max <span style="color: #339933;">=</span> RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">4</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">int_val</span><span style="color: #339933;">;</span>
                        node<span style="color: #339933;">-&gt;</span>port <span style="color: #339933;">=</span> RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">3</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">int_val</span><span style="color: #339933;">;</span>
                        snprintf<span style="color: #009900;">&#40;</span>node<span style="color: #339933;">-&gt;</span>name<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>node<span style="color: #339933;">-&gt;</span>name<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s&quot;</span><span style="color: #339933;">,</span> 
                                <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">str_val</span>.<span style="color: #202020;">s</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        snprintf<span style="color: #009900;">&#40;</span>node<span style="color: #339933;">-&gt;</span>ip<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>node<span style="color: #339933;">-&gt;</span>ip<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%s&quot;</span><span style="color: #339933;">,</span> 
                                <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span>.<span style="color: #202020;">values</span><span style="color: #009900;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #009900;">&#93;</span>.<span style="color: #202020;">val</span>.<span style="color: #202020;">str_val</span>.<span style="color: #202020;">s</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        node<span style="color: #339933;">-&gt;</span>next <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
&nbsp;
                        total_max <span style="color: #339933;">+=</span> node<span style="color: #339933;">-&gt;</span>calls_max<span style="color: #339933;">;</span>
                        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">==</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">=</span> node<span style="color: #339933;">;</span>
                                mylist<span style="color: #339933;">-&gt;</span>first <span style="color: #339933;">=</span> node<span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
                                mylist<span style="color: #339933;">-&gt;</span>last<span style="color: #339933;">-&gt;</span>next <span style="color: #339933;">=</span> node<span style="color: #339933;">;</span>
                                mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">=</span> node<span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                <span style="color: #009900;">&#125;</span>
                LOG<span style="color: #009900;">&#40;</span>L_DBG<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;PRELOAD TOTAL: [servers] %d items = %lu bytes.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> 
                        i<span style="color: #339933;">,</span> i <span style="color: #339933;">*</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> ci_li_node<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                mylist<span style="color: #339933;">-&gt;</span>dt <span style="color: #339933;">=</span> time<span style="color: #009900;">&#40;</span>NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>       
        dbf.<span style="color: #202020;">free_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>Как видим из простого примера, получение данных из MySQL сводится к трём действиям:
<ol>
<li>Отправляем SQL запрос с помощью команды raw_query.
<li>Читаем результаты с помощью макросов RES_ROW_N и RES_ROWS
<li>Подчищаем за собой память с помощью free_result</ol>
<p>Пока мы действуем по шаблону &#8211; всё отлично работает.
</p>
<p align=justify >
Но стоит нам захотеть чего то большего &#8211; и подход придётся менять. Например приведенным выше кодом нельзя загрузить за раз большую таблицу (тысячи записей). Прокладочные интерфейсы БД и памяти &#8211; накладываются друг на друга и возникают интересные эффекты. Дело в том, что при попытке загрузить большую таблицу целиком &#8211; db_mysql выделяет память под неё &#8211; одним куском. С другой стороны, pkg_free не освобождает память моментально, а лишь помечает её как готовую к очистке. Всё это приводит к тому, что загрузка большой таблицы срабатывает 2 раза подряд, а на третий возникает ошибка &#8211; недостаточно памяти.
</p>
<p align=justify >
Зачем загружать всю таблицу целиком &#8211; спросите вы? Вариантов может быть очень много &#8211; самый распространённый, пожалуй, &#8211; для того, что бы закешировать данные из БД. На одной СУБД далеко не уедешь, даже на такой быстрой как MySQL. Итак, что же нужно сделать для того, что бы обойти проблемы с памятью? Ответ очень простой: нужно воспользоваться вызовом fetch_result. К сожалению, применение этого вызова не расписано в <a href=http://www.asipto.com/pub/kamailio-devel-guide/>KAMAILIO (OPENSER) Devel Guide</a>, но, как известно, лучшая документация это исходный код. С практикой применения этого вызова можно ознакомиться в модулях Kamailio:</p>
<pre>
[root@sipproxy kamailio-3.0.3]# grep -l fetch_result */*/*.c
...
modules_k/dialog/dlg_db_handler.c
modules_k/drouting/dr_load.c
modules_k/htable/ht_db.c
modules_k/pdt/pdt.c
...
</pre>
<p>Вызов fetch_result позволяет указать сколько строк мы хотим поместить в память. Таким образом, вызывая fetch_result в цикле &#8211; мы обработаем все строки возвращённые базой данных по порциям. Если вы планируете использовать fetch_result самостоятельно, необходимо передать NULL в качестве указателя db_res_t** _r у функций raw_query(&#8230;) и query(&#8230;). Для наглядности, рассмотрим похожий кусок кода, написанный с использованием вызова fetch_result. Параметр ci_preload_chunk задаёт количество строк загружаемых в память за 1 вызов:
</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">snprintf<span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #339933;">,</span> <span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span>
        <span style="color: #ff0000;">&quot;select name,owner from sip where host='dynamic' and owner&gt;0&quot;</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
sql_cmd.<span style="color: #202020;">s</span> <span style="color: #339933;">=</span> sqlcmd<span style="color: #339933;">;</span>
sql_cmd.<span style="color: #202020;">len</span> <span style="color: #339933;">=</span> strlen<span style="color: #009900;">&#40;</span>sqlcmd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
LOG<span style="color: #009900;">&#40;</span>L_DBG<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Trying to execute SQL: '%s'<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> sqlcmd<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fres <span style="color: #339933;">=</span> dbf.<span style="color: #202020;">raw_query</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>sql_cmd<span style="color: #339933;">,</span> NULL<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>fres <span style="color: #339933;">==</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        LOG<span style="color: #009900;">&#40;</span>L_DBG<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;Trying to fetch first %d items.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> ci_preload_chunk<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>dbf.<span style="color: #202020;">fetch_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>res<span style="color: #339933;">,</span> ci_preload_chunk<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Error while fetching result<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        dbf.<span style="color: #202020;">free_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>       
        total <span style="color: #339933;">=</span> RES_ROW_N<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        LOG<span style="color: #009900;">&#40;</span>L_DBG<span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;%d first items fetched.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> total<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>total <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">do</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #b1b100;">for</span><span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> total<span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                row <span style="color: #339933;">=</span> RES_ROWS<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> i<span style="color: #339933;">;</span>
                                u <span style="color: #339933;">=</span> shm_malloc<span style="color: #009900;">&#40;</span><span style="color: #993333;">sizeof</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">struct</span> ci_li_sipuser<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>u <span style="color: #339933;">==</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Could not allocate shared memory<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                        <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span>       
                                u<span style="color: #339933;">-&gt;</span>sipaccount <span style="color: #339933;">=</span> atoi<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span><span style="color: #339933;">*</span><span style="color: #009900;">&#41;</span>VAL_STRING<span style="color: #009900;">&#40;</span>ROW_VALUES<span style="color: #009900;">&#40;</span>row<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                u<span style="color: #339933;">-&gt;</span>customer <span style="color: #339933;">=</span> VAL_INT<span style="color: #009900;">&#40;</span>ROW_VALUES<span style="color: #009900;">&#40;</span>row<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                u<span style="color: #339933;">-&gt;</span>next <span style="color: #339933;">=</span> NULL<span style="color: #339933;">;</span>
                                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">==</span> NULL<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">=</span> u<span style="color: #339933;">;</span>
                                        mylist<span style="color: #339933;">-&gt;</span>first <span style="color: #339933;">=</span> u<span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
                                        mylist<span style="color: #339933;">-&gt;</span>last<span style="color: #339933;">-&gt;</span>next <span style="color: #339933;">=</span> u<span style="color: #339933;">;</span>
                                        mylist<span style="color: #339933;">-&gt;</span>last <span style="color: #339933;">=</span> u<span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span>
                                mylist<span style="color: #339933;">-&gt;</span>elements<span style="color: #339933;">++;</span>
                                cnt<span style="color: #339933;">++;</span>
                        <span style="color: #009900;">&#125;</span>
                        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>dbf.<span style="color: #202020;">fetch_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>res<span style="color: #339933;">,</span> ci_preload_chunk<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Error while fetching result<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                                        dbf.<span style="color: #202020;">free_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                                <span style="color: #009900;">&#125;</span>
                                <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
                        <span style="color: #009900;">&#125;</span>
                        total <span style="color: #339933;">=</span> RES_ROW_N<span style="color: #009900;">&#40;</span>res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span>total <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                dbf.<span style="color: #202020;">free_result</span><span style="color: #009900;">&#40;</span>db_handle<span style="color: #339933;">,</span> res<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/10/kamailio-how-to-load-big-table-with-db_mysql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kamailio 3.1.0</title>
		<link>http://tamkovich.com/2010/10/kamailio-3-1-0/</link>
		<comments>http://tamkovich.com/2010/10/kamailio-3-1-0/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 10:10:50 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1548</guid>
		<description><![CDATA[Вчера, 6 октября 2010 года, состоялся релиз новой версии замечательного проекта Kamailio &#8211; 3.1.0. С полным списком нововведений, можно ознакомиться здесь, из наиболее интересного отмечу: Асинхронный TLS Поддержка UDP RAW сокетов на Linux (повышение производительности на 40-50%) Встроенные интерпретаторы LUA и Python Встроенные HTTP и XCAP серверы Подсистема кеширования работающая по алгоритму &#171;индексированное дерево&#187;. Регистрация [...]]]></description>
			<content:encoded><![CDATA[<p align=justify >
Вчера, 6 октября 2010 года, состоялся релиз новой версии замечательного проекта Kamailio &#8211; 3.1.0. С полным списком нововведений, можно ознакомиться <a href=http://www.kamailio.org/w/kamailio-openser-v3.1.0-release-notes/>здесь</a>, из наиболее интересного отмечу:
</p>
<ul>
<li> Асинхронный TLS
<li> Поддержка UDP RAW сокетов на Linux (повышение производительности на 40-50%)
<li> Встроенные интерпретаторы LUA и Python
<li> Встроенные HTTP и XCAP серверы
<li> Подсистема кеширования работающая по алгоритму &laquo;индексированное дерево&raquo;.
<li> Регистрация на других серверах по протоколу <a href=http://tamkovich.com/tag/sip/ >SIP</a>
<li> Поддержка заголовка Reason для сообщений CANCEL
<li> Продолжение работы по слиянию проектов Kamailio и SER &#8211; объединены модули: sl, auth, sms и ratelimit
</ul>
<p align=justify >
Встроенные интерпретаторы LUA/Python &#8211; это, судя по всему, дань моде. Так же как и встроенные серверы XCAP и HTTP. Все остальные изменения &#8211; крайне интересны. Надеюсь нововведения не отразятся на стабильности работы Kamailio.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/10/kamailio-3-1-0/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Тестируем SIP Redirect Server с помощью sipp</title>
		<link>http://tamkovich.com/2010/09/benchmarking-redirect-server-with-sipp/</link>
		<comments>http://tamkovich.com/2010/09/benchmarking-redirect-server-with-sipp/#comments</comments>
		<pubDate>Fri, 24 Sep 2010 09:27:51 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[SIP]]></category>
		<category><![CDATA[sipp]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1517</guid>
		<description><![CDATA[Замечательная утилита sipp сегодня принадлежит корпорации HP. Утилита эта используется для генерации потока звонков по протоколу SIP. Сценарий по умолчанию подразумевает стандартный поток SIP ообщений: Отправляем INVITE, получаем ответы с кодами 100, 180, 183 и 200. Дождавшись ответа с кодом 200, отправляем подтверждение ACK. Выдерживаем паузу (в нашем случае &#8211; 0 миллисекунд) и отправляем сообщение [...]]]></description>
			<content:encoded><![CDATA[<p align=justify>
Замечательная утилита sipp сегодня принадлежит корпорации HP. Утилита эта используется для генерации потока звонков по протоколу <a href=http://tamkovich.com/tag/sip/ >SIP</a>. Сценарий по умолчанию подразумевает стандартный поток <a href=http://tamkovich.com/tag/sip/ >SIP</a> ообщений: Отправляем INVITE, получаем ответы с кодами 100, 180, 183 и 200. Дождавшись ответа с кодом 200, отправляем подтверждение ACK. Выдерживаем паузу (в нашем случае &#8211; 0 миллисекунд) и отправляем сообщение BYE. Для сообщения BYE дожидаемся ответа с кодом 200.
</p>
<pre>
                                 Messages  Retrans   Timeout   Unexpected-Msg
      INVITE ---------->         16        0         0
         100 <----------         0         0         0         16
         180 <----------         0         0         0         0
         183 <----------         0         0         0         0
         200 <----------  E-RTD1 0         0         0         0
         ACK ---------->         0         0
       Pause [      0ms]         0                             0
         BYE ---------->         0         0         0
         200 <----------         0         0         0         0
</pre>
<p><span id="more-1517"></span></p>
<p align=justify>
Данный сценарий не очень подходит для тестирования серверов перенаправления (redirect server). Дело в том, что на любой запрос клиента (INVITE, REGISTER и т.д.) сервер перенаправления, как правило, выдает ответ с кодом 300 (Multiple Choices) или 302 (Moved Temporarily). В сценарии по умолчанию, ответы с данными кодами попадают в категорию "Unexpected Messages" - неожиданных сообщений. В целом тестировать нагрузку можно и так, когда ваш сервер перестанет справляться с нагрузкой, цифра в колонке Timeout начнёт возрастать. Однако при таком подходе, невозможно отличить ответы с кодами 300 и 302 от других "неожиданных ответов".
</p>
<p align=justify>
Вторым недостатком использования теста по умолчанию, является его синтетичность. Все звонки инициированные по этому сценарию - идентичны между собой. Т.е. имеют одинаковые поля From, To, Contact и т.д. Результаты такого теста, могут сильно отличаться от реальности, т.к. одно единственное значение полей From, To, Contact - наверняка попадет в кеш тестируемой системы.
</p>
<p align=justify>
На помощь нам приходит чрезвычайная гибкость утилиты sipp. Дело в том, что пользователь может создать свой собственный, произвольный сценарий тестирования и описать его используя XML. Кроме того, существует возможность подставлять в <a href=http://tamkovich.com/tag/sip/ >SIP</a> сообщения, генерируемые программой sipp данные из внешних источников - CSV файлов. Прочитать подробности о создании собственных сценариев, можно на <a href=http://sipp.sourceforge.net/doc/reference.html#xmlsyntax >официальном сайте</a> программы sipp. Здесь же, в качестве примера, я приведу сценарий, используемый мной для тестирования производительности сервера перенаправления (<a href=http://tamkovich.com/tag/sip/ >SIP</a> Redirect Server).
</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;ISO-8859-1&quot;</span> <span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;scenario</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;Redirect Scenario&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;send</span> <span style="color: #000066;">retrans</span>=<span style="color: #ff0000;">&quot;500&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
     <span style="color: #339933;">&lt;![CDATA[</span>
&nbsp;
<span style="color: #339933;">      INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0</span>
<span style="color: #339933;">      Via: SIP/2.0/[transport] [local_ip]:[local_port]</span>
<span style="color: #339933;">      From: [field0] &lt;sip:[field0]@[local_ip]:[local_port]&gt;;tag=[call_number]</span>
<span style="color: #339933;">      To: sut &lt;sip:[service]@[remote_ip]:[remote_port]&gt;</span>
<span style="color: #339933;">      Call-ID: [call_id]</span>
<span style="color: #339933;">      Cseq: 1 INVITE</span>
<span style="color: #339933;">      Contact: sip:[field0]@[local_ip]:[local_port]</span>
<span style="color: #339933;">      Max-Forwards: 70</span>
<span style="color: #339933;">      Subject: Performance Test</span>
<span style="color: #339933;">      Content-Type: application/sdp</span>
<span style="color: #339933;">      Content-Length: [len]</span>
&nbsp;
<span style="color: #339933;">      v=0</span>
<span style="color: #339933;">      o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]</span>
<span style="color: #339933;">      s=-</span>
<span style="color: #339933;">      t=0 0</span>
<span style="color: #339933;">      c=IN IP[media_ip_type] [media_ip]</span>
<span style="color: #339933;">      m=audio [media_port] RTP/AVP 0</span>
<span style="color: #339933;">      a=rtpmap:0 PCMU/8000</span>
&nbsp;
<span style="color: #339933;">    ]]&gt;</span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/send<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
&nbsp;
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;recv</span> <span style="color: #000066;">response</span>=<span style="color: #ff0000;">&quot;300&quot;</span> <span style="color: #000066;">optional</span>=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/recv<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;recv</span> <span style="color: #000066;">response</span>=<span style="color: #ff0000;">&quot;302&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
   <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/recv<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/scenario<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p align=justify >
Пару слов о структуре данного сценарий. Внутри сценария присутствует 1 тег send и 2 тега recv. Тег send описывает запрос отправляемый программой sipp, теги recv - возможные ответы на отправленное сообщение. В теге send присутствует конструкция &lt;![CDATA[ ... ]]&gt; Внутри которой находится тело отправляемого запроса. В теле запроса присутствует большое количество переменных sipp (слова в квадратных скобках). Большинство из них будет подставлено утилитой sipp автоматически. Наибольший интерес для нас представляет переменная <b>[field0]</b>. Перед отправкой на место данного ключевого слова подставляется первое поле из внешнего источника (CSV файла). Для того, что бы использовать этот сценарий, необходимо выполнить:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">sipp <span style="color: #660033;">-sf</span> redirect.xml <span style="color: #660033;">-inf</span> uids.csv <span style="color: #660033;">-s</span> <span style="color: #000000;">1010</span> <span style="color: #660033;">-l</span> <span style="color: #000000;">0</span> <span style="color: #660033;">-r</span> <span style="color: #000000;">2000</span> 10.10.1.4</pre></div></div>

<p align=justify >
Здесь redirect.xml - файл, содержащий наш сценарий. uids.csv - файл содержащий большое количество имён пользователей (как верных так и неверных). Именно из файла uids.csv подставляется первое поле взамен ключевого слова [field0]. Именно благодаря этому файлу мы уходим от синтетического сценария ближе к реальности, моделируя ситуацию в которой большое количество абонентов звонит на один и тот же номер. С помощью параметра -s 1010 указывается номер на который будут совершаться вызовы. Значение параметра -s подставляется вместо ключевого слова [service]. Если в сценарии заменить [service] на [field1] то можно смоделировать ситуацию, в которой множество абонентов совершает вызовы множества (различных) номеров. Параметр -l 0 - снимает ограничение на количество активных звонков в единицу времени. Параметр -r 2000 устанавливает скорость инициирования новых вызовов (CPS) - 2000 вызовов в секунду. Ну а 10.10.1.4 это, как несложно догадаться, IP адрес тестируемого сервера.
</p>
<p align=justify >
Так же приведу пример файла users.csv. Первой строкой в файле указывается ключевое слово, в нашем случаем - RANDOM. Это слово, определяет в каком порядке будут использованы строки файла. На сегодня возможны варианты: RANDOM - случайно, SEQUENTIAL - последовательно и специальное USER. Итак, вот он файл:
</p>

<div class="wp_syntax"><div class="code"><pre class="csv" style="font-family:monospace;">RANDOM
100;
101;
102;
103;
104;
...
11998;
11999;</pre></div></div>

<p align=justify >
Обратите внимание на ';' - для работы с sipp рекомендую включать в csv файлы пустую колонку в конец таблицы. Иначе, есть риск, что sipp добавит к полю виндовый \r. Например вместо имени пользователя "100" будет подставляться "100\r", что может изменить результаты тестирования. Если строк в вашем файле выходит слишком много, генерировать такой файл ненужно. Существует возможность описать последовательность значений в виде формулы. Например вот такая запись будет эквивалентна CSV файлу с цифрами от 0 до 100 000 в первой колонке:
</p>

<div class="wp_syntax"><div class="code"><pre class="csv" style="font-family:monospace;">USERS,PRINTF=100000
%d</pre></div></div>

<p align=justify >
Реальный тест с использованием приведенного сценария выглядит вот так:
</p>
<pre>
[root@voiptest ~]# sipp -sf redirect.xml -inf uids.csv -s 1010 -l 0 -r 2000 10.10.1.4
Resolving remote host '10.10.1.4'... Done.
------------------------------ Scenario Screen -------- [1-9]: Change Screen --
  Call-rate(length)   Port   Total-time  Total-calls  Remote-host
2000.0(0 ms)/1.000s   5060      49.63 s        99272  10.10.1.4:5060(UDP)

  1270 new calls during 0.636 s period   0 ms scheduler resolution
  0 calls (limit 0)                      Peak was 40 calls, after 2 s
  0 Running, 66004 Paused, 0 Woken up
  0 dead call msg (discarded)            5 out-of-call msg (discarded)
  1 open sockets

                                 Messages  Retrans   Timeout   Unexpected-Msg
      INVITE ---------->         99272     1         0
         300 <----------         0         0         0         0
         302 <----------         99272     0         0         0
</pre>
<p align=justify >
Удачного тестирования!</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/09/benchmarking-redirect-server-with-sipp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>eyeBeam и X-Lite не понимают перенаправления 3XX (300, 302 и т.д.)</title>
		<link>http://tamkovich.com/2010/08/eyebeam-xlite-doesnt-understand-3xx-300-302-responses/</link>
		<comments>http://tamkovich.com/2010/08/eyebeam-xlite-doesnt-understand-3xx-300-302-responses/#comments</comments>
		<pubDate>Fri, 27 Aug 2010 09:09:26 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1474</guid>
		<description><![CDATA[Казалось бы X-Lite (он же eyeBeam) от фирмы CounterPath, один из самых распространённых софтфонов, не должен содержать детских ошибок в работе с SIP proxy, но к сожалению это не так. X-Lite/eyeBeam принципиально не умеет работать с перенаправляющими (Redirect) серверами. Перенаправляющие SIP сервера, это как правило SIP proxy, настроенные таким образом, что бы на запросы клиентов [...]]]></description>
			<content:encoded><![CDATA[<p><img src=/wp-content/uploads/2010/08/counterpath.png align=right ></p>
<p align=justify >
Казалось бы X-Lite (он же eyeBeam) от фирмы CounterPath, один из самых распространённых софтфонов, не должен содержать детских ошибок в работе с <a href=http://tamkovich.com/tag/sip/ >SIP</a> proxy, но к сожалению это не так. X-Lite/eyeBeam принципиально не умеет работать с перенаправляющими (Redirect) серверами. Перенаправляющие <a href=http://tamkovich.com/tag/sip/ >SIP</a> сервера, это как правило <a href=http://tamkovich.com/tag/sip/ >SIP</a> proxy, настроенные таким образом, что бы на запросы клиентов отвечать кодами 3XX (как правило 300 &laquo;Multiple Choices&raquo; или 302 &laquo;Moved Temporarily&raquo;) &#8211; перенаправляя клиента на наименее загруженный сервер.
</p>
<p align=justify >
При попытке зарегистрироваться на сервере перенаправления, X-lite пишет на своём экране: &laquo;Registration error: 302 &#8211; Redirect&raquo;. Прямо скажем коды 3XX не являются ошибками, однако X-Lite/eyeBeam считает иначе. Если мы посмотрим wireshark-ом, то увидим следующее:
</p>
<p><span id="more-1474"></span><br />
<center><img src=/wp-content/uploads/2010/08/xlite-wireshark.gif ></center></p>
<p align=justify >
При попытке зарегистрироваться на балансировщике нагрузки (192.168.14.198), X-Lite (192.168.1.114) получает перенаправление на адрес 192.168.14.207. После этого X-Lite, в соответствии с RFC3261, должен сформировать новый <a href=http://tamkovich.com/tag/sip/ >SIP</a> запрос и отправить его по новому адресу (192.168.14.207). Как показывает wireshark, X-Lite формирует новый <a href=http://tamkovich.com/tag/sip/ >SIP</a> запрос, подставляя в него адрес полученный от балансировщика нагрузки. Однако, вместо того что бы отправить его по соответствующему IP адресу, X-Lite продолжает использовать IP адрес <a href=http://tamkovich.com/tag/sip/ >SIP</a> proxy. Судя по форуму CounterPath, этой проблеме более 2х лет.
</p>
<p align=justify >
Что же другие продукты от CounterPath? eyeBeam, как и следовало ожидать, ведёт себя точно так же как X-Lite, т.е. некорректно обрабатывает редиректы. А вот дорогущий Bria Professional вероятно использует другое ядро, отличное от eyeBeam/X-Lite посколько он правильно работает с перенаправлениями. Что делать? как быть? &#8211; Заплатить 50 баксов за Bria Professional или поставить Zoiper. Zoiper корректно отрабатывает перенаправления 3XX полученные от Kamailio.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/08/eyebeam-xlite-doesnt-understand-3xx-300-302-responses/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Kamailio. Функции child_init(rank) и mod_init()</title>
		<link>http://tamkovich.com/2010/08/kamailio-child_init-rank-mod_init/</link>
		<comments>http://tamkovich.com/2010/08/kamailio-child_init-rank-mod_init/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 10:29:14 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1467</guid>
		<description><![CDATA[Каждый IP телефонист рано или поздно приходит к мысли, а не написать ли мне свой модуль для Asterisk, ну что бы делал всё что мне нужно быстро и без 2х страниц диалплана? Когда модуль для Asterisk написан, возникает желание написать модуль и для SIP-proxy, например для Kamailio. Программировать под Kamailio, на мой взгляд, несколько сложнее [...]]]></description>
			<content:encoded><![CDATA[<p align=justify>
Каждый IP телефонист рано или поздно приходит к мысли, а не написать ли мне свой модуль для <a href=http://tamkovich.com/asterisk/ >Asterisk</a>, ну что бы делал всё что мне нужно быстро и без 2х страниц диалплана? Когда модуль для <a href=http://tamkovich.com/asterisk/ >Asterisk</a> написан, возникает желание написать модуль и для <a href=http://tamkovich.com/tag/sip/ >SIP</a>-proxy, например для Kamailio. Программировать под Kamailio, на мой взгляд, несколько сложнее чем под <a href=http://tamkovich.com/asterisk/ >Asterisk</a>. Дело в том, что пользовательская база у <a href=http://tamkovich.com/tag/sip/ >SIP</a>-proxy серверов (SER, OpenSER, Kamailio, OpenSIPS и т.д.) гораздо меньше пользовательской базы у <a href=http://tamkovich.com/asterisk/ >Asterisk</a> &#8211; со всеми последствиями вытекающими отсюда, такими как: малое количество онлайн документации, малое количество форумов/списков рассылки и, самое главное, малое количество заданных и ещё меньшее количество отвеченных вопросов в интернете.
</p>
<p align=justify>
Если вы начали программировать модуль для Kamailio, вы уже наверняка ознакомились с замечательным документом <a href=http://www.asipto.com/pub/kamailio-devel-guide/ >KAMAILIO (OPENSER) Devel Guide</a> &#8211; если нет, рекомендую сделать это прямо сейчас. Содержимое документа будет актуально и пользователям OpenSIPS.
</p>
<p><span id="more-1467"></span></p>
<p align=justify>
В двух словах о функциях child_init(rank) и mod_init(). Обе эти функции используются для инициализации вашего модуля, с небольшим различием. Функция mod_init() выполняется сразу после того как Kamailio инициализирует параметры вашего модуля, установленные из конфига с помощью директив modparam(). Очень важно обратить внимание на то, что mod_init() выполняется только один раз. mod_init() подходящее место для инициализации переменных находящихся в общей (разделяемой) памяти. Для распараллеливания вычислений используется старый-добрый fork() т.е. Kamailio создаёт несколько копий процесса, часть из этих копий используются для служебных целей, а остальные &#8211; обрабатывают <a href=http://tamkovich.com/tag/sip/ >SIP</a> сообщения в соответствии с конфигурационным файлом. Сразу после форка, вызывается функция child_init(rank). В отличие от mod_init(), child_init(rank) выполняется не 1 раз а несколько &#8211; по одному разу для каждого нового процесса. Для того, что бы отличить, что за процесс вызвал child_init(rank) используется единственный параметр этой функции &#8211; целочисленный rank. В &laquo;<a href=http://www.asipto.com/pub/kamailio-devel-guide/ >KAMAILIO (OPENSER) Devel Guide</a>&raquo; &#8211; опущен вопрос о том, какие значения он может принимать. Но, как известно, лучшая документация это исходный код. Возможные специальные значения параметра rank перечислены в файле sr_module.h:
</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#define PROC_MAIN      0  /* Main ser process */</span>
<span style="color: #339933;">#define PROC_TIMER    -1  /* Timer attendant process */</span>
<span style="color: #339933;">#define PROC_RPC      -2  /* RPC type process */</span>
<span style="color: #339933;">#define PROC_FIFO      PROC_RPC  /* FIFO attendant process */</span>
<span style="color: #339933;">#define PROC_TCP_MAIN -4  /* TCP main process */</span>
<span style="color: #339933;">#define PROC_UNIXSOCK -5  /* Unix socket server */</span>
<span style="color: #339933;">#define PROC_ATTENDANT -10  /* main &quot;attendant process */</span>
<span style="color: #339933;">#define PROC_INIT     -127 /* special rank, the context is the main ser</span>
                                      <span style="color: #666666; font-style: italic;">// process, but this is guaranteed to be executed</span>
                                      <span style="color: #666666; font-style: italic;">// before any process is forked, so it can be used</span>
                                      <span style="color: #666666; font-style: italic;">// to setup shared variables that depend on some</span>
                                      <span style="color: #666666; font-style: italic;">// after mod_init available information (e.g.</span>
                                      <span style="color: #666666; font-style: italic;">// total number of processes).</span>
                                      <span style="color: #666666; font-style: italic;">// WARNING: child_init(PROC_MAIN) is again called</span>
                                      <span style="color: #666666; font-style: italic;">// in the same process (main), but latter</span>
                                      <span style="color: #666666; font-style: italic;">// (before tcp), so make sure you don't init things</span>
                                      <span style="color: #666666; font-style: italic;">// twice, bot in PROC_MAIN and PROC_INT */</span>
<span style="color: #339933;">#define PROC_NOCHLDINIT -128 /* no child init functions will be called</span>
                              <span style="color: #666666; font-style: italic;">//  if this rank is used in fork_process() */</span>
&nbsp;
<span style="color: #339933;">#define PROC_MIN PROC_NOCHLDINIT /* Minimum process rank */</span></pre></div></div>

<p align=justify >
Кроме специальных значений rank &lt;= 0, так же имеются положительные, последовательно начиная с 1. Эти значения получают процессы работники &#8211; которые заняты непосредственно обработкой <a href=http://tamkovich.com/tag/sip/ >SIP</a> сообщений. Таким образом, если для работы вашего модуля необходимо соединение с БД, целесообразно открыть его из функции child_init(rank) для процессов, у которых rank &gt; 0. Например вот так:
</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #993333;">static</span> <span style="color: #993333;">int</span> child_init<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> rank<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        srand<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #0000dd;">11</span><span style="color: #339933;">+</span>rank<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #0000dd;">7</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>rank <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>init_db<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">!=</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;could not initiate a connection to the database<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
&nbsp;
                LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Rank: %d, PID: %d. Connecting to DB.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> rank<span style="color: #339933;">,</span> getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>db_bind_mod<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>db_url<span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span>dbf<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Unable to bind to a database driver<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                        <span style="color: #b1b100;">return</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                db_handle <span style="color: #339933;">=</span> dbf.<span style="color: #202020;">init</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>db_url<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
                LM_ERR<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Rank: %d, PID: %d. NOT Connecting to DB.<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> rank<span style="color: #339933;">,</span> getpid<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p align=justify >
При запуске Kamailio с модулем содержащим подобную инициализацию, мы увидим в сислоге:
</p>

<div class="wp_syntax"><div class="code"><pre class="log" style="font-family:monospace;">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.</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/08/kamailio-child_init-rank-mod_init/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SER, OpenSER, Kamailio, OpenSIPS, SIP-router &#8211; кто есть кто?</title>
		<link>http://tamkovich.com/2010/06/ser-openser-kamailio-opensips-sip-router/</link>
		<comments>http://tamkovich.com/2010/06/ser-openser-kamailio-opensips-sip-router/#comments</comments>
		<pubDate>Tue, 08 Jun 2010 14:03:38 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[OpenSER]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1314</guid>
		<description><![CDATA[От обилия почти идентичного ПО, в сегменте SIP маршрутизаторов &#8211; разбегаются глаза. SER, OpenSER, Kamailio, OpenSIPS, SIP-router &#8211; в чём собственно разница? &#8211; спросит начинающий IP-телефонист? Всё не так сложно, как могло бы показаться с первого взгляда. Вначале было слово SER! SIP Express Router был разработан в Германии в институте Fraunhofer (известным разработкой MP3) в [...]]]></description>
			<content:encoded><![CDATA[<p align=justify>
От обилия почти идентичного ПО, в сегменте <a href=http://tamkovich.com/tag/sip/ >SIP</a> маршрутизаторов &#8211; разбегаются глаза. SER, <a href=http://tamkovich.com/tag/openser/ >OpenSER</a>, <a href=http://tamkovich.com/tag/kamailio/ >Kamailio</a>, OpenSIPS, <a href=http://tamkovich.com/tag/sip/ >SIP</a>-router &#8211; в чём собственно разница? &#8211; спросит начинающий IP-телефонист? Всё не так сложно, как могло бы показаться с первого взгляда.</p>
<p align=justify >
Вначале было <strike>слово</strike> SER! <a href=http://tamkovich.com/tag/sip/ >SIP</a> Express Router был разработан в Германии в институте Fraunhofer (известным разработкой MP3) в 2001 году. Компания разработчиков подобралась весьма пёстрая &#8211; румыны, венгры, испанцы и даже, что удивительно, немцы. В 2004 году проект был выделен из под крыла института и пущен в свободное плавание. Для этого была создана компания iptel.org. Но, как известно любому LOR-овцу &#8211; если тебе что-то не нравится в проекте &#8211; его надо тут же форкнуть, к чему это общение, обсуждение проблем и компромисы с недостойными?
</p>
<p><span id="more-1314"></span></p>
<p align=justify>
Что может не нравится в проекте созданом на деньги немецких налогоплательщиков? ну хотя бы то, что генеральных директоров в новой компании не 5 и даже не 3. Так проект SER был форкнут и появился параллельный проект <a href=http://tamkovich.com/tag/openser/>OpenSER</a>. Почти 4 года оба проекта находились в анабиозе. Различия между этими проектами и сегодня минимальны, не смотря на то, что 4 года &#8211; приличный срок. И вот настал август 2008 года. Чего же удалось достичь проекту <a href=http://tamkovich.com/tag/openser/>OpenSER</a> за 4 года? Ну во-первых выяснилось, что название OpenSER &#8211; нарушает торговые знаки, а во-вторых, что два генеральных директора тоже многовато. По этому в августе 2008 года <a href=http://tamkovich.com/tag/openser/>OpenSER</a> был форкнут и переименован. Из <a href=http://tamkovich.com/tag/openser/>OpenSER</a>-а вышли две ветки: <a href=http://tamkovich.com/tag/kamailio/>Kamailio</a> и OpenSIPS. Каждая из веток претендует считаться наследницей <a href=http://tamkovich.com/tag/openser/>OpenSER</a>-а. По моему мнению, из всех перечисленных продуктов, Kamailio обладает наибольшей пользовательской базой, а значит меньше шансов, что Ваши вопросы остануться без ответа. Недавно было объявлено о &laquo;совместной инициативе&raquo; проектов SER и Kamailio. Пока инициатива выглядит в виде централизованного сайта для двух проектов: <a href=http://sip-router.org>sip-router.org</a>, но видя любовь авторов к форкам, можно предположить, что рано или поздно будит мёрдж.
</p>
<p><center><br />
<img src=/wp-content/uploads/2010/06/ser.png ><br />
</center></p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/06/ser-openser-kamailio-opensips-sip-router/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Интеграция Asterisk 1.6.2 и Kamailio 3.0.x</title>
		<link>http://tamkovich.com/2010/06/asterisk-kamailio-integration/</link>
		<comments>http://tamkovich.com/2010/06/asterisk-kamailio-integration/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 15:59:15 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Asterisk]]></category>
		<category><![CDATA[ITSP]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1308</guid>
		<description><![CDATA[Обновился документ по интеграции Kamailio 3.0.x и Asterisk 1.6.2. Кроме того, что используются новые версии ПО, изменилась сама концепция интеграции. Ключевые тезисы новой схемы: Минимизация отклонений от стандартной конфигурации Asterisk-realtime. Вся аутентификация — внутри Kamailio. Все звонки, в т.ч. и локальные — проходят через Asterisk. Все media потоки — проходят через Asterisk. Обработка SIP сообщений [...]]]></description>
			<content:encoded><![CDATA[<p align=justify >Обновился <a href=http://kb.asipto.com/asterisk:realtime:kamailio-3.0.x-asterisk-1.6.2-astdb >документ</a> по интеграции Kamailio 3.0.x и <a href=http://tamkovich.com/asterisk/ >Asterisk</a> 1.6.2. Кроме того, что используются новые версии ПО, изменилась сама концепция интеграции. Ключевые тезисы новой схемы:</p>
<ul>
<li> Минимизация отклонений от стандартной конфигурации <a href=http://tamkovich.com/asterisk/ >Asterisk</a>-realtime.
<li> Вся аутентификация — внутри Kamailio.
<li> Все звонки, в т.ч. и локальные — проходят через <a href=http://tamkovich.com/asterisk/ >Asterisk</a>.
<li> Все media потоки — проходят через <a href=http://tamkovich.com/asterisk/ >Asterisk</a>.
<li> Обработка <a href=http://tamkovich.com/tag/sip/ >SIP</a> сообщений не связанных со звонками выполняется с помощью Kamailio.
</ul>
<p align=justify >Согласно предложенной схеме, регистрация выглядит следующим образом:</p>
<p><center><img src=/wp-content/uploads/2010/06/int-register.png ></center><br />
<span id="more-1308"></span></p>
<p align=justify >Аппарат А, отправляет запрос REGISTER и после успешной аутентификации регистрируется на Kamailio. Kamailio регистрируется на сервере <a href=http://tamkovich.com/asterisk/ >Asterisk</a> от имени клиента, указав в качестве котакта свой IP адрес. Таким образом при звонке с <a href=http://tamkovich.com/asterisk/ >Asterisk</a> к абоненту A, <a href=http://tamkovich.com/asterisk/ >Asterisk</a> отправит INVITE к Kamailio, а тот в свою очередь передаст его клиенту. Кстати о звонках, звонок между абонентами A и B выглядит следующим образом:</p>
<p><center><img src=/wp-content/uploads/2010/06/int-invite.png ></center></p>
<p align=justify >Для установки соединения между аппаратами A и B, аппарат A отправляет запрос INVITE по IP адресу сервера Kamailio. После успешной аутентификации, Kamailio отправляет INVITE к <a href=http://tamkovich.com/asterisk/ >Asterisk</a>. <a href=http://tamkovich.com/asterisk/ >Asterisk</a>, отправляет INVITE к абоненту B, однако в качестве контакта для абонента B указан IP адрес Kamailio. Получив INVITE от <a href=http://tamkovich.com/asterisk/ >Asterisk</a> для абонента B, Kamailio проверяет базу зарегистрированных пользователей (usrloc) и пытается перенаправить INVITE для абонента B по его фактическому адресу.</p>
<p align=justify >На мой взгляд: просто, элегантно, и, самое главное, масштабируемо. Я обычно использую несколько иную балансировку нагрузки, однако предложенная схема заслуживает самого тщательного изучения. Автор документа, Daniel-Constantin Mierla, обещает регулярно обновлять инструкцию, поддерживая её в актуальном состоянии.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/06/asterisk-kamailio-integration/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Kamailio v3.0.2</title>
		<link>http://tamkovich.com/2010/06/kamailio-v3-0-2/</link>
		<comments>http://tamkovich.com/2010/06/kamailio-v3-0-2/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 08:07:42 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1306</guid>
		<description><![CDATA[27 мая, как всегда, тихо и незаметно &#8211; обновился замечательный SIP сервер Kamailio (бывший OpenSER) до версии 3.0.2. Основные изменения: Исправлено падение TLS из-за некорректного выделения памяти. return() теперь работает внутри цикла while(). Исправлено падение mediaproxy, в случае когда ответ содержит больше media потоков чем оригинальный INVITE. Исправлено падение lib/srdb1, вызванное отсутствием проверки RES_ROW(res) на [...]]]></description>
			<content:encoded><![CDATA[<p align=justify >27 мая, как всегда, тихо и незаметно &#8211; обновился замечательный <a href=http://tamkovich.com/tag/sip/ >SIP</a> сервер Kamailio (бывший OpenSER) до версии 3.0.2. Основные изменения:
</p>
<ul>
<li> Исправлено падение TLS из-за некорректного выделения памяти.
<li> return() теперь работает внутри цикла while().
<li> Исправлено падение mediaproxy, в случае когда ответ содержит больше media потоков чем оригинальный INVITE.
<li> Исправлено падение lib/srdb1, вызванное отсутствием проверки RES_ROW(res) на NULL.
<li> Исправлено падение avp_copy() при использовании флага &#8216;g&#8217;.
<li> Исправлено падение в модуле carrierroute.
<li> Исправлена утечка памяти в модуле topoh.
</ul>
<p align=justify >
Довольного много падений для стабильной версии. Радует частота выхода исправленных версий — команда Kamailio взяла за правило выпускать релиз с исправлениями раз в 2 месяца и пока успешно следует ему. Так же хочу отметить, что все исправления, кроме выхода из цикла while() &#8211; касаются модулей. В ядре Kamailio серьёзных проблем вроде утечек памяти или падений — не исправлялось. Будем надеяться, что их там нет.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/06/kamailio-v3-0-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kamailio v3.0.1</title>
		<link>http://tamkovich.com/2010/03/kamailio-v3-0-1/</link>
		<comments>http://tamkovich.com/2010/03/kamailio-v3-0-1/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 06:11:00 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Разное]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[OpenSER]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=1101</guid>
		<description><![CDATA[8 марта, тихо и незаметно (c), вышел очередной релиз замечательного SIP сервера Kamailio, в прошлом известного как OpenSER. Для тех кто не в курсе, Kamailio это SIP сервер с открытым исходным кодом. Благодаря тому, что он не занимается обработкой медиа-потоков, Kamailio, по заявлениям авторов, способен обслуживать более 300 000 пользователей, совершающих звонки со скоростью свыше [...]]]></description>
			<content:encoded><![CDATA[<p><img src=/wp-content/uploads/2010/03/kamailio-rock-logo.jpg align=left ></p>
<p align=justify>
8 марта, тихо и незаметно (c), вышел очередной релиз замечательного <a href=http://tamkovich.com/tag/sip/ >SIP</a> сервера Kamailio, в прошлом известного как OpenSER. Для тех кто не в курсе, Kamailio это <a href=http://tamkovich.com/tag/sip/ >SIP</a> сервер с открытым исходным кодом. Благодаря тому, что он не занимается обработкой медиа-потоков, Kamailio, по заявлениям авторов, способен обслуживать более 300 000 пользователей, совершающих звонки со скоростью свыше 5000 звонков в секунду (в stateless режиме). Kamailio обладает множеством интересных возможностей, из наиболее интересных можно выделить: Поддержка всех транспортных протоколов (UDP, TCP, TLS и SCTP), поддержка IPv6, конвертация траспорта (например UDP в TLS), поддержка DNS SRV и ENUM, интеграция с net-snmp, CPL – Call Processing Language (RFC3880) и многое другое. Подробный список можно изучить <a href=http://www.kamailio.org/w/features/ >здесь</a>.
</p>
<p align=justify>
Kamailio v3.0.1 &#8211; это версия исправляющая ошибки обнаруженные в недавно вышедшей 3.0.0. За 2 месяца с момента выхода 3.0.0 в Kamailio внесено 44 изменения. Из серьёзных изменений можно выделить лишь исправление segfault-а при чтении некорректного конфигурационного файла. Рекомендую обновиться все пользователям Kamailio v3.0.0.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2010/03/kamailio-v3-0-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Building Telephony Systems with OpenSER</title>
		<link>http://tamkovich.com/2009/11/building-telephony-systems-with-openser/</link>
		<comments>http://tamkovich.com/2009/11/building-telephony-systems-with-openser/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 19:46:08 +0000</pubDate>
		<dc:creator>Сергей Тамкович</dc:creator>
				<category><![CDATA[Книги]]></category>
		<category><![CDATA[Kamailio]]></category>
		<category><![CDATA[OpenSER]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://tamkovich.com/?p=588</guid>
		<description><![CDATA[Наконец-то прочитал португальско-индусскую книгу Building Telephony Systems with OpenSER. Впечатление книга оставила двоякое. С одной стороны, в книге большое количество разнообразных ошибок (лексических, орфографических, опечаток в конфигурационных файлах и тому подобного) с другой стороны, других книг по SIP прокси &#8211; просто нет. Кроме проблем с орфографией, выделю ещё несколько моментов, которые мне не понравились. Книга [...]]]></description>
			<content:encoded><![CDATA[<p><img src=/wp-content/uploads/2009/11/openser.png align=left class="inlineimg" >
<p align=justify>Наконец-то прочитал португальско-индусскую книгу <a href=http://www.packtpub.com/building-telephony-systems-with-openser/book>Building Telephony Systems with OpenSER</a>. Впечатление книга оставила двоякое. С одной стороны, в книге большое количество разнообразных ошибок (лексических, орфографических, опечаток в конфигурационных файлах и тому подобного) с другой стороны, других книг по <a href=http://tamkovich.com/tag/sip/ >SIP</a> прокси &#8211; просто нет.
</p>
<p align=justify>
Кроме проблем с орфографией, выделю ещё несколько моментов, которые мне не понравились. Книга посвящена построению сети VoIP провайдера, на базе OpenSER/Kamailio. По мнению автора, OpenSER/Kamailio это основа сети <a href=http://tamkovich.com/tag/sip/ >SIP</a> провайдера, тогда как для <a href=http://tamkovich.com/asterisk/ >Asterisk</a>, отводится роль голосовой почты и шлюза в ТФОП. С таким подходом я не согласен. По моему мнению, время, когда провайдеры зарабатывали исключительно на терминации трафика &#8211; уходит в прошлое. Доля доходов от дополнительных видов обслуживания (голосовая почта, конференции, виртуальные частные АТС и т.п.) &#8211; растёт из года в год. Реализация ДВО с помощью OpenSER/Kamailio представляется мне неоправданно сложной и неестественной. С развитием <a href=http://tamkovich.com/asterisk/ >Asterisk</a> как мультисервисной платформы, единственным применением OpenSER/Kamailio в сети ITSP остаётся &#8211; балансирование нагрузки и, надо отдать должное, с этим он справляется превосходно.
</p>
<p><span id="more-588"></span></p>
<p align=justify>
К сожалению, в книге никак не затронут вопрос использования OpenSER/Kamailio в качестве диспетчера нагрузки (loadbalancer) и это &#8211; третий недостаток.
</p>
<p align=justify>
Не совсем понятно, на кого рассчитана данная книга? В предисловии написано:</p>
<blockquote><p>
This book is intended for Linux and networking professionals, who want to understand <a href=http://tamkovich.com/tag/sip/ >SIP</a> and OpenSER from a practical perspective, or are interested in IP telephony and call routing.
</p></blockquote>
<p>Совсем не понятно, зачем профессионалам объяснять со скриншотами процесс установки Debian. И сделано это, в ущерб разделу о протоколе <a href=http://tamkovich.com/tag/sip/ >SIP</a>. В главе &laquo;Introduction to <a href=http://tamkovich.com/tag/sip/ >SIP</a>&raquo; нет ни одного слова об основных методах протокола <a href=http://tamkovich.com/tag/sip/ >SIP</a> (REGISTER, INVITE, CANCEL и т.д.). Как можно опустить столь значимую информацию в пользу скриншотам с Debian &#8211; мне не ясно.
</p>
<p align=justify>
Ну и последнее, что сильно цепляется за глаза, это отсутствие в книге описания конфигурационного языка OpenSER/Kamailio и его основных команд. Из книги, вы никогда не узнаете, что делают команды lookup(&laquo;location&raquo;), fix_nated_register() и любых других.
</p>
<p align=justify>
Не смотря на все недостатки данной книги, рекомендую её к прочтению всем, кто профессионально занимается IP телефонией. Если у вас нет опыта работы с OpenSER/Kamailio эта книга, хоть и с натяжками, позволит вам составить своё впечатление об этом программном продукте.</p>
]]></content:encoded>
			<wfw:commentRss>http://tamkovich.com/2009/11/building-telephony-systems-with-openser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

