Введение в SIP для Java, C# и VB разработчиков

Добавлено 14 декабря 2011 в 18:56

SIP — протокол создания сессий

SIP (Session Initiation Protocol) был разработан для соединения людей и устройств для выполнения ими (возможно длительного) обмена информацией. Существующие протоколы, такие как HTTP и SMTP, не были специально разработаны для такой существенной человеческой деятельности, и поэтому SIP был создан, чтобы заполнить этот пробел. Однако SIP многое заимствует из этих двук протоколов: от шаблона обмена сообщениями, формата сообщения и кодирования из HTTP до схемы URI из SMTP.

В 2002 году проверенная версия стандарта SIP была оформлена Инженерным советом Интернет (IETF) как RFC3261. Из-за открытого характера процесса стандартизации IETF и того, что SIP основан на текстовом интерфейсе и имеет много общих черт с существующими спецификациями, данный протокол было легко понять, расширить и реализовать.

С момента своего появления SIP получил поддержку в качестве посредника при обмене мгновенными сообщениями (наприме, Windows Messenger) и VoIP (большинство известных платформ, кроме Skype).

Модули

Архитектура программных средств SIP состоит из нескольких соединенных модулей:

  • Агент пользователя (UA — User Agent) — модуль, который представляет конечного пользователя в клиентском устройстве. Он обычно работает в двух режимах: клиент агента пользователя (UAC — User Agent Client) отправляет исходные запросы и обрабатывает ответы; и сервер агента пользователя (UAS — User Agent Server) принимает запросы и отправляет ответы.
  • Прокси серверы привлекаются в маршрутизации SIP сообщений до правильной конечной точки. Фиксирующие прокси иногда используют агентов пользователей в логической структуре, называемой Back-To-Back-User-Agent
  • Серверы переадресации обеспечивают новый адрес или иной маршрут к получателю. Сервер может использовать сервер определения местоположения для сохранения информации о местоположении.
  • Регистратор действует как текущее хранилище информации о привязке клиента к сети.

Агент пользователя имеет тенденцию располагаться на устройстве пользователя. Остальные модули обеспечивают необходимые службы поддержки во многих сценариях.

Сообщения

SIP сообщения бывают двух видов:

  • запрос — отправляется от клиента к серверу и определяет операцию, запрашиваемую клиентом;
  • ответ — отправляется от сервера к клиенту и доставляет информацию о статусе текущего запроса.

Запрос

SIP запрос характеризуется как метод, очень похожий на HTTP запрос, и является ‘глаголом’, так как запрашивает действия, которые должны быть выполнены другими агентами пользователей и серверами. RFC3261 определяет шесть методов (первые шесть в таблице 1), а последующие стандарты определяют остальные методы расширения (начиная с INFO).

Таблица 1. Методы SIP.
МетодОписание
INVITEИспользуется для установки SIP сессии. Параметры сессии должны быть согласованы.
REGISTERАунтефицирует агента пользователя и передает текущее местоположение в сети.
BYEЗавершает открытую сессию.
ACKПодтверждает успешный ответ на INVITE. Третья часть “трехстороннего рукопожатия”.
CANCELОтменяет открытый запрос. BYE может быть использован, чтобы отменить (разрушить) существующий запрос.
OPTIONSЗапрашивает возможности корреспондентов.
Методы расширения
INFOПередает во время разговора связанную с сессией информацию. Используется редко.
MESSAGEИспользуется для передачи мгновенных сообщений.
NOTIFYПубликует результаты событий. Используется вместе с запросами SUBSCRIBE.
PRACKПодтверждение предварительного ответа (Provisional Response ACKnowledgment). Подтверждает получение предварительного ответа.
PUBLISHПубликует информацию о статусе. Используется для передачи статуса присутствия в службах мгновенных сообщений.
REFERМеханизм передачи запроса кому-то, более подходящему для его выполнения.
SUBSCRIBEИспользуется для запроса получения будующих запросов NOTIFY и PUBLISH.
UPDATEИзменяет параметры сессии в середине разговора.

Ответы

