UNИX, весна 2008, 05 семинар (от 11 июля)
Материал из eSyr's wiki.
[править] Протокол XMPP
- Докладчик: Даниил Алексеевский
- Информация семинаре: http://uneex.ru/Events/XMPP
- Диктофонная запись: http://esyr.org/lections/audio/uneex_2008_summer/uneex_seminar_08_07_11.ogg
- Фотографии: http://esyr.org/photo/uneex/080711/
Началось всё с того, чт в 1998 году некто Джереми ..., который сказал: ""я хочу сделать IM на XML. Из нег длг пытались выбить, почему н этого хчет: н сначала отбивался, чт он будет расширяемый и всё такое, н в итоге всё свелсь к тму, что н этого хочет. Он написал jabberd, потом обр. собщество, через некотрое время зарегистрирован jabber.org. На рассылке велись активные дискуссии. 8 августа 1999 года пришёл левый чувак, который сказал, что вот IETF разрабатывает стандарт IMPP, хочет стандартизировать протокол IM. Через 3 дня Джереми публиковал html-ку, в кторой он написал, что он хочет, чтобы их проткол был более стабильны, удвлетворял стандарту и так далее... В 2000 гду они сделали стандарт, который подходит для IETF и забросили его туда. Чуть позже jabberd стал версии 1ю.0. Ещё чуть пзже ни попытались прдвинуть в IETF RFC, но на неё забили и она заэкспайрилась. Чуть позже решили стандартизирвать протокол и был создан JSF, задача котрого сстояла в разрабоотке и проталкивании стандартов. В тоже время, когда рганизовали JSF, стали стандартиховывать заметки по протоколу. Тгда же стали оформлять все расширения в виде JEP (abber Extension Proposal), тогда же был стандартизован формат этих JEP, который двольно близк к RFC.
В 2002 году им удалось запихать в IETF IETF-draft для XMPP. Лектр не очень представляет, как организуется документооборт в IETF, но кажется, что это уже нечто близкое к утверждению, по крайней мере, оно опубликаовано на ietf.org. Этот стандарт был двольно забавный, читать его довольн трудно, туда был свалено всё, чт к тму имелось в XMPP: инициализация сессий, обмен сообщений, такая вещь, как jabber.iq:agent, был ещё дин забавный неймспейс jabber.iq:oob (out of band data, протокол обмена файлами, который по своей хреновости соресновался с тем, что было в аське)
С точки зрения лектора, знаменательным является 10 февраля 2003 года, когда ... оставил первый комментарий в репозитории ejabberd. В 2006 году jabber.org, который дщо этого момента жил на jabberd 1, перепоолз на ejabberd.
В 2003 году протокол наконец-то сформировался, вытеснили старую авторизацию, которая не допускала дайджестов и небыло нормального шифрования. В 2004 году наконец-то зарегистрировали 4 RFC касательно jabber. Лектор всегда считал, чт их было две --- RFC 3920 (XMPP-Core), 3921 (XMP), однако сегодня, он обнаружил, что их было 4, была ещё 3923, которая устанавливала связь между предыдущими двумя и IMPP, и ещё одна RFC, которая описывает шифрование point-to-point, которая описывает шифрование и подпись сообщ по протоколу s/mime. Лектор вспервые сегдня посмотрел на не ё и ужаснулся, пскольку выглядит это следующим образом:
<message> <e ...> ContentType: From: ...
либо запихивать base64 от зашифрованного текста. То есть, люди выбросиоли xml, заставляли писать ещё один парсер и так далее.
В 2004(?) году гугл объявил о создании google talk.
Это то, что лектор счёл уместным расскзаать в части истории.
Что же такое XMPP?
Все знают, чт такое XML namespaces? Никто... Ну, они управляются двумя атрибутами. Суть с том, что есть докумен, он определяется схемой. Обычно схемы достаточно дляя определения. Как только схем становится несколоько, возникает потенциальный конфликт. Каким можно ссылаться на несколько схем? Можно, например, указать, какими схемами описывается документ, глобально или локально. Чтобы разрулить эту ситуацию, каждой схеме приписывают неймспейс. При этом неймспейсы схемам приписываются глбально. НапримеР, у одной схемы неймспейс jabber.iq:last, у другой --- jabber.client. Лектр вернётся на шаг назад.
Рассказывалось про некоторые вехи в развития протокола.
- Первая веха -- всё свободно
- Вторая --- когда захотели публиковаться в IETF и придумали нечто RFC-образное, чт в последствии стало драфтом
- Третья --- организация JSF и стандартизация JEP
- "Взрослая жизнь с IETF". Настоящий RFC и было ещё неск. RFC, который вводили всякий беспорядок в XML-неймспейсы. В этой эпохе было принято называть неймспейсы jbber:чт-нибудь (jabber:client, jabber:iqчто-нибудь, jabber:xчято-нибудь...) В эту пору было принято использовать следующий способ названия для XML-схем: http://jabber.org/protocol/...#часть протокола. Лектор можно привести только один пример, неймспейсы стали называться urn:ietf:xmpp:... . Когда такое встречается в обычном тексте, это вызывает ужас и непонятно, зачем такое.
В чём суть неймспейсов. Когда мы гворим, что мы в этом неймспейсе, то мы подчиняемся этму неймспейсу, и ... . Например: <iq xmlns="jabber:iq.last"> ... </iq> и тогда всё внутри соответствует ему. Когда мы хтим, чтобы внутренность соответствовала неск. неймспейсам, то говорим <stream ns:stream="jabber:client">. Примерно с таких слов начинается любой микропоток, который инициирует клиент в сторону сервера. Значит это следующее --- начиная с этого места, мы используем этот неймспейс.
Теперь к основному --- что же такое XMPP. XMPP строится вокруг ... в давние времена лектор видил документ с идеологией xmpp, но лектор его найти не смог. Там было следующее: основная идея xmpp - инструмент задания xml-потоков, которыми узлы в реальном времени обмениваются ими, вся смысловая нагрузка на сервере, клиенты должн быть как можно более простые, что сервера, сответственно, делаются модульными в достаточно явном виде. Модульными и жутко умными. Сейчас есть документ, где примерно такое говорится, и там впервом пункте приписывается, что это открытая и стандартизованная система.
Ещё один пункт идеологии xmpp --- он не зависит от транспортного уровня. Но далее речь о tcp и на нём все примеры.
Мировоззрение с точки зрения устройства мира, с точки зрения xmpp. RFC начинается с рисунка в виде ascii-арта. У нас есть неск. серверов, которые умеют общаться между собой, сервера могут общаться с компонентами, которые в древние времена называли агентами, сервера могут общаться с транспортами, которые общ. с чужими сетями, которые общ. с другими клиентами.
Адресация в xmpp строится вокруг jid, которые сост. вокруг названия узла и сервера: node@domain/resource. Итак, xmpp выделяет в этой картинке тлько два типа связей: между серверами и т ссервера к ... --- jabber:server, и между серверами и клиентами --- jbber:client. И стаднарт описывает оба случая, они почти одинаковы за неск. исключниями. Даже этот оно не сильно важно для описания xml-потоков, поскольку с них важно, что существует понятие инициирующей стороны и слушающей. Инициирующая сторона открывет tcp-соединение и посылает пакет следующего содердания:
<?xml version=1.0 > / <stream:stream s | ns:stream --- заодит неймспейс, в котороом будет вестись поток \ ...>
Дословно должно произойти следующее: должно быть открыт соединение, в которое будут положены байтики от открывающего д закрывающего. Они интерпретируются почти как xml, за исключением того, что тут не требуется наличие закр. тегов. Отвечающая сторона отвечает также, за исключением, того, что неймспейс будет другой. Делаа опис. понятие xml-поток. Каждая сторона может слать пакеты низлежащего уровня, в лююбом случае каждая сторона шлёт куски текста, которые являются с одной стороны, потомками ns:stream, с другой стороны, являются законченным xml за исключением заголовка. Указывать заголовок, можно, но обязательно xml1.0 и кодировку utf-8.
Дальше для собственно этих самых тегов, которые пересылаются, они называются потомками тега stream, xmpp-core определяет три возможно потомка, с учётом, что старые реализации посылают ещё неск. других, на которые хорошо бы реагировать:
- stream:features
- stream:error
- ...
В древности был потомок auth, который можно встретить в нек-рых библиотеках и клиентах. Сответственно в features устанавливаются возможные св-ва потока, которые подд. сервер, в ответ на иниц. потока сервер обязан ответить, какие он поддерж. св-ва. Им же устанавливаются всяческие авторизации и шифрование. error отличается от шоибки потока, когда единственное что можно сделать --- закрыть поток.
Долгое время лектор считал интересной частью xmpp инициализацию соединения. То, что происх. между заголовками и тем, когда начинают в потоке ходить сообщения и происх. обмен данными. В этом месте могут случиться три вещи:
- Инициализация TLS
- Авторизация
- Связывание с ресурсом
Ведутся они все по одной и той же схеме. Сначала отвеч. стоорона высылает шапку с вом. свойствами, иниц. сторона выбирает, хочет ли она что-то делать из этих действий.
(картинка)
Опции здесь такие:
- На первом этапе иниц. сторона может установить шифрвания или авторизоваться
- После шифр. может только авторизоваться
- После авторизации может бвыть только bind
Если мы выбрали шифроваться, то отвечаем тоже stram:features, в котором выбирается наличие шифрование, и из мех. шифрования выбир. подмножество. В ответ на это начиная со след. байта сервер пускает бинарную белиберду, кторая явл. собственно шифрованием, и присх. собственн TLS-initiaslization. Всё это происх. в одном и том же tcp-соединении. Следом за этим, когда tls-иниц. завершена, снова образуется поток, в котором снова мжно сдлать байты. Это тоже соед., но оно другое. Поэтому случается снова обмен заголовками, и снова отвеч. сторона высылает св-ва потока.
Следующим этапом идёт авторизация по SASL, оно отличается тем, что сервер добыл из базы парол и подтвердил, что он правлиьный.
На этом всякие автор-шифр. завершаются, про них забывают и радуются жизни.
Далее в уст. после авт. потоке у нас есть три выделеных потомка типа stream, которые називаются stanzas: message, presence, iq. У них есть наборы атрибутов, которые опис. не здесь: from, to, type, id. В Данном месте нас инт. только то, что iq бывают только типов get и result, у iq всегда надо указ. неймспейс.
iq --- обмен структ. данными, о которых в ядре не говоритмя ничегО, поэтэиому для него всегда нажо указ. неймспейс.
<iq type='set' xmlns='jabber.iq:bind'> <query> <resource>
Не смотря на то, что в core про iq ничего не говориться, там сказано, что в описании iq должен быть оописан его потомок query, но не все станд. этому соотв.
Самим соед. мы уст., какой домен, авторизацией ---- какой w, а биндом --- какой ресурс.
Есть одно значение атрибута type, которое все станци должны поддерживать --- error. В ответ приходит примерно такая же станца. В одну сторону идёт set, в другуй --- result, который либо пустой, либо будет содерж. query и resource, либо придёт error и клиент тогда должен решать, что делать, скорее всего пожаловаться пользователю.
Ещё (можно было бы упомянуть в начале, а можно и сейчас). xml в этих потоках не совсем xml, а его подмножество. У него может быть не более одного processing instruction, запрещены прбелы между тегами, запрещены ещё комментарии, запрещены всякие штуки, которые относятся не к xml, а к sgml, например DTD. Есть некие оговорки в ядре, при которых совместимость с xmpp Зафиксирован 4 значениями список возможных entity-references --- <, >, & &aquot;, и хотя < и > можно было бы опускать, но их исп. обязательно. Ну и кодировка потока utf-8.
Что определяет core:
- Структуру мира (архитектуру)
- xml-потоки
- Инициализацию самого потока
- Дайт смутные предст, что такое stanza.
Этлго вполне дост, чтобы исп. в качестве RFC. Лектор не видел реализации, которые обх. только таким ядром и делали что-то полезное.
Второй из текужих станд. протоколов называется XMPP-IM. Начинается он с требования, что сервер может потребовать или не потребовать, чтобы клиент иниц. сессию. То, что до этого было, это не иниц. сессии. Как об этом сообщ. сервер: то ли в strea:features, то ли клиент всегда пробует это сделать... Иниц. выглядит следующим образом:
<iq type='set' id='1'> <query xmlns='jabber.iq:session' /> //C </iq>
<iq type='result' id='1' /> //S
В случае взаимод. сервера и сервера или с компонентой сервер не может иниц. серверный диалог. Есть некое расш. к иниц. --- server digest, в которой можно сказать, что сервер для удост. с сервером орг. диалог с третьим сервером, но вообще обычно сервер с сервером не иниц. диалога за иск. передачи клиент. сообщ. Ситуация общ. сервера с сервером в xmpp-im явно не является.
Лектор не может понять прелесть подобной инициализации. Объяснение в том, что происх. иниц. именно xmpp-im.
Только после этого можно обмениваться станцами.
Что такое станца и какие они бывают.
* message. Обязана отправляться клиентом в аттр. to='id', от сервера приходит from и не содерижит to. У неё может быть опционально поле type, причём, что забавно, в протоколе не сказано, как трактовать отсутствие этого атрибута, пожэтому в нек-рых клиентах оно трактуется как type='normal', в некоторых --- 'chat', в некоторых --- 'groupmail'. Normal отображается как mail, chat отображается более компактно, подраз., что у него е будет subject, хотя не факт. groupchat используется в конференциях.
Маршруизция. Если jid находится на том же сервере, то он непоср. маршр. получателю, иначе уст. s2s соединение, и там идёт сообщ. с аттр. from и to.
Стандартные потоки:
- <subject> --- plain text
- <body> --- plain text
- <x> --- для всчких расширений
Атрибут id генерирует клиент, тогда сервер его сохраняет и исп. при ответе, чтобы отличать, на что ответ.
Есть раширение XHTML-IM, которое вбирает подмножество xhtml, опред. там очень огр. подмн. xhtml, и декларируется, что можно писать
<x xmlns="http://jabber.org/protocol/xhml-im"> //(?) --- проверить xmlns <html> <body> ...
Отдельно в ядре есть пункт, что делать, когда встречаешься с неизв. неймспейсм. Общее правило --- не трогай. Привод. неск. искл., когда не передавать, а выбросить.
- presence. Обычно его шлют без указания to. В этом случае он рассылается всем, кто может и хочет сметрть твой статус. Может --- есть разрешение на subscription. Можно указать to. В таком случае stanza будет перенаправляться по тем же прпвилам, что и ьуыыфпу
- Атрибут type. он может отуст. Это является одним из возм знвчений
type | значение | комментарий |
---|---|---|
--- | available | передача сообщ. о том, что ты есть. Клиент обязан в начале сессии послать такую станцу --- <presence />, опционально с id. Это наз. initial-presence |
type=unavailable | unavailable | |
type=subscribe | subscribe | запрос на получение авторизации. Правила очень просты. Их можно отпр. при наличии поля to, когда клиен отправляет такой запрос, во-первых, этот presence транс. получаетль, во-вторых на сервере отправитель оказывается в состоянии subscribtion=ask. В частности, такое состояние можно увидеть в ростере. |
type=subscribed | subscribed | На это получатель может ответить так, это значит, что разрешение на сабскрипшн дано |
type=unsubscribe | unsubscribe | Запрос отписки, сервер сразу отвечает unsubscribed |
type=unsubscribed | unsubscribed | Запрет подписки |
Подписанные --- множество тех, кому можно слать presence без to. С нкотоорым иограничениями. Потомки:
- Когда presence type отсутствует или unavail, то потомок <show> может иметь следующее содержимое --- available, away, xa, dnd, ffc
- status --- plain text
- priority --- что такое приоритет. Если мы где-нибудь указываем to='node@domain' без ресурса, а у соотв. узла на соотв. домене есть неск. ресурсов, то сообщ. будет отпр. на ресурс с большим приоритетом.
Следующая станца iq. Доставляется только туда, куда говориться, то есть правила такие же, как у message, хотя могут делаться исключения.
<iq type='set/get/result'>
Да, у всех может быть error и в этом случае будет пристуствовать потомок error, который будет объяснять, почему же именно ошибка.
У messsage бывает потомок под названием thread, который не поддерживает не один известным клиентом, а зря, поскольку позволяет общаться межу двумя клиентами в рамках одних ресурсов в одном окне. Правила такие --- thread для того, что бы сообщ. в нём были, надо копировать.
Ростер. У Ростер ыбывают следующе протоколы взаимодействия:
- Заппос
- server-side push --- когда клиент шлёт ростер (или добавления в ростер). Об этом позже
- Редактирование ростера. По подобному протоколу, только в обратную сторону
Когда какие случаи возн.
Если клиент добавляет себе какой-то контакт, то он шлёт на сервер запрос set с ростером, в которм приводится...
<iq> <query> <item subscripton //сервер игн. subscription за иск. remove name=".." jid=".."> <group>...</> </> </> </>
Клиент. У него есть неск. ресурсов. Он с одного из ресурсов отпр. запрос на удаление ростера. subskription бывает ask, both, from, to , remove. Тогда в ответ на такой запрос сервер ответит в это же соединение пустым result, а все ост. ресурсам соверш. server-side roster push, на что они обязаны ответить пустым result.
ростер и presence --- две ортогональные вещи, и забота клиента их стандартизовать.
В 2007 JSF переименовал себя в XSF. Как написано в соотв. док-те, чтобы лучше отражать цели комитета --- отвечать за всякую возню в стандартах.
XMPP IM выделяет примерно 4 вещи:
- session init
- message --- базовая перед. сообщ.
- presence --- базовый обмен статусом
- roster --- базовый обмен ростером
- subscription --- управление подписками
- privacy --- управление списками ограничений на рассыдку сообщений. Эти самые ограничения поддерживаются почти одним только tkabber.
Семантика privacy lists такая: у клиента есть список списков ограничений, каждый список ограничений в чём-то очень похож на набор правил фаервола. Это список, в котороом есть номер очередного порядка правила (они проходятся в порядке номеров до первого попадания), правила бывают {{{<item> type='jid/group/subscription'}}} --- матчастя по знач. jid, по группе или по статусу subscription, правило может разрешать или запрещать получ. сообщ, получение-отправку презена, получение iq. Например, правило на subscription --- не получать сообщения от неподписанных пользователей. Правила такого типа собираются в списки. Каждый клиент может задавать неск. таких списков, активен только один, и большинство будет валаться на сервере. Один ожно назвать дефолтом, и он будет активен всегда, когда клиент иниц. сессию. И ещё клиент может попросить сделать активным на текущую сессию другой список.
Существует XEP-0191, который называется simple message blocking, который сделан потому, что клиенты отказываются реализовывать мороку со списком ограничений, и который позв. просто положить список контактов, от которых запрещено получать сообщения.
Та часть, которая явл. зарегистр. ядром, она завершилась.
Есть протокол, который делает примерно ту же, роль, что и IMPP, advanced messages requiremet, он перечисляет список расширений, которые делают клиент члеовекоприемлимым. В частности, MUC (multiuser chat/conference)=XEP0045, в нём же есть требование поддержки то ли chat state, то ли message event.
Расш, которые нходятся в сост. приняты готовы и их можно отпр. в IETF и их реком. исп. всем, они довольно тсранные:
- Data form. Аналогично роли форм в html. Исп, например, при создании конф. Пользователю поылается форма, в которой предлагается заполнить форму для созд. конф.
- xmlrpc. Стандарт на то, как xmlrpc вытащить из обёртки http и запихать в xmpp
- in-bound registration --- протокол для регистрации и удаления собст. аккаунта
- discovery --- предназначен для того, чтобы получать список возможностей чего-нибудь. Считается хорошим тоном, если на сервере хостится неск. компонент, то хорошо бы выдавать список конференций.
В самом начале лектор упоминал, что в самой версии, которая попала в IETF, вместо discovery был browse (который deprecated), а до него был agents.
Ещё есть протокол entity-caps, который вып. то же, что и discovery.
Ещё одно забавное наблюдение: лектор обнаружил три клиента, которые рисуют графику через jabber, например inkscape, coccinella, tkabberiwhiteboard. У каждого из них протокол свой, и никто не публиковал расширение на эту тему.
|
|