Кратко

  • Если сжатие увеличивало дейтаграмм, RFC 1977 сохранял исходную оболочку PPP ради MTU, но не отменял изменение словаря после пробного расчёта; принимающая сторона повторяла его локально.
  • В обычном пакете не было кода LZW CLEAR, поэтому оба участника должны были по одинаковым входам, ширинам и счётчикам самостоятельно очистить словари на одной границе.
  • 16-битный номер мог показать пропуск до декодирования следующего сжатого пакета. Reset-Request/Reset-Ack открывал новую историю с нуля, но не подтверждал полноту или подлинность оставленной истории.

Сжатие, результат которого не отправили

Передатчик не мог узнать несжимаемый пакет по внешнему виду. Он сначала запускал BSD Compress, сравнивал длины и лишь затем выбирал представление. При заметном расширении RFC 1977 требовал послать исходный пакет PPP. Даже увеличение менее чем на три октета обычно вело к тому же выбору, если только сжатый результат всё ещё не нарушал MTU.

Так верхним уровням не приходилось считать MTU меньше из-за возможного неудачного сжатия. Но сам расчёт уже прошёл. LZW прочёл байты, нашёл или создал цепочки, сдвинул порог ширины кода и обновил показатели эффективности.

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

Функция pf_bsd_incomp из приложения «делает вид», что сжимает вход: увеличивает последовательность, считает вход и условный выход, создаёт те же словарные записи, но ничего не кодирует для передачи. Исходной была форма на линии, а не действие над историей.

Словарь без конца файла

У Unix compress естественной границей служил конец файла. После переноса в PPP словарь продолжался через границы дейтаграмм. Он стал общей памятью, которую две независимые реализации восстанавливали из одинакового порядка входов.

Согласование CCP задавало только исходные параметры. Тип опции 21 означал BSD Compress, Version должен был равняться 001, а Dict задавал максимальную ширину от 9 до 16 бит; обычным выбором названы 12. Код в приложении поддерживал 9–15 бит. Это ограничение конкретного примера, а не сужение диапазона спецификации.

Лишняя память не позволяла получателю выбрать больший словарь. От предела зависели момент заполнения, переход ширины и проверка, после которой таблица могла быть очищена. Локальное «улучшение» разорвало бы общую временную шкалу.

Для внутреннего поля Protocol действовало отдельное правило. Значение меньше 0x100 нужно было представить одним октетом до расчёта последовательности и сжатия всего пакета, независимо от согласования PPP Protocol-Field-Compression. Одинаковый дейтаграмм должен был давать одинаковые входные байты.

До фазы Network-Layer Protocol у PPP и состояния Opened у CCP сжатые пакеты были запрещены. Подтверждение параметров доказывало согласие с началом, но не доказывало, что ядро, драйвер и процесс управления выполнят все дальнейшие переходы в одном порядке.

CLEAR без места на линии

Классический BSD LZW резервировал значение 256 для CLEAR. В кодированном потоке оно могло сообщить декодеру об очистке. В обычном пакете PPP кодов LZW не было. Если плохо сжимаемые данные ухудшали уже заполненный словарь, явный сигнал нельзя было надёжно передать именно в этот момент.

RFC 1977 заменил сообщение воспроизводимым условием. Пример после заполнения словаря проверял отношение сжатия через каждые 10 000 входных байтов. Если новое отношение ухудшалось или становилось меньше единицы, pf_bsd_clear возвращал ширину к девяти битам, сбрасывал последнюю запись, отношение и счётчики.

Передатчик принимал решение по пробному сжатию, получатель—по симуляции исходного пакета. Они должны были считать одинаковые входные байты и одинаковую условную длину, назначать коды в одном порядке и одинаково обновлять счётчики. Невидимая очистка оставалась согласованной лишь при совпадении всех этих деталей.

Конструкция экономила заголовок и берегла MTU, но включала алгоритмические мелочи в условия совместимости. После очистки первые пакеты обычно давали мало выигрыша и снова шли в исходной форме. По одному полю протокола они были неотличимы от трафика до включения сжатия, хотя уже строили новый словарь.

Пропуск становится видимым позже

Настоящий пакет BSD Compress содержал 16-битную последовательность, старшим октетом вперёд. Она начиналась с нуля после очистки, росла для каждого допустимого пакета—включая исходные—и переходила через ноль после 65535. Получателю следовало проверить значение до декодирования.

У исходного пакета такого заголовка не было. Если он терялся, передатчик продвигал словарь и счётчик, а получатель не делал ничего. Ошибка могла проявиться лишь при следующем сжатом пакете, номер которого не совпадал с локальным ожиданием.

Такой номер останавливал декодирование с заведомо неверным словарём. Он не называл потерянный пакет, не отличал потерю от перестановки, не возвращал байты и не удостоверял участника. RFC ссылался на HDLC FCS и обычное отбрасывание повреждённых кадров, а в Security Considerations не обсуждал безопасность. Циклический счётчик и контрольная сумма линии не являются криптографическим доказательством целостности.

Reset не чинит прошлое

При первом неожиданном номере получатель должен был послать CCP Reset-Request и отбрасывать сжатые пакеты до Reset-Ack. Передатчик очищал словарь и обнулял последовательность для каждого запроса, поскольку не знал, дошёл ли прежний ACK. Получатель также очищал состояние при каждом подходящем ответе.

RFC сравнивал это с отказом от одного «файла» и началом другого. Reset не восстанавливал отсутствующую запись и не подтверждал старую историю. Он создавал новую общую точку. Новый Configure-Request мог временно вывести CCP из Opened и повторить согласование, но был дороже.

На занятой линии за время RTT после ошибки приходило несколько бесполезных сжатых пакетов. Запросы нужно было повторять до доставки хотя бы одного, но не чаще кругового времени: избыточные запросы вызывали избыточные очистки. Одна секунда была только примером.

Внутри системы оставалась ещё одна граница. Если CCP обрабатывал daemon, а данные—ядро, очистка передатчика должна была быть упорядочена с Configure-Ack или Reset-Ack, открывающим новую историю. Получатель должен был очиститься до следующего пакета. Правильный ACK в трассе не доказывал правильного порядка этих исполнителей.

Общее правило и отдельное свидетельство

RFC 1977 определил небольшой общий набор: допустимые входы, Version 1, предел ширины, проверку отношения, последовательность и перезапуск. IANA по-прежнему регистрирует опцию CCP 21 и значения PPP для сжатых дейтаграмм.

В логике Lu Heng эти детерминированные правила позволяют локальную проверку, но не заменяют свидетельства работающей системы. Для утверждения, что оба словаря двигались вместе, нужны полный порядок пакетов, исходные входы, смены ширины, счётчики и границы очистки.

Статья не пересказывает общую историю CCP из RFC 1962, последовательный формат RFC 1963 или переупорядочение Multilink из RFC 1990. Источники не устанавливают сегодняшнее распространение или показатели продукта. Историческая граница уже достаточно важна: «несжатый» в BSD Compress обозначал форму передачи, а не остановку словаря.

Источники