Сообщения SIP ответов всегда посылаются в ответ на запрос. С их помощью отправляются обновления статуса, подтверждения, инструкции и коды ошибок назад к UAC, который передает запросы. Ответы могут быть либо предварительными, либо окончательными, и каждый ответ должен быть идентифицирован по 3-значному коду.

Типы ответов

Было определено шесть классов ответов, выделенных в отдельные категории, используя 3-значный код. Первые пять заимствованы из HTTP, шестой является новым для SIP.

Таблица 2. Классы ответов.
КлассОписание
1xx
Предварительный
Подтверждает прием запроса и продолжение обработки. Предварительные ответы на INVITE никогда не подтверждаются запросом ACK.
2xx
Успех
Запрос был получен, обработан и применён.
3xx
Перенаправление
Предоставляет информацию о местоположении или альтернативные службы для попыток соединения.
4xx
Отказ запроса
Запрос содержит ошибку или не может быть обработан сервером.
5xx
Отказ сервера
Сервер не в состоянии выполнить запрос из-за внутренней ошибки.
6xx
Глобальный отказ
Нет службы, которая могла бы выполнить запрос.

Внутри каждого класса, цифровые коды ответов предопределены, некоторые из них скопированы из HTTP.

Таблица 3. Примеры кодов ответов.
КодРасшифровкаОписание
100Trying
Продолжение попытки
Следующий узел получил запрос.
180Ringing
Посылка вызова
Попытка оповещения пользователя.
182Queued
Поставлен в очередь
Временно недоступен. Запрос поставлен в очередь, а не отклонён.
200OKЗапрос выполнен успешно.
301Moved Permanently
Перемещен окончательно
Пользователь больше не доступен по адресу, указанному в URI запроса.
302Moved Temporarily
Перемещен временно
Повторить запрос на новый адрес, указанный в заголовке Contact.
400Bad Request
Плохой запрос
Невозможно понять или правильно обработать запрос.
401Unauthorised
Неавторизован
Запросу либо отказано в аунтефикации, либо требуется дополнительная информация.
403Forbidden
Запрещено
Сервер отказывается обработать запрос. Запрос не повторять.
404Not Found
Не найден
Сервер не может определить пользователя в своем домене.
408Request Timeout
Время ожидания истекло
Сервер не смог обработать запрос в разумные сроки.
415Unsupported Media
Неподдерживаемое медиа
Формат медиа не поддерживается сервером.
480Temporarily Unavailable
Временно недоступен
Вызываемый абонент временно недоступен.
485Ambiguous
Двусмысленный
Двусмысленный URI запроса.
486Busy Here
Занято
Вызываемый абонент в данный момент не хочет или не может принять входящий звонок.
500Server Internal Error
Внутренняя ошибка сервера
Сервер столкнулся с непредвиденным условием.
513Message Too Large
Слишком большое сообщение
Длина сообщения превысила заданное ограничение.
603Decline
Отклонен
Пользователь явно отказался принять запрос.

Поле заголовка Warning

Поле заголовка Warning используется для передачи дополнительной информации о состоянии ответа. Заголовок определяет 3-значный код от 300 до 399, имя хоста, а текст предупреждения.


Warning: 307 isi.edu "Session parameter 'foo' not understood".

Анатомия сообщения

Каждое SIP сообщение начинается со стартовой строки с последующей за ней последовательностью заголовков, которая отделяется от тела сообщения последовательностью символов возврата каретки и перевода строки (CRLF).

  • Стартовая строка — форматированная строка запроса для запросов или строка статуса для ответов.
  • Заголовки — именованные атрибуты, передающие дополнительную информацию о сообщении.
  • Раздельтельная строка — разделитель между заголовком и телом сообщения.
  • Тело — бинарная или текстовая полезная нагрузка. Обычно это протокол описания сессий SDP или текст сообщения.

Стартовая строка, строки всех заголовков, а также разделительная строка заканчиваются последовательностью символов [CRLF].

Стартовая строка

