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 */