Данной статьей мы продолжаем серию переводов секции 5 страниц man из Inferno OS. В этой статье мы расскажем про самый первый тип сообщения Styx — сообщение version. Именно с этого сообщения начинается вся работа с сервером или клиентом, и с него начинается то, что называется транзакция (в современных терминах, это бы называлось сессией). Далее, мы дадим перевод информации из справочного руководства Inferno и покажем простой пример реализации этого типа сообщения в D.
НАЗВАНИЕ
version — согласование версии протокола
СИНТАКСИС
size[4] Tversion tag[2] msize[4] version[s] size[4] Rversion tag[2] msize[4] version[s]
ОПИСАНИЕ
Запрос версии согласовывает версию протокола и размер сообщения, которые будут использоваться в соединении, и инициализирует соединение для ввода-вывода. Tversionдолжно быть первым сообщением, отправленным по 9P-соединению и клиент не может отправлять дальнейшие запросы, пока не получит ответ Rversion. Тег для сообщения версии должен быть NOTAG (значение (ushort) ~0).
Клиент предлагает максимальный размер сообщения msize, который является максимальной длиной в байтах, которую он когда-либо будет генерировать или ожидать к получению в одном 9P-сообщении. Это значение включает в себя все данные протокола 9P, начиная с поля размера сообщения и заканчивая самим сообщением, но не включает в себя оболочки транспортных протоколов. Сервер отвечает своим собственным максимальным значением msize, которое должно быть меньше или равно значению клиента. В дальнейшем обе стороны соединения должны соблюдать это ограничение.
Строка версии идентифицирует уровень протокола. Строка всегда должна начинаться с двух символов «9P». Если сервер не понимает строки версии клиента, то он должен ответить сообщением Rversion со строкой версии из 7 символов «unknown», а не Rerror.
Сервер может ответить строкой версии клиента или строкой версии, идентифицирующей ранее определенную версию протокола. В настоящее время единственной определенной версией является строка из 6 символов «9P2000». Строки версий определены таким образом, что если строка клиента содержит один или несколько символов точки, начальная подстрока до нее, но не включая любую другую, определяет версию протокола. После удаления любого такого суффикса, разделенного точками, сервер может ответить строкой в формате 9Pnnnn, где nnnn — меньше или равно цифрам, отправленным клиентом.
Успешный запрос версии инициализирует соединение. Все ожидающие операции ввода-вывода на соединении прерываются; все активные fidавтоматически освобождаются («clunked»). Набор сообщений между запросами версии называется сеансом.
ВХОДНЫЕ ТОЧКИ
Сообщение version генерируется sys-fversion(2). Оно также генерируется автоматически, если требуется, при вызове системных вызовов mount или fauth на неинициализированном соединении.
СМОТРИТЕ ТАКЖЕ
НЕОФИЦИАЛЬНЫЙ ПРИМЕР НА D
В нашем неофициальном примере к этой строке справочной информации, предполагается, что мы игнорируем всче что сказано насчет указания версии протокола через точки (в справочном мануале, если вдруг непонятно из перевода имеется в виду отбрасывание точек после упоминания первой точки в версии. Насколько нам известно, в реальном коде такое почти не применяется, за исключением специфических расширений протокола, которые мы рассматривать не будем). Также, берем за основу к коду использование библиотеки styx2000.
Тогда, примерный код сообщения version может выглядеть следующим образом:
alias StyxArguments = StyxMessage; /// согласование версии протокола (https://powerman.name/Inferno/man/5/version.html) StyxMessage processVersion(ushort tag, StyxArguments args) { StyxMessage r; // если тэг не равен значению по умолчанию (это STYX_NOTAG), то это ошибка if (tag != STYX_NOTAG) { r = createRmsgError(tag, cast(string) STYX_MESSAGE_ERROR.ENEEDNOTAG); } else { // максимальный размер сообщения (это включая поля с указанием размера) auto msize = args[0].toSize.getSize; // версия протокола auto sversion = args[1].toVersion.getVersion; // если размер указанный клиентом превышает то, что указано сервером, то устанавливаем то значение // которое хочет сервер if (msize > MAX_MESSAGE_SIZE) { msize = MAX_MESSAGE_SIZE; } // если версия протокола равна 9p2000 (это исходный протокол без модификаций) if (sversion == STYX_VERSION) { // сообщение о версии почти без изменений, кроме размера r = createRmsgVersion(STYX_NOTAG, msize); } else { import std.string : startsWith; // если название протокола не начинается с 9P, то это не ошибка if (!sversion.startsWith(`9P`)) { // ответ сервера, что версия протокола непонятна r = createRmsgVersion(STYX_NOTAG, msize, STYX_VERSION_UNKNOWN); } else { // согласно спецификации, здесь сервер может указать версию (это четыре цифры после префикса 9P) // меньшую или равную клиентской, чтобы показать что будет вестись работа по старой версии протокола. // но, согласно спецификации можно вернуть и версию клиента. Правильнее, будет указать, что используем // стандартную версию - 9P2000, так как другие - это просто расширения и версий младше не существует. r = createRmsgVersion(STYX_NOTAG, msize, STYX_VERSION); } } } return r; }
Что здесь происходит ?
Здесь используется следующие модули из styx2000 (import не упомянут, так как это часть кода сервера 9P): styx2000.protoconst, styx2000.extrautil.styxmessage, styx2000.extrautil.mischelpers и styx2000.miscerrors.
В первом содержится константа STYX_NOTAG, которая упомянута выше в описании сообщения version, а также некоторые другие примитивы. В модулях styx2000.extrautil.styxmessage и styx2000.extrautil.mischelpers содержатся примитивы для StyxMessage, а также вспомогательные функции вида create<T или R><сообщение>, которые позволяют конструировать нужные сообщения из примтивных типов styx2000 и типов в D.
Сама функция — это возможный прототип метода обработки сообщения version для сервера. Данная функция принимает тег сообщения и набор параметров StyxArguments (псевдоним для StyxMessage), в виде отдельных StyxObject (определен в styx2000.protobj), которые извлечены из самого сообщения (допустим с помощью метода decodeиз styx2000.protomsg, примененного к байтовому потоку, поступившему от клиента) и результатом работы такого метода является также сообщение 9P/Styx, которое может быть преобразовано в поток байтов с помощью encode из модуля styx2000.protomsg.
То, что далее делает processVersion подробно описано в тексте выше, а также в комментариях кода. Для тех кому интересны подробности, советуем обратится к документации styx2000.