Стартовая строка передает тип сообщения и версию протокола. И для запроса (строка запроса), и для ответа (строка статуса) стартовая строка содержит три элемента, разделенных пробелами.

  • Строка запроса: содержит метод и URI и заканчивается версией протокола ("SIP/2.0").
    
    INVITE sip:bob@897s.aarhus.com SIP/2.0
  • Строка статуса: начинается версией протокола, после чего следует числовой код состояния, и завершается короткой текстовой расшифровкой.
    
    SIP/2.0 200 OK

Заголовки

Заголовки имеют такой же формат как и у типовых HTTP заголовков. Все они состоят из регистронезависимого имени в кодировке ASCII и двоеточия, за которым следует значение, которое иногда идет в кодировке UTF8 и обычно регистрозависимо. В каждом заголовке может быть один и более параметров, разделенных точкой с запятой, добавленных к значению и передающих дополнительные теги и функции.


  header-name: header-value(;parameter-name=parameter-value)*[CRLF]

Каждый заголовок может быть разделен на несколько строк, используя последовательности символов [CRLF][TAB или SPACE] (так называемое свёртывание). Более того, несколько заголовков с одинаковыми именами (например, Contact) могут появиться на отдельных строках или могут быть помещены в одну строку, разделенные запятыми. Например:


  Contact: <sip:alice@atlanta.com>
  Contact: <sip:alice1@chicago.com>

Может быть представлено так:


  Contact: <sip:alice@atlanta.com>, <sip:alice1@chicago.com>

Или, используя свёртывание:


  Contact: <sip:alice@atlanta.com>,
    <sip:alice1@chicago.com>

Тело сообщения

Тело сообщения описывает сессию (используя SDP) или содержит непрозрачный текст или бинарные данные, содержащие полезную нагрузку, связанную с сессией (например, с MIME типом или форматом сообщения). Тело сообщения может содержаться как в сообщениях запросов, так и в сообщениях ответов.

Поля заголовков

В следующих примерах Алиса совершает вызов Боба, используя его SIP URI, 'sip:bob@897s.aarhus.com'. Боб отвечает Алисе откликом, уведомляющим об успехе. Сообщение запроса INVITE в примере содержит SDP сообщение, на которое должен быть получен ответ вместе с ответом «200 OK».

