Пример RTP сети с оконечными системами, смесителями и трансляторами
Рисунок 4.4.9.2.3 Пример RTP сети с оконечными системами, смесителями и трансляторами
Некоторый набор смесителей и трансляторов представлен на Рисунок 4.4.9.2.3. Здесь показано их влияние на SSRC и CSRC-идентификаторы. Оконечные системы обозначены символами ES и выделены желтым цветом. Трансляторы обозначены буквами TRS (на рисунке овалы голубого цвета) и смесители обозначены как MUX (прямоугольники сиреневого цвета). Запись "M1:13(1,17)" обозначает пакет отправленный смесителем MUX1, который идентифицируется случайным значением SSRC 13 и двумя CSRC-идентификаторами 1 и 17, скопированными с SSRC-идентификаторов пакетов оконечных систем ES1 и ES2.
Последовательное включение смесителей
В RTP-сессии могут быть задействованы несколько смесителей и трансляторов, как это показано на Рисунок 4.4.9.2.3. Если два смесителя включены последовательно, так как MUX2 и MUX3, пакеты полученные смесителем могут быть уже объединены и включать CSRC-список со многими идентификаторами. Cмеситель (MUX3) должен формировать CSRC-список для исходящих пакетов, используя CSRC-идентификаторы уже смешанных входных пакетов (выход MUX2) и SSRC-идентификаторы несмешанных входных пакетов, поступивших от ES9 (E:36). Это отмечено на рисунке для выходных пакетов смесителя MUX3 как M3:99(9,11,36). Если число идентификаторов в списке CSRC превышает 15, остальные не могут быть туда включены.
SSRC-идентификаторы в RTP-заголовках и в различных полях RTCP-пакетов являются случайными 32-битовыми числами, которые должны быть уникальными в рамках RTP-сессии. Очень важно, чтобы одни и те же числа не были использованы несколькими участниками сессии.
Недостаточно использовать в качестве идентификатора локальный сетевой адрес (такой как IPv4), так как может быть не уникальным. Так как RTP трансляторы и смесители допускают работу с сетями, использующими различные адресные пространства, это допускает их случайное совпадение с большей вероятностью, чем в случае использования случайных чисел.
Не приемлемо также получать идентификаторы SSRC путем простого обращения к функции random() без тщательной инициализации.
Так как идентификаторы выбраны случайным образом, существует малая, но конечная вероятность того, что два или более источников выберут одно и то же число. Столкновение более вероятно, если все источники стартуют одновременно. Если N число источников, а L длина идентификатора (в нашем случае, 32 бита), вероятность того, что два источника независимо выберут одно и то же значение (для больших N [8]) составляет 1 - exp(-N2 / 2(L+1)). Для N=1000, вероятность примерно равна 10-4.
Типовое значение вероятности столкновения много меньше худшего случая, рассмотренного выше. Рассмотрим случай, когда новый источник подключается к RTP-сессии, в которой все остальные источники уже имеют уникальные идентификаторы. Если N равно числу источников, а L длина идентификатора, вероятность столкновения равна N / 2L. Для N=1000, вероятность составит около 2*10-7.
Вероятность столкновения уменьшается еще больше в случае, когда новый источник получает пакеты других участников до того, как передаст свой первый пакет. Если новый источник отслеживает идентификаторы других участников, он легко может устранить вероятность конфликта.
Преодоление столкновений и детектирование петель
Хотя вероятность столкновения идентификаторов SSRC довольно мала, все RTP реализации должны быть готовы обнаруживать столкновения и предпринимать адекватные меры для их преодоления. Если источник обнаруживает в какой-либо момент, что другой источник использует тот же идентификатор SSRC, он посылает пакет RTCP BYE для старого идентификатора и выбирает новый. Если получатель обнаруживает, что два других источника имеют равные идентификаторы (столкновение), он может воспринимать пакеты от одного и игнорировать от другого до тех пор, пока это не будет зарегистрировано отправителями или CNAME.
Так как идентификаторы уникальны, они могут использоваться для детектирования петель, которые могут создаваться смесителем или транслятором. Петля приводит к дублированию данных и управляющей информации:
Транслятор может некорректно переадресовать пакет некоторой мультикастинг-группе, откуда этот пакет получен.
Это может быть сделано непосредственно или через цепочку трансляторов. В этом случае один и тот же пакет появится несколько раз, приходя от разных сетевых источников.
Два транслятора некорректно поставленные в параллель, т.е., с одними и теми же мультикастными группами на обеих сторонах будут направлять пакеты от одной мультикастной группы к другой. Однонаправленные трансляторы могут создать две копии; двунаправленные трансляторы могут образовать петлю.
Смеситель может замкнуть петлю путем посылки пакета по адресу, откуда он был получен. Это может быть выполнено непосредственно, через смеситель или через транслятор.
Источник может обнаружить, что его собственный пакет движется по кругу, или что пакеты других источников осуществляют циклическое движение.
Оба вида петель и столкновения приводят к тому, что пакеты приходят с тем же самым SSRC-идентификатором, но с разными транспортными адресами, которые могут принадлежать оконечной или какой-то промежуточной системе. Следовательно, если источник меняет свой транспортный адрес, он должен также выбрать новый SSRC-идентификатор с тем, чтобы ситуация не была интерпретирована, как зацикливание. Петли или столкновения, происходящие на дальней стороне транслятора или смесителя, не могут быть детектированы с использованием транспортного адреса источника, если все копии пакетов идут через транслятор или смеситель. Однако, столкновения могут быть детектированы, когда фрагменты двух RTCP SDES пакетов содержат равные SSRC-идентификаторы, но разные коды CNAME (см. описание протокола RTCP).
Для того чтобы детектировать и устранять конфликты, реализации RTP должны содержать алгоритм, аналогичный описанному ниже. Он игнорирует пакеты от нового источника, которые входят в противоречие с работающим источником. Алгоритм разрешает конфликты с SSRC-идентификаторами участников путем выбора нового идентификатора и посылки RTCP BYE для старого. Однако, когда столкновение вызвано зацикливанием собственных пакетов участников сессии, алгоритм выбирает новый идентификатор только раз и после этого игнорирует пакеты от транспортного адреса, вызвавшего зацикливание.
Это требуется для того, чтобы избежать потока пакетов BYE.
Этот алгоритм зависит от равенства транспортных адресов для RTP и RTCP пакетов источника. Алгоритм требует модификации приложений, которые не отвечают этому ограничению.
Этот алгоритм требует наличия таблицы транспортных адресов источников, упорядоченных по их идентификаторам. В таблицу заносятся адреса, откуда данный идентификатор был впервые получен. Каждый SSRC или CSRC идентификатор, полученный с информационным или управляющим пакетом ищется в этой таблице, для того чтобы корректно обработать полученные данные. Для управляющих пакетов каждый элемент с его собственным SSRC, например, фрагмент SDES, требует отдельного просмотра. SSRC в сообщениях-отчетах составляют исключение. Если SSRC или CSRC не найдены, создается новая запись в таблице. Эти записи в таблице удаляются, когда приходит пакет RTCP BYE с соответствующим кодом SSRC, или когда достаточно долго не приходит вообще никаких пакетов.
Для того чтобы отслеживать зацикливание собственных пакетов участников, необходимо также завести отдельный список транспортных адресов источников, которые считаются конфликтными. Заметим, что это должен быть короткий список, обычно пустой. Каждый элемент этого списка хранит адрес источника и время, когда был получен последний конфликтный пакет. Элемент может быть удален из списка, когда за время 10 периодов посылки RTCP сообщений-отчетов не прибыло ни одного конфликтного пакета.
Предполагается, что собственные идентификаторы и состояния участников записаны в таблицу идентификаторов источников.
IF SSRC или CSRC-идентификатор не найден в таблице идентификаторов источников:
THEN создать новую запись и внести туда транспортный адрес источника и SSRC или
CSRC вместе с кодом состояния.
CONTINUE (продолжить) обычную процедуру обработки.
Идентификатор найден в таблице
IF транспортный адрес источника из пакета совпадает с одним из записанных в таблице:
THEN CONTINUE Продолжить обычную процедуру обработки.
Обнаружено столкновение идентификаторов или зацикливание
IF идентификатор источника не совпадает с собственным идентификатором участника:
THEN IF идентификатор источника совпадает с тем, что содержится в фрагменте RTCP SDES содержащем элемент CNAME, который отличается от CNAME из рекорда таблицы:
THEN (опционно) Случилось столкновение посторонних идентификаторов.
ELSE (опционно) Случилось зацикливание.
ABORT Прервать обработку информационного или управляющего пакета.
Столкновение для идентификатора участника или зацикливание его пакетов
IF транспортный адрес найден в списке конфликтных адресов:
THEN IF идентификатор источника не найден во фрагменте RTCP SDES, содержащем CNAME, или если CNAME принадлежит участнику:
THEN (опционно) случилось зацикливание собственного трафика.
Записать текущее время в соответствующую запись таблицы конфликтных адресов.
ABORT (прервать) обработку информационного или управляющего пакета.
Зафиксировать факт столкновения.
Внести новую запись в таблицу конфликтных адресов и зафиксировать время записи.
Послать пакет RTCP BYE с идентификатором SSRC.
Выбрать новый идентификатор.
Внести новую запись в таблицу идентификаторов источников со старым SSRC, транспортным адресом источника обработанного пакета.
CONTINUE Продолжить обычную процедуру обработки.
В этом алгоритме все пакеты от вновь конфликтующих источников будут игнорироваться, а пакеты от исходного источника будут приниматься. Если в течение достаточно протяженного периода времени пакеты от исходного источника не приходят, соответствующая запись в таблице будет аннулирована.
Когда из-за столкновения выбран новый SSRC-идентификатор, кандидат-идентификатор должен быть сверен с содержимым таблицы идентификаторов. Если такой код там уже имеется, должен быть выбран другой кандидат и процедура сверки повторена.
Зацикливание информационных мультикастинг-пакетов может вызвать сильную перегрузку сети. Все смесители и трансляторы должны реализовывать алгоритм детектирования зацикливания с тем, чтобы немедленно прервать этот опасный процесс.
Это должно уменьшить лишний трафик. Однако, в крайних случаях, где смеситель или транслятор не прерывают зацикливание, может быть необходимо для оконечных систем прервать передачу.
Когда необходимо шифрование RTP или RTCP, все октеты будут инкапсулированы в одну дейтограмму нижележащего уровня и зашифрованы как единое целое. Для RTCP в начало последовательности перед шифрованием добавляется 32-битное случайное число, чтобы предотвратить возможные атаки. В случае RTP никаких префиксов не требуется, так как порядковый номер и временная метка и без того являются случайными числами.
Алгоритмом шифрования по умолчанию является DES (Data Encryption Standard), работающий в режиме CBC (Cipher Block Chaining), как это описано в RFC 1423 [9], за исключением того, что используется заполнение кратное 8 октетам. Инициализационный вектор равен нулю, так как для RTP-заголовка используются случайные числа. Более подробно о векторах инициализации можно прочесть в [10]. Приложения, которые используют шифрование должны поддерживать алгоритм DES в режиме CBC. Этот метод выбран потому, что он показал на практике свою эффективность при работе с аудио и видео приложениями в Интернет. Возможно применение и других криптографических средств.
В качестве альтернативы шифрованию на уровне RTP, можно определить дополнительные типы поля данных для шифрованных полей данных в профайлах. Этот метод позволяет шифровать только данные, в то время как заголовки остаются незашифрованными. Это может оказаться полезным для реализации шифрования и дешифрования.
Для обеспечения демультиплексирования RTP полагается на нижележащий протокольный уровень. Для UDP и сходных с ним протоколов, RTP использует четные номера портов, а соответствующие RTCP-потоки используют нечетные номера портов. Если приложению предлагается использовать нечетный номер RTP-порта, этот номер должен быть заменен на ближайший четный меньше исходного.
Информационные RTP-пакеты не имеют поля длины или каких-либо других средств ограничения размеров пакета, по этой причине RTP полагается на нижележащий протокол при задании размера поля данных.
Максимальная длина RTP- пакетов ограничена размером используемых транспортных пакетов (например, UDP).
Если RTP-пакеты переносятся посредством протокола, который поддерживает поточный метод передачи, должен быть определен механизм вложения. Механизм вложения должен быть детализован и в случае, когда транспортный протокол использует в поле данных заполнители.
Механизм вложения может быть определен в профайле даже в случае, когда для транспортировки RTP используется не поточный протокол, это позволяет укладывать несколько RTP-пакетов в одну дейтограмму транспортного протокола (например, UDP). Передача нескольких RTP-пакетов в одном транспортном уменьшает издержки, связанные с заголовком и может упростить синхронизацию различных потоков.
Константы, определяющие тип данных (PT) RTP-пакета, задаются профайлом а не самим протоколом. Однако, значение октета RTP-заголовка, который содержит бит(ы) маркера не должно ни при каких обстоятельствах равняться 200 и 201 (десятичные), для того чтобы отличить RTP-пакеты от RTCP-пакетов типа SR и RR.
Использование протокола RTP в различных приложениях может предъявлять различные требования. Адаптация протокола к этим требованиям осуществляется путем выбора определенных параметров, использования различных расширений (см. Рисунок 4.4.9.2.2) или путем вариации формата на основе профайлов. Типовое приложение использует только один профайл. Спецификация формата поля данных определяет то, например, как, закодированный видеосигнал (H.261) должен переноситься RTP-пакетами.
В рамках RTP-стандарта определены следующие элементы поля данных (этот список не следует рассматривать, как окончательный):
Заголовок поля данных RTP. Октет RTP заголовка, содержащий маркер тип поля данных, может быть переопределен с помощью профайла (например, можно изменить число маркерных битов).
Типы поля данных. Профайл обычно определяет набор форматов поля данных (напр., типов кодирования исходных данных) и соответствие между этими форматами и кодами типа поля данных.
Для каждого описанного типа поля данных должна быть определена частота временных меток.
Дополнения к заголовку RTP. К стандартному RTP-заголовку могут быть добавлены новые поля, расширяющие функциональность приложения.
Расширения заголовка RTP. Структура содержимого первых 16 бит расширения RTP-заголовка должна быть определена профайлом (см. Рисунок 4.4.9.2.2).
Безопасность. Профайл может специфицировать, какие услуги и алгоритмы безопасности должно обеспечить приложение.
Установка соответствия между строкой и ключом. Профайл может специфицировать, какому ключу шифрования соответствует введенный пользователем пароль.
Нижележащий протокол. Определяется нижележащий транспортный протокол, который служит для пересылки RTP-пакетов.
Транспортное соответствие. Соответствие RTP и RTCP адресам транспортного уровня, например, UDP-портам.
Инкапсуляция. Инкапсуляция RTP-пакетов может быть определена для того, чтобы позволить транспортировку нескольких RTP-пакетов в одной дейтограмме нижележащего протокола.
Не предполагается, что для каждого приложения требуется свой профайл. В пределах одного класса приложений целесообразно использовать расширения одного и того же профайла. Простое расширение, такое как введение дополнительного типа поля данных или нового типа RTCP-пакета, может быть выполнено путем регистрации их через комитет по стандартным числам Интернет и публикации их описаний в приложении к профайлу.
Алгоритмы работы отправителя и получателя RTP-пакетов описаны в RFC-1889 на примере кодов, написанных на языке СИ.
Нижеприведенные определения заимствованы целиком из RFC, ссылка на который приведена в начале данного раздела. Все цифра представлены в формате, где первым является старший октет. Предполагается, что битовые поля размещаются без заполнителей в том же порядке, что и октеты.
/*
* rtp.h -- Файл заголовка RTP (RFC 1889)
*/
#include <sys/types.h>
/*
* Нижеприведенные определения предполагают 32-битовое представление, а в случаях
* 16- или 64-битового представлений необходимы соответствующие модификации.
*/
typedef unsigned char u_int8;
typedef unsigned short u_int16;
typedef unsigned int u_int32;
typedef short int16;
/*
* Текущая версия протокола.
*/
#define RTP_VERSION 2
#define RTP_SEQ_MOD (1<<16)
#define RTP_MAX_SDES 255 /* максимальная длина текста для SDES */
typedef enum {
RTCP_SR = 200,
RTCP_RR = 201,
RTCP_SDES = 202,
RTCP_BYE = 203,
RTCP_APP = 204
} rtcp_type_t;
typedef enum {
RTCP_SDES_END = 0,
RTCP_SDES_CNAME = 1,
RTCP_SDES_NAME = 2,
RTCP_SDES_EMAIL = 3,
RTCP_SDES_PHONE = 4,
RTCP_SDES_LOC = 5,
RTCP_SDES_TOOL = 6,
RTCP_SDES_NOTE = 7,
RTCP_SDES_PRIV = 8
} rtcp_sdes_type_t;
/*
* Заголовок RTP-пакета
*/
typedef struct {
unsigned int version:2; /* версия протокола */
unsigned int p:1; /* флаг заполнителя */
unsigned int x:1; /* Флаг расширения заголовка */
unsigned int cc:4; /* число CSRC */
unsigned int m:1; /* Бит маркера */
unsigned int pt:7; /* тип поля данных */
u_int16 seq; /* номер по порядку */
u_int32 ts; /* временная метка */
u_int32 ssrc; /* источник синхронизации */
u_int32 csrc[1]; /* опционный список CSRC */
} rtp_hdr_t;
/*
* Общее слово RTCP-заголовка
*/
typedef struct {
unsigned int version:2; /* версия протокола */
unsigned int p:1; /* флаг заполнителя */
unsigned int count:5; /* варьируется в зависимости от типа пакета */
unsigned int pt:8; /* тип пакета RTCP */
u_int16 length; /* Длина пакета в словах */
} rtcp_common_t;
/*
* Маска версии, бита заполнителя и типа пакета
*/
#define RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe)
#define RTCP_VALID_VALUE ((RTP_VERSION << 14) | RTCP_SR)
/*
* Блок отчета о приеме
*/
typedef struct {
u_int32 ssrc; /* Источник, для которого составлен отчет */
unsigned int fraction:8; /* доля потерянных пакетов с момента последнего SR/RR */
int lost:24; /* полное число потерянных пакетов */
u_int32 last_seq; /* номер последнего полученного пакета */
u_int32 jitter; /* разброс времени прихода пакетов */
u_int32 lsr; /* последний SR-пакет от этого источника */
u_int32 dlsr; /* задержка с момента последнего SR пакета */
} rtcp_rr_t;
/*
* элемент SDES
*/
typedef struct {
u_int8 type; /* тип элемента (rtcp_sdes_type_t) */
u_int8 length; /* Длина элемента (в октетах) */
char data[1]; /* текст */
} rtcp_sdes_item_t;
/*
* One RTCP packet
*/
typedef struct {
rtcp_common_t common; /* общий заголовок */
union {
/* sender report (SR) */
struct {
u_int32 ssrc; /* Отправитель, генерирующий этот отчет */
u_int32 ntp_sec; /* временная метка NTP */
u_int32 ntp_frac;
u_int32 rtp_ts; /* временная метка RTP */
u_int32 psent; /* послано пакетов */
u_int32 osent; /* послано октетов */
rtcp_rr_t rr[1]; /* список переменной длины */
} sr;
/* Отчет о приеме (RR) */
struct {
u_int32 ssrc; /* приемник, формирующий данный отчет */
rtcp_rr_t rr[1]; /* список переменной длины */
} rr;
/* описание источника (SDES) */
struct rtcp_sdes {
u_int32 src; /* первый SSRC/CSRC */
rtcp_sdes_item_t item[1]; /* список элементов SDES */
} sdes;
/* BYE */
struct {
u_int32 src[1]; /* список источников */
/* can't express trailing text for reason */
} bye;
} r;
} rtcp_t;
typedef struct rtcp_sdes rtcp_sdes_t;
/*
* Информация состояния источников
*/
typedef struct {
u_int16 max_seq; /* наибольший зарегистрированный номер */
u_int32 cycles; /* shifted count of seq. number cycles */
u_int32 base_seq; /* основной порядковый номер */
u_int32 bad_seq; /* последний 'плохой' порядковый номер + 1 */
u_int32 probation; /* sequ. packets till source is valid */
u_int32 received; /* пакетов получено */
u_int32 expected_prior; /* пакет, ожидаемый в последнем интервале */
u_int32 received_prior; /* пакет, полученный за последний интервал */
u_int32 transit; /* относительное время передачи для предыдущего пакета */
u_int32 jitter; /* оценка временного разброса */
/* ... */
} source;
Получатель RTP-пакета должен проверить корректность заголовка. Здесь следует учитывать, что пакет может быть зашифрован. Если пакет не пройдет данную проверку (например, неверно дешифрован, ошибка в адресе или обнаружен неизвестный тип поля данных), должно быть выработано соответствующее сообщение.
Ограниченная проверка допустима только для нового источника:
В поле версии RTP должен быть записан код 2.
Тип поля данных должен быть из числа известных, в частности он не должен быть равным SR или RR.
Если бит P=1, тогда последний октет пакета должен содержать правильное число октетов, в частности оно должно быть меньше полной длины пакета минус размер заголовка.
Бит X должен быть равен нулю, если профайл не указывает на использование механизма расширения. В противном случае длина поля расширения должна быть меньше полной длины пакета минус длина стандартного заголовка вместе с заполнителем.
Длина пакета должна согласовываться с CC и типом поля данных (если длина поля данных известна).
Последние три проверки достаточно сложны и не всегда возможны. Если SSRC-идентификатор в пакете соответствует одному из полученных ранее, тогда пакет вероятно корректен и следует проверить то, что его порядковый номер лежит в нужном диапазоне. Если SSRC-идентификатор ранее не встречался, тогда данный пакет может рассматриваться некорректным до тех пор, пока не будет получено несколько таких последовательно пронумерованных пакетов.
Программа update_seq, приведенная ниже гарантирует, что источник декларирован правильно после получения MIN_SEQUENTIAL последовательно пронумерованных пакетов. Она также проверяет номера пакетов SEQ и актуализует состояние источника пакетов в структуре, на которую указывает S.
Когда новый источник дает о себе знать впервые (т.е. его SSRC-идентификатор отсутствует в таблице), и для описания его состояния выделено место в памяти, S->probation должно быть сделано равным числу последовательных пакетов, которые должны быть зарегистрированы до того, как источник будет объявлен легальным (параметр MIN_SEQUENTIAL ), а переменной s->max_seq присваивается значение SEQ-1. s->probation помечает источник как еще нелегальный, так что описание его состояния может быть выброшено после короткой выдержки.
После того как источник признан легальным, номер по порядку считается корректным, если он не больше чем на MAX_DROPOUT впереди S->max_seq и не больше на MAX_MISORDER после.
В противном случае возвращается нуль, что означает неудачу проверки, а плохой последовательный номер запоминается. Если номер очередного полученного пакета имеет следующий номер по порядку, то он рассматривается как начало новой последовательности (возможно источник рестартовал). Так как при этом теряется много циклов, статистика потерь пакетов сбрасывается.
Приведенные типовые значения параметров базируются на максимальном времени сбоя нумерации равном 2 секундам при скорости 50 пакетов/сек и времени таймаута 1 минута. Параметр таймаута MAX_DROPOUT должен соответствовать небольшой доле от 16-битового диапазона нумерации. Таким образом, после рестарта новый номер пакета с большой вероятностью не должен попасть в допустимый диапазон.
void init_seq(source *s, u_int16 seq)
{
s->base_seq = seq - 1;
s->max_seq = seq;
s->bad_seq = RTP_SEQ_MOD + 1;
s->cycles = 0;
s->received = 0;
s->received_prior = 0;
s->expected_prior = 0;
/* other initialization */
}
int update_seq(source *s, u_int16 seq)
{
u_int16 udelta = seq - s->max_seq;
const int MAX_DROPOUT = 3000;
const int MAX_MISORDER = 100;
const int MIN_SEQUENTIAL = 2;
*
* Источник нелегален до тех пор, пока не будет получено MIN_SEQUENTIAL пакетов
* с последовательно нарастающими номерами.
*/
if (s->probation) {
/* пакет соответствует последовательности */
if (seq == s->max_seq + 1) {
s->probation--;
s->max_seq = seq;
if (s->probation == 0) {
init_seq(s, seq);
s->received++;
return 1;
}
} else {
s->probation = MIN_SEQUENTIAL - 1;
s->max_seq = seq;
}
return 0;
} else if (udelta < MAX_DROPOUT) {
/* в порядке, с допустимым зазором */
if (seq < s->max_seq) {
/*
* Порядковый номер переполнен – начинаем новый 64K цикл.
*/
s->cycles += RTP_SEQ_MOD;
}
s->max_seq = seq;
} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
/* порядковый номер изменился слишком сильно */
if (seq == s->bad_seq) {
/*
* Два последовательных пакета – предполагается, что другая сторона рестартовала, не
* предупредив нас об этом. re-sync (т.е., считаем, что получили первый пакет).
*/
init_seq(s, seq);
}
else {
s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
return 0;
}
} else {
/* задублированные пакеты или пакеты с перепутанным порядком прихода */
}
s->received++;
return 1;
}
Проверка корректности может быть и жестче, требуя более двух пакетов с последовательными номерами подряд. Недостатком такого подхода будут трудности, связанные с каналами, где вероятность потери пакета велика. Однако, так как проверка корректности заголовка RTCP-пакета достаточно строга, можно ограничиться требованием двух последовательных информационных пакетов. Если начальная потеря данных в течение нескольких секунд приемлема, приложение может выбрасывать все информационные пакеты до тех пор, пока не будет получен от источника корректный RTCP-пакет.
В зависимости от приложения и используемого кодирования для проверки можно использовать дополнительную информацию о структуре поля данных. Например, для типов данных, где используются временные метки, можно с некоторой точностью предсказывать очередное значение метки на основании знания предыдущей и разности номеров пакетов.
Для того чтобы посчитать частоту потерь пакетов, нужно знать ожидаемое и реально полученное число пакетов для каждого из источников. Число полученных пакетов получается простым их подсчетом с учетом возможного дублирования и запаздывания. Ожидаемое число пакетов может быть подсчитано получателем как разность между наибольшим порядковым номером пакета (s->max_seq) и номером первого пакета в последовательности (S->base_seq). При этом нужно учитывать то, что номера имеют 16 бит, и по этой причине могут переполниться (число переполнений хранится в переменной s->cycles).
extended_max = s->cycles + s->max_seq;
expected = extended_max - s->base_seq + 1;
Число потерянных пакетов определяется как разность между ожидаемым и реально полученным числом пакетов:
lost = expected - s->received;
Доля потерянных пакетов за отчетный период (с момента посылки предыдущего SR или RR пакета) вычисляется из разности ожидаемого и реально полученного числа пакетов за отчетный период, где expected_prior и received_prior представляют собой значения, записанные в момент подготовки предыдущего отчета.:
expected_interval = expected - s->expected_prior;
s->expected_prior = expected;
received_interval = s->received - s->received_prior;
s->received_prior = s->received;
lost_interval = expected_interval - received_interval;
if (expected_interval == 0 || lost_interval <= 0) fraction = 0;
else fraction = (lost_interval << 8) / expected_interval;
Результирующее значение доли равно 8-битовому числу с фиксированной запятой, расположенной слева.
Генерирование псевдослучайных 32-битовых идентификаторов
Ниже приведенная подпрограмма (заимствована из RFC-1889) генерирует псевдослучайные 32-битовые идентификаторы, используя программы MD5, опубликованные в RFC-1321 [11]. Системные программы могут и не присутствовать во всех операционных системах, но они помогают понять, какого рода информация может использоваться.
o getdomainname() ,
o getwd() , или
o getrusage()
"Живые" видео или аудио сигналы могут быть также не плохим источником случайных числе, при этом только следует позаботиться о том, чтобы микрофон не был отключен, а объектив камеры не был закрыт [7].
Использование этой или другой подобной программы предполагает определенную процедуру инициализации, которая нужна для получения первых псевдослучайных чисел. Так как эта программа заметно загружает процессор, ее непосредственное использование для генерации RTCP-периодов нельзя считать приемлемым. Следует заметить, что данная программа выдает один и тот же результат при последовательных вызовах до тех пор, пока не изменится показание системных часов или не будет задано другое значение аргумента type.
/*
* Генерация псевдослучайного 32-битового числа.
*/
#include <sys/types.h> u_long */
#include <sys/time.h> /* gettimeofday() */
#include <unistd.h> /* get..() */
#include <stdio.h> /* printf() */
#include <time.h> /* clock() */
#include <sys/utsname.h> /* uname() */
#include "global.h" /* from RFC 1321 */
#include "md5.h" /* from RFC 1321 */
#define MD_CTX MD5_CTX
#define MDInit MD5Init
#define MDUpdate MD5Update
#define MDFinal MD5Final
static u_long md_32(char *string, int length)
{
MD_CTX context;
union {
char c[16];
u_long x[4];
} digest;
u_long r;
int i;
MDInit (&context);
MDUpdate (&context, string, length);
MDFinal ((unsigned char *)&digest, &context);
r = 0;
for (i = 0; i < 3; i++) {
r ^= digest.x[i];
}
return r;
} /* md_32 */
/*
* Полученный результат - 32- битовое число без знака. Используйте аргумент 'type' если вам
* нужно получить несколько разных величин подряд.
*/
u_int32 random32(int type)
{
struct {
int type;
struct timeval tv;
clock_t cpu;
pid_t pid;
u_long hid;
uid_t uid;
gid_t gid;
struct utsname name;
} s;
gettimeofday(&s.tv, 0);
uname(&s.name);
s.type = type;
s.cpu = clock();
s.pid = getpid();
s.hid = gethostid();
s.uid = getuid();
s.gid = getgid();
return md_32((char *)&s, sizeof(s));
} /* random32 */
Библиография
[1] |
D. D. Clark и D. L. Tennenhouse, "Architectural considerations for a new generation of protocols," in SIGCOMM Symposium on Communications Architectures и Protocols , (Philadelphia, Pennsylvania), pp. 200--208, IEEE, Sept. 1990. Computer Communications Review, Vol. 20(4), Sept. 1990. |
[2] |
D. E. Comer, Internetworking with TCP/IP , vol. 1. Englewood Cliffs, New Jersey: Prentice Hall, 1991. |
[3] |
Postel, J., "Internet Protocol", STD 5, RFC 791, USC/Information Sciences Institute, September 1981. |
[4] |
Mills, D., "Network Time Protocol Version 3", RFC 1305, UDEL, March 1992. |
[5] |
Reynolds, J., и J. Postel, "Assigned Numbers", STD 2, RFC 1700, USC/Information Sciences Institute, October 1994. |
[6] |
Eastlake, D., Crocker, S., и J. Schiller, "Randomness Recommendations for Security", RFC 1750, DEC, Cybercash, MIT, December 1994. |
[7] |
J.-C. Bolot, T. Turletti, и I. Wakeman, "Scalable feedback control for multicast video distribution in the internet," in SIGCOMM Symposium on Communications Architectures и Protocols, (London, England), pp. 58--67, ACM, Aug. 1994. |
[8] |
Balenson, D., "Privacy Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, и Identifiers", RFC 1423, TIS, IAB IRTF PSRG, IETF PEM WG, February 1993. |
[9] |
V. L. Voydock и S. T. Kent, "Security mechanisms in high-level network protocols," ACM Computing Surveys, vol. 15, pp. 135--171, June 1983. |
[10] |
Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, MIT Laboratory for Computer Science и RSA Data Security, Inc., April 1992. |
[11] |
S. Stubblebine, "Security services for multimedia conferencing," in 16th National Computer Security Conference , (Baltimore, Maryland), pp. 391--395, Sept. 1993. |
[12] |
S. Floyd и V. Jacobson, "The synchronization of periodic routing messages," IEEE/ACM Transactions on Networking , vol. 2, pp. 122-136, April 1994. |
<
Содержание раздела