# Точка входа route{ # # Следующий условный оператор осуществляет проверку поля заголовка MaxForwards - счетчик «прыжков» маршрутизации. # Если его значение равно нулю, посылается ответ 483 и прекращается обработка данного пакета. # Помимо этого, функция mf_process_maxfwd_header() смотрит. а имеется ли вообще такой заголовок в пакете, если нет, # то он создается и устанавливается в заданное значение - в данном случае 10. if (!mf_process_maxfwd_header("70")) { sl_send_reply("483","Too Many Hops"); exit; } # Далее мы проверяем наличие тега у поля To, который показывает, относится ли данный пакет к какому-либо диалогу. if (has_totag()) { # Пакет OPTIONS, помимо собственно запроса доступных опций, обычно используется в качестве средства проверки соединения. # Следующая проверка служит для того, чтобы удостовериться, действительно ли пакет предназначен именно нашему прокси. if (is_method("OPTIONS") && uri==myself && (! uri=~"sip:.*[@]+.*")) { options_reply(); exit; } # Смотрим, есть ли в пакете указание, куда его маршрутизировать дальше. # Функция loose route() сама по себе очень многозначная (как и многие другие функции), и, если таковое указание имеется, # она действует в соответствии с секцией 16.12 RFC 3261 за некоторыми исключениями (о них лучше почитать в документации). if (loose_route()) { # В серьезных скриптах маршрутизации здесь и спрятана вся логика - например, # осуществляется аккаунтинг. Однако, поскольку скрипт у нас исключительно простой, # пакет мы просто маршрутизируем по направлению, которое в нем и задано. route(relay); } else { #В случае же, если пакет не содержит маршрута, мы смотрим, не является ли он пакетом ACK, # пришедшим в ответ на сообщение об ошибке, и переправляем его куда следует. if (is_method("ACK")) { if ( t_check_trans() ) { t_relay(); exit; } else { # Если же данный запрос ACK не принадлежит никакой транзакции, мы просто его игнорируем. exit; } } #В остальных же случаях мы отправляем сообщение с кодом "404", аналогичное подобному же в HTTP. sl_send_reply("404","Not here"); } exit; } #Обрабатываем запросы, не относящиеся к заданному диалогу. Запрос CANCEL мы не трогаем и пересылаем дальше. if (is_method("CANCEL")) { if (t_check_trans()) { t_relay(); } exit; } #Функция t check trans() тоже имеет двойное назначение - если запрос не относится ни к ACK, ни к CANCEL, # но относится к какой- то транзакции ретрансляции, она его ретранслирует дальше, что следующая строчка и делает. t_check_trans(); # Фильтруем пакеты, у которых есть поле Route, но не задано поле To (за исключением пакета ACK), и логируем о подобных попытках. t_check_trans(); #Если запрос адресован не нам, добавляем поле Record-Route для принудительной маршрутизации SIP-трафика через наш прокси. if (loose_route()) { xlog("L_ERR", "Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]"); if (!is_method("ACK")) { sl_send_reply("403", "Preloaded Route denied"); } } #Если в запросе не фигурирует URI, который хоть как-то относится к нашему серверу, мы его отправляем в route(relay). if (!is_method("REGISTER|MESSAGE")) { record_route(); } #Поддержку presence (сообщений о статусе присутствия абонента) тоже не реализуем, для чего отключаем методы. if (!uri==myself) { route(relay); } #Поддержку presence (сообщений о статусе присутствия абонента) тоже не реализуем, для чего отключаем методы. PUBLISH и SUBSCRIBE if (is_method("PUBLISH|SUBSCRIBE")) { sl_send_reply("503", "Service Unavailable"); exit; } #Обработка запроса REGISTER. Для упрощения скрипта мы даем возможность регистрироваться всем, безо всякой аутентификации. Кроме того, база местоположений по тем же соображениям временная, в настоящую БД ничего не пишется if (is_method("REGISTER")) { if (!save("location", "m")) { sl_reply_error(); } exit; } # Функция lookup() проверяет, есть ли у нас в базе местоположений данный пользователь. Если его нет, мы создаем новую транзакцию и возвращаем "404". # Опять же в серьезных скриптах здесь еще и проверяются поддерживаемые клиентом методы, чего мы не делаем. if (!lookup("location")) { t_newtran(); t_reply("404", "Not Found"); exit; } route(relay); } #Блок relay, который и обрабатывает все проходящие пакеты. route[relay] { #В случае INVITE мы смотрим, есть ли отрицательный результат транзакции, и, если есть, отправляем в соответствующий блок. if (is_method("INVITE")) { t_on_failure("fail"); } #Наконец, пропускаем пакет дальше и, если он почему-либо не проходит,выдаем ошибку "500". if (!t_relay()) { send_reply("500", "Internal Server Error"); } } # Блок fail, о котором было упомянуто выше. failure_route[fail] { #Если транзакция была отменена, мы просто выходим из блока. if (t_was_cancelled()) { exit; } }
~~socialite~~