Все примеры кода довольно независимы от языка программирования. Для тех, кто заинтересован в дальнейшем изучении SIP, в конце приводится список библиотек для Java, .NET и C++. И с небольшими изменениями весь код должен работать с любым из них (в данных примерах автор использовал библиотеку Konnetic SIP для C#).

Создание сообщения запроса

  1. Добавить строку запроса, которая указывает на сообщение запроса INVITE к аккаунту 'sip:bob@897s.aarhus.com'.
    
      Invite invite = new Invite(new SipUri("sip:bob@897s.aarhus.com"));
    
  2. Создать заголовок Via, который указывает получателю обратный путь.
    
      invite.ViaHeaders.Add(new ViaHeaderField("122.181.8.8:11506",
                            SipTransportProtocol.Udp));
    
  3. Создать адреса отправителя и получателя. В качестве SIP URI могут использоваться IP адреса, но рекомендуется применять полные доменные адреса. Возможно использование отображаемых имён. В целях безопасности заголовку From разрешается быть анонимным, если это необходимо.
    
      invite.From.Uri = new SipUri("sip:bob@897s.aarhus.com");
      invite.From.DisplayName = "Bob";
      invite.From.Tag = "769122";
      invite.To.Uri = new SipUri("sip:alice@ml99.odense.com");
      invite.To.DisplayName = "Alice";
    
  4. Создать уникальные идентификаторы для вызова и разговора. CallId — это уникальное значение для сессии. Последовательность Sequence увеличивается в последующих запросах. Набор To, From и Call-ID обеспечивает уникальный ключ для вызова.
    
      invite.CallId.CallId = "afh7989asdfhf@ml99.odense.com"; 
      invite.CSeq.Sequence = 3434534; 
      invite.CSeq.Method = SipMethod.Invite;
    
  5. Создать дополнительную контактную информацию об отправителе.
    
      invite.ContactHeaders.Add(new ContactHeaderField(
          new SipUri("sip:alice2@vejle.com")));                          
    
  6. И наконец, добавить описание содержимого сообщения. В данном примере контент сообщения не рассматривается.
    
      invite.ContentType.MediaType = "application"; 
      invite.ContentType.MediaSubType = "sdp"; 
      invite.ContentLength = 136;
    

Сообщение SIP запроса

В результате сообщение SIP запроса должно выглядеть подобно следующему:


INVITE sip:bob@897s.aarhus.com SIP/2.0
Via: SIP/2.0/UDP 124.191.8.8:11506
Max-Forwards: 70
To: Bob <sip:bob@897s.aarhus.com> 
From: Alice <sip:alice@odense.com>;tag=769122
Call-ID: afh7989asdfhf@ml99.odense.com
CSeq: 3434534 INVITE
Contact: <sip:alice2@vejle.com>
Content-Type: application/sdp
Content-Length: 136

Создание сообщения ответа

Если вы помните, в данном примере Боб отвечает Алисе откликом, уведомляющем об успехе. Сообщение — пример ответа «200 OK».

  1. Создать строку статуса, которая показывает, что запрос был успешен.
       
    Response okMessage = new Response(StandardResponseCode.Ok);
    
  2. Скопировать заголовок Via из сообщения запроса.
        
    okMessage.ViaHeaders.Add(new ViaHeaderField("122.181.8.8:11506", 
                                                SipTransportProtocol.Udp));
    
  3. Скопировать адресную информацию. Поля To и From остаются теми же, что и в оригинале, за исключением параметра tag в поле To. Они не меняются местами для ответа. Вы должны думать о них, как об оригинальных полях To и From.
        
    okMessage.From.Uri = new SipUri("sip:bob@897s.aarhus.com"); 
    okMessage.From.DisplayName = "Bob"; 
    okMessage.From.Tag = "769122"; 
    okMessage.To.Uri = new SipUri("sip:alice@ml99.odense.com"); 
    okMessage.To.DisplayName = "Alice";
    okMessage.To.Tag = "abgj67";
    
  4. Скопировать идентификатор из сообщения запроса.
        
    invite.CallId.CallId = "afh7989asdfhf@ml99.odense.com"; 
    invite.CSeq.Sequence = 3434534; 
    invite.CSeq.Method = SipMethod.Invite; 
    
  5. Добавить дополнительную контактную информацию. На этот раз для Боба.
        
    okMessage.ContactHeaders.Add(new ContactHeaderField(
        new SipUri("sip:bob2@vejle.com")));
    
  6. И наконец, добавить описание контента.
        
    okMessage.ContentType.MediaType = "application";
    okMessage.ContentType.MediaSubType = "sdp";
    okMessage.ContentLength = 132; 
    

Должен отметить, что хорошая библиотека предоставит API, который автоматизируют большую часть шаблонного кода, показанного выше. Например, копирование полей из запроса в ответ может быть реализовано в библиотеке.

Сообщение SIP ответа

В результате сообщение SIP ответа должно выглядеть подобно следующему:


SIP/2.0 200 OK
Via: SIP/2.0/UDP 124.191.8.8:11506
To: Bob <sip:bob@897s.aarhus.com>;tag=abgj67
From: Alice <sip:alice@odense.com>;tag=769122
Call-ID: afh7989asdfhf@mel99.odense.com
CSeq: 3434534 INVITE
Contact: <sip:bob2@vejle.com>
Content-Type: application/sdp
Content-Length: 132

Пример сценария установления соединения

В этом разделе подробно описывается процесс вызова между теми же агентами пользователей SIP, что рассмотрены выше, и которые могут использовать те же структуры сообщений. Показаны три этапа успешного вызова: начальная сигнализация, создание медиасессии и, в конце, завершение вызова.

Процесс вызова SIP
Алиса совершает SIP вызов Боба, обменивается с ним медиапакетами, затем Боб завершает вызов.

Установление сессии

  • UA Алисы отправляет сообщение INVITE на SIP адрес Боба(т.е. 'sip:bob@897s.aarhus.com'). Содержимое сообщения — сообщение в протоколе SDP, описывающее ожидаемый обмен медиаданными.
  • UA Боба принимает INVITE и отвечает сообщением «100 Trying».
  • Затем UA пытается привлечь к себе внимание Боба и одновременно с этим отправляет Алисе сообщение «180 Ringing».
  • Боб отвечает, и его UA отправляет сообщение «200 OK». «200 OK» содержит также подтверждающее SDP сообщение Боба.
  • В завершение, UA Алисы подтверждает получение ответа OK с помощью запроса ACK.
  • Медиапотоки установлены непосредственно между Алисой и Бобом.

На этот момент мы подготовили почву для другого протокола (например, RTP) для транспортировки медиаданных непосредственно между Алисой и Бобом без дальнейшего вмешательства SIP. Эта передача реализована на так называемом канальном или транспортном уровне, а SIP действует в рамках уровня управления и сигнализации.

Завершение сессии

В конце вызова SIP используется для завершения сессии. Если, например, вызов завершается Бобом, обмен будет выглядеть следующим образом:

  • Боб кладет трубку, и его UA инициирует завершение сессии передачей Алисе запроса BYE.
  • UA Алисы отвечает сообщением «200 OK».

В приведенном выше примере Алиса и Боб ведут обмен абстрактными медиаданными. Это может быть и голосовой вызов, и видео конференция, и сеанс обмена мгновенными сообщениями; процедура установления и закрытия соединения будет выглядеть точно так же.

API и библиотеки SIP

Список не является исчерпывающим, но по мнению автора статьи в нём представлено лучшее, с чем он сталкивался. Разумными критериями, используемыми для отбора хорошего SIP API, являются реализация поддержки строго типизированных полей заголовков, реализация SIP транзакций, инкапсуляция большинства внутренностей SIP.

Разумный критерий, используемый для хорошего SIP API, является ли он обеспечивает поддержку для строго типизи

Таблица 4. Рекомендуемые SIP стеки.
ЯзыкСсылкаОписание
JavaNIST's SIP LibraryСправочный API от National Institute of Standards and Technology.
C#, VB и т.д.Konnetic's SIP .NET LibraryХорошо документированные низкоуровневые SIP и SDP стеки.
C#, VB и т.д.Microsoft's Unified Comms ServerВысокоуровневые SIP, SDP и RTP стеки.
C++PJSIP SIP StackЛёгкий, но полностью реализованный и легко портируемый SIP стек.

Инструменты тестирования

Инструменты тестирования имеют важное значение, поскольку соблюдение стандарта необходимо для любого приложения взаимодействующего с другими SIP приложениями и серверами.

Таблица 5. Рекомендуемые инструменты тестирования SIP.
ИнструментОписание
SIPpГенератор SIP трафика от HP.
PROTOSПриложение тестирования от университета Оулу, Финляндия.
ETSI TS 102 027-2Список тестовых сценариев SIP вызовов.
Torture Tests“Пыточные” тесты.
WiresharkПожалуй, лучший сетевой анализатор из доступных.

Дополнительная литература

Некоторые из вышеперечисленных IETF нуждаются в комментариях. Не позвольте этому остановить вас. Большинство RFC написаны хорошо и доступно. Вы многое узнаете, просто прочитав первые 10 страниц.

Теги

C#C++ / CppIP телефонияJavaSIPVoIPПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.


  • 2020-01-28antzol

    Ну, статье всё-таки уже десять лет. Некоторые проекты могут успеть закрыться, но что-то еще живое.
    От Microsoft:
    - Lync SDK - https://docs.microsoft.com/...
    - UCMA - https://docs.microsoft.com/...
    PJSIP всё еще жив и доступен по ссылке.

  • 2020-01-28Сергей Яцутко

    ЭХ, ссылки все битые. И куда копать - не понятно совсем :(

  • 2016-12-19Василий Соколенко

    C#, VB и т.д. Konnetic's SIP .NET Library Хорошо документированные низкоуровневые SIP и SDP стеки.
    Не работает ссылка аналогично

  • 2016-12-18Василий Соколенко

    Java NIST's SIP Library Справочный API от National Institute of Standards and Technology.
    Нерабочая ссылка. http://www-x.antd.nist.gov/...