Кратко
- Регистрация и состояние транспортного потока жили по разным правилам. Ответ на keepalive не продлевал автоматически binding, а устранимая ошибка его обновления не обязательно уничтожала рабочий путь.
- Несколько записей могли вести к одному экземпляру пользовательского агента. Для выбора маршрута требовалось различать AOR, постоянный instance-id и reg-id каждого потока.
- Код 430 означал отказ конкретного потока и позволял поиск другого. Любой иной окончательный ответ, кроме предусмотренных исключений, запрещал повторять тот же запрос к тому же экземпляру по запасному пути.
Ошибка обновления не всегда означала смерть пути
У регистрации был срок действия: её следовало обновлять, чтобы сопоставление адреса пользователя и Contact не стало бесконечным обещанием. У потока была другая задача — сохранять пригодный обратный транспорт от прокси к пользовательскому агенту. Эти два состояния могли разойтись.
RFC 5626, опубликованный в 2009 году, прямо допускал, что устранимая ошибка обновления — например 503 — не требует закрывать надёжное соединение, которое продолжает отвечать на keepalive. Это не превращало старую регистрацию в вечную. Это лишь не позволяло устранимому сбою одного механизма уничтожить технически живой ресурс другого до того, как правила восстановления решат его судьбу.
Возможна была и обратная картина. По UDP ответ STUN приходил, однако XOR-MAPPED-ADDRESS в нём уже отличался от прежнего. Сам факт ответа тогда становился доказательством отказа старого потока: за внешней парой адреса и порта больше не стояла та же ассоциация. «Что-то ответило» не равнялось «зарегистрированный путь остался прежним».
Эта аккуратность была нужна не ради терминологии. Если все зелёные индикаторы свести к одному признаку «онлайн», система не поймёт, что можно сохранить, что следует обновить и на каком уровне допустима повторная попытка.
Проверочное сообщение не доказывало доставку звонка
Keepalive работал до следующего SIP-hop. Он мог подтвердить реакцию transport peer или обновить NAT-состояние, но не подтверждал, что человек увидел INVITE, что приложение обработало его или что аудио прошло. Значение Flow-Timer задавало ожидание сервера по частоте с запасом, а не аренду гарантированной доступности на весь интервал.
Частый keepalive ускорял обнаружение отказа ценой батареи и серверной нагрузки. Несколько flows сокращали период, когда один незамеченный разрыв лишал устройство входящих запросов, но также увеличивали состояние. Восстановление использовало экспоненциальную задержку со случайным разбросом, причём базовое ожидание различалось в ситуациях, когда потеряны все пути и когда хотя бы один остался. Числа из RFC были значениями по умолчанию своего времени, а не универсальным современным нормативом.
RFC 6223 позже формализовал согласование SIP keepalive между соседними узлами отдельно для каждого направления через параметр Via keep. Документ особо подчёркивал, что не определяет повторное использование соединения. Поддерживать соседний транспорт и разрешать по нему произвольный обратный запрос — не одно решение.
Имя экземпляра, транспорт и право на обратный трафик не слились
RFC 5923 рассматривал TLS connection alias между соседями, способными инициировать соединения в обе стороны. Повторное использование зависело от аутентификации и решения принимающего узла. Открытый TLS-канал не становился автоматически универсальным обратным маршрутом. Для случаев, где направление открытия ограничено, область применения указывала на Outbound.
RFC 5627 отвечал на вопрос об адресации конкретной инстанции. При blind transfer обращение к AOR могло выбрать другой телефон или голосовую почту, хотя требовался аппарат, уже участвующий в разговоре. GRUU давал внешне используемый URI к этому экземпляру через домен. Он не был flow token edge и не сообщал, жив ли определённый транспорт.
В приложении B RFC 7118 браузерный SIP-клиент показывал границу особенно ясно. Не зная собственной локальной transport address, он мог при запрошенной и подтверждённой поддержке Outbound использовать случайное имя под .invalid в Via и Contact. Обратная сигнализация шла через WebSocket proxy и существующий flow. Это условие конкретного сценария, а не общая лицензия на бесполезные Contacts; сертификат сервера всё равно проверялся, а передача медиа оставалась вне документа.
Реестр параметров SIP IANA фиксирует коды, имена параметров и нормативные ссылки. Он не доказывает массового внедрения и не оценивает качество продуктов. Исторический результат скромнее и важнее: система научилась хранить несколько способов возврата к аппарату, не умножая сам аппарат и не отменяя уже полученный от него ответ.
REGISTER отвечал на один вопрос, INVITE задавал другой
В базовом SIP RFC 3261 связывал Address of Record, или AOR, с одним либо несколькими Contacts. Registrar принимал REGISTER, а location service предоставлял сопоставления прокси, который маршрутизировал новые запросы. Эти функции могли находиться в одном сервере, но смысл их оставался различным.
Ответ на REGISTER по надёжному транспорту возвращался по соединению, на котором пришёл запрос, пока соединение существовало. Поздний INVITE не был продолжением этого ответа. Это был новый запрос в обратную сторону. Телефон за NAT или межсетевым экраном мог открыть исходящую TCP- или TLS-сессию, но не принимать новую сессию, которую сервер попытался бы открыть к адресу из Contact.
Outbound использовал уже созданный телефоном flow. Для TCP это соединение; для UDP — двунаправленная ассоциация, определяемая адресами, портами и транспортным протоколом. Поэтому механизм нельзя сводить к удержанию TCP-сокета. Его смысл состоял в том, чтобы связать будущую доставку с конкретным ранее установленным путём, не предполагая доступности входящего транспорта, которого никто не создавал.
Домашний домен должен был помнить пограничный прокси
Телефон часто регистрировался не прямо у registrar. Первым узлом мог быть edge proxy, и будущему запросу требовалось пройти через него обратно. RFC 3327 ввёл Path: промежуточные прокси добавляли себя во время регистрации, полученный вектор сохранялся с binding и затем превращался в заранее заданный Route для запроса через домашний домен.
Path не создавал диалог из REGISTER и не был Record-Route с другим названием. Он также не давал любому отправителю право навязать произвольную цепочку. Маршрут работал в области домашнего домена и его согласованных правил, а потому нуждался в защите целостности и доверенной связи с регистрацией.
Первому edge этого всё ещё было недостаточно. Он должен был узнать точный flow к устройству. Outbound позволял вложить в Path защищённый от изменения flow token и признак ob. Токен был локальным средством восстановления ассоциации, а не глобальным именем человека, не постоянным адресом телефона и не доказательством права на учётную запись.
Из этого следовало правило очистки. Если транспорт достоверно закрыт — например, TCP-соединение завершилось или UDP получил соответствующую сетевую ошибку, — все bindings на этом flow должны стать недействительными независимо от AOR. Позднее повторное использование номера локального дескриптора не воскрешало прежнего получателя.
Постоянным был экземпляр, а не каждая строка
Чтобы аппарат мог держать несколько обратных путей, стандарт разделил два идентификатора. instance-id обозначал экземпляр пользовательского агента и сохранялся при перезагрузке или смене сети. reg-id различал одновременно зарегистрированные потоки этой инстанции. Binding сравнивался в контексте AOR, instance-id и reg-id.
После перезапуска аппарат вновь использовал ту же последовательность reg-id. На первый взгляд это похоже на нежелательное столкновение идентификаторов. На деле столкновение было намеренным: новая регистрация должна была заменить устаревшую запись той же логической роли. Бесконечно новые номера оставили бы в таблице старые пути, которые выглядели бы как дополнительные возможности доставки.
Contact при этом не исчезал. Он сохранялся и участвовал в построении target set. Изменилось другое: строкового сравнения Contacts стало недостаточно, чтобы определить число получателей. Прокси запрещалось одновременно помещать в target set более одного Contact для одной AOR и одной instance-id. Разные устройства под общей AOR по-прежнему могли получать вызовы; несколько путей одного устройства не должны были превращаться в искусственное разветвление на несколько аппаратов.
Число регистраций поэтому не отвечало на вопрос о числе телефонов. Оно тем более не доказывало число пользователей или независимых зон отказа. Две записи могли различаться лишь путём к одному и тому же экземпляру.
430 ограничивал неисправность одним потоком
В примере спецификации телефон зарегистрирован через два edge. Один из них аварийно завершается и запускается снова. Новый INVITE приходит до того, как сам телефон заметил потерю прежнего flow. Перезапущенный edge не может восстановить токен и отвечает 430 Flow Failed.
Прокси AOR удаляет испорченный binding и ищет другой для той же AOR и instance-id с иным reg-id. Второй edge получает запрос; для нового диалога он добавляет себя в Record-Route. Позже телефон исправляет первую регистрацию, сохраняя reg-id, но получая новый flow token.
Это пример из раздела 9.3 стандарта, а не документированный инцидент оператора. Он не измеряет время восстановления и не обещает незаметно перенести любой уже существующий диалог. Для части маршрутизации внутри диалога спецификация оставляла процедуры edge за пределами обязательного алгоритма. Узкий вывод надёжнее: прокси мог обнаружить смерть пути и спасти новый запрос раньше локального детектора телефона.
430 не означал исчезновение аккаунта, отказ пользователя или обрыв медиапотока. Код предназначался для обмена между edge и авторитетным прокси; пользовательский агент не должен был его получать и при получении трактовал его как 400. Изменённый flow token требовал отдельной реакции, для которой рекомендовался 403. Разные причины оставались разными именно для того, чтобы запасной путь не стал безусловным повтором.
Окончательный ответ был командой остановиться
После 430 прокси мог выбрать другой binding того же экземпляра. После окончательного ответа действовало противоположное правило. Если ответ не был 408 или 430, ту же заявку нельзя было отправлять другой цели, представляющей ту же AOR и instance-id. Устройство уже ответило.
Исключения и область правила нельзя опускать. Оно не запрещало будущий новый звонок, не описывало все повторные попытки в каждом протоколе и не отменяло обычное SIP-разветвление между действительно разными устройствами. Оно ограничивало один запрос, одну логическую инстанцию и её альтернативные маршруты.
Тем самым Outbound различал недоставленное и уже рассмотренное. Первый случай мог оправдать обход. Во втором обход превратил бы отказ или иной результат устройства в повод спросить его ещё раз. Резервирование стало безопаснее не только потому, что появилось больше путей, но и потому, что возникло основание не использовать лишний путь.
Обзор для участников
Подробный контекст профиля
Войдите с подходящим уровнем подписки, чтобы открыть полный обзор и примечания к источникам.
Только для Стратегического сообщества
Стратегическое сообщество
Открыто всем читателям. Вступите и войдите, чтобы открыть обзоры профилей.
Вступить в Стратегическое сообществоТолько для Альянса лидеров
Альянс лидеров
Для проверенных владельцев IP-активов и руководителей. Войдите, чтобы открыть обзоры Альянса.
Вступить в Альянс лидеров
