8.5. Псевдокод
В этом параграфе представлен алгоритм, описывающий этапы обработки, через которые должна пройти конечная точка DCCP при получении пакета. Реализация DCCP не обязана в точности следовать описанному здесь алгоритму, но любая реализация должна генерировать видимые эффекты, в точности соответствующие приведенному здесь псевдокоду за исключением тех случаев, когда в данном документе явно разрешено иное поведение.
Принятый пакет обозначается, как P, сокет — S. Переменными сокета являются:
- S.SWL — нижний предел окна порядковых номеров;
- S.SWH — верхний предел окна порядковых номеров;
- S.AWL — нижний предел окна номеров подтверждений;
- S.AWH — верхний предел окна номеров подтверждений;
- S.ISS — начальный порядковый номер в переданном пакете;
- S.ISR — начальный порядковый номер в принятом пакете;
- S.OSR — порядковый номер в первом пакете, принятом в состоянии OPEN;
- S.GSS — максимальный порядковый номер в переданных пакетах;
- S.GSR — максимальный порядковый номер в принятых пакетах;
- S.GAR — максимальный корректный номер подтверждения, принятый в пакетах, отличных от Sync; инициализируется значение S.ISS
Операция "Send packet" (передача пакета) всегда использует значение S.GSS и увеличивает его на 1.
Этап 1: Базовая проверка заголовка
/* Этот этап проверяет корректность формата пакетов. Не прошедшие проверку пакеты
игнорируются без передачи в ответ пакетов Reset */
Если пакет короче 12 байтов, он отбрасывается с возвратом управления.
Если тип P.type непонятен, пакет отбрасывается с возвратом управления.
Если P.Data Offset меньше размера фиксированного заголовка для данного типа пакетов или
больше размера пакета, пакет отбрасывается с возвратом управления.
Если P.type не является Data, Ack или DataAck и P.X == 0 (пакет имеет короткий порядковый
номер), пакет отбрасывается с возвратом управления.
Если контрольная сумма заголовка некорректна, пакет отбрасывается с возвратом управления.
Если значение P.CsCov слишком велико для размера пакета, пакет отбрасывается с возвратом
управления.
Этап 2: Проверка номеров портов и обработка состояния TIMEWAIT
/* Flow ID представляет собой квартет <src addr, src port, dst addr, dst port> */
Ищем flow ID в таблице и определяем соответствующий сокет.
Если сокета нет или S.state == TIMEWAIT,
/* Порядковый номер и номер подтверждения берутся из полученного пакета; см. 8.3.1. */
Генерируется пакет Reset(No Connection), пока не будет P.type == Reset
Отбросить пакет с возвратом управления.
Этап 3: Обработка состояния LISTEN
Если S.state == LISTEN,
Если P.type == Request или P содержит корректную опцию Init Cookie,
/* Требуется просмотр опций пакета для проверки Init Cookie. Однако на этом этапе
обрабатываются только опции Init Cookie, а остальные опции — на этапе 8. Данное
сканирование нужно выполнять только при использовании опций Init Cookie */
/* Создать новый сокет и переключиться на него */
Установить S := новый сокет для данной пары портов
S.state = RESPOND
Выбрать S.ISS (начальный порядковый номер) или установить из опций Init Cookie
Инициализировать S.GAR := S.ISS
Установить S.ISR, S.GSR, S.SWL, S.SWH из пакета или опций Init Cookie
Продолжить с S.state == RESPOND
/* Пакет Response будет генерироваться на этапе 11 */
Иначе,
Генерировать Reset(No Connection), пока не будет P.type == Reset
Отбросить пакет с возвратом управления.
Этап 4: Подготовка порядковых номеров в состоянии REQUEST
Если S.state == REQUEST,
Если (P.type == Response или P.type == Reset) и S.AWL <= P.ackno <= S.AWH,
/* установить переменные нумерации, соответствующие другой точке, чтобы пакет P
прошел проверки на этапе 6 */
Установить S.GSR, S.ISR, S.SWL, S.SWH
/* Обработка Response продолжается на этапе 10; Reset — на этапе 9 */
Иначе,
/* Только пакеты Response и Reset корректны в состоянии REQUEST */
Генерировать Reset(Packet Error)
Отбросить пакет с возвратом управления.
Этап 5: Подготовка порядковых номеров для Sync
Если P.type == Sync или P.type == SyncAck,
Если S.AWL <= P.ackno <= S.AWH и P.seqno >= S.SWL,
/* P является корректным, поэтому переменные нумерации соответственно обновляются.
После этого P передается для проверки этапа 6. При необходимости на этапе 15
генерируется SyncAck */
Обновить S.GSR, S.SWL, S.SWH
Иначе,
Отбросить пакет с возвратом управления.
Этап 6: Проверка порядковых номеров
Если P.X == 0 и соответствующий признак Allow Short Sequential Numbers = 0,
/* Пакет имеет короткий порядковый номер, но такие номера не разрешены */
Отбросить пакет с возвратом управления.
Иначе, если P.X == 0,
Расширить P.seqno и P.ackno до 48 битов с использованием процедуры параграфа 7.6
Пусть LSWL = S.SWL и LAWL = S.AWL
Если P.type == CloseReq или P.type == Close или P.type == Reset,
LSWL := S.GSR + 1, LAWL := S.GAR
Если LSWL <= P.seqno <= S.SWH и (P.ackno не существует или LAWL <= P.ackno <= S.AWH),
Обновить S.GSR, S.SWL, S.SWH
Если P.type != Sync,
Обновить S.GAR
Иначе,
Если P.type == Reset,
Передать пакет Sync, подтверждающий S.GSR
Иначе,
Передать пакет Sync, подтверждающий P.seqno
Отбросить пакет с возвратом управления.
Этап 7: Проверка неожиданных типов пакетов
Если (S.is_server и P.type == CloseReq)
или (S.is_server и P.type == Response)
или (S.is_client и P.type == Request)
или (S.state >= OPEN и P.type == Request и P.seqno >= S.OSR)
или (S.state >= OPEN и P.type == Response и P.seqno >= S.OSR)
или (S.state == RESPOND and P.type == Data),
Передать пакет Sync, подтверждающий P.seqno
Отбросить пакет с возвратом управления.
Этап 8: Обработка опций и маркировка подтверждаемости
/* Обработка опций не описывается здесь. Некоторые опции (такие, как Mandatory) могут приводить к сбросу соединения при котором этапы 9 и далее не будут выполняться */ Пометить пакет как подтверждаемый (в терминах Ack Vector — Received или Received ECN)
Этап 9: Обработка Reset
Если P.type == Reset,
Сбросить соединение
S.state := TIMEWAIT
Установить таймер TIMEWAIT
Отбросить пакет с возвратом управления.
Этап 10: Обработка состояния REQUEST (вторая часть)
Если S.state == REQUEST,
/* если мы пришли сюда, P является корректным пакетом Response от сервера (см. этап 4)
и следует перейти в состояние PARTOPEN. Состояние PARTOPEN означает передать Ack,
не передавать пакетов данных, периодически повторять передачу Ack, всегда включая
все опции Init Cookie из пакета Response */
S.state := PARTOPEN
Установить таймер PARTOPEN
Продолжить с S.state == PARTOPEN
/* Этап 12 будет передавать пакет Ack, завершающий трехэтапное согласование */
Этап 11: Обработка состояния RESPOND
Если S.state == RESPOND,
Если P.type == Request,
Передать Response, возможно с опциями Init Cookie
если были переданы опции Init Cookie,
Удалить S и возвратить управление
/* Этап 3 будет создавать другой сокет, когда клиент завершит 3-этапное
согласование */
Иначе,
S.OSR := P.seqno
S.state := OPEN
Этап 12: Обработка состояния PARTOPEN
Если S.state == PARTOPEN, Если P.type == Response, Передать Ack Иначе, если P.type != Sync, S.OSR := P.seqno S.state := OPENЭтап 13: Обработка CloseReq
если P.type == CloseReq и S.state < CLOSEREQ,
Генерировать Close
S.state := CLOSING
Установить таймер CLOSING
Этап 14: Обработка Close
Если P.type == Close,
Генерировать Reset(Closed)
Разорвать соединение
Отбросить пакет с возвратом управления.
Этап 15: Обработка Sync
Если P.type == Sync,
Генерировать SyncAck
Этап 16: Обработка данных
/* В этой точке все данные приложения из P могут передаваться прикладной программе. Однако приложение НЕ ДОЛЖНО получать данных более, чем из одного пакета Request или Response */