Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Опкоды, Формулы, Клиент (http://mangos.ytdb.ru/forumdisplay.php?f=9)
-   -   Централизованый формат снифов (http://mangos.ytdb.ru/showthread.php?t=1852)

Konctantin 20.07.2010 18:34

Централизованый формат снифов
 
Редакция от 31 июля 2011, 13:13, версия 3.1
  • 1. RAW.
    • 1.1. заголовок снифа.
      Код:

      struct MainHeader
      {
        char signature[3]; // 'RAW'.
        byte version[2]; // 0x01, 0x03
        byte snifferID;
        uint build;
        char language[4]; // Язык клиента: 'ruRU', 'enGB' и т.д.
        byte sessionKey[40];
        uint unixTime;
        uint tickCount;
        uint optionalHeaderLength;
      };
      byte[optionalHeaderLength] optionalData;

    • 1.2. чанк
      Код:

      struct ChunkHeader
      {
        char direction[4]; // 'SMSG', 'CMSG'
        uint sessionID;
        uint tickCount;
        uint optionalDataLength;
        uint dataLength;
      };
      byte[optionalDataLength] optionalData;
      byte[dataLength] data;

  • 2. PKT.
    • 2.1. заголовок снифа.
      Код:

      struct MainHeader
      {
        char signature[3]; // 'PKT'
        byte version[2]; // 0x01, 0x03
        byte snifferID;
        uint build;
        char language[4]; // Язык клиента: 'ruRU', 'enGB' и т.д.
        byte sessionKey[40]; // может быть заполнено нулями
        uint unixTime;
        uint tickCount;
        uint optionalHeaderLength;
      };
      byte[optionalHeaderLength] optionalData;

    • 2.2. чанк
      Код:

      struct ChunkHeader
      {
        char direction[4]; // 'SMSG', 'CMSG'
        uint sessionID;
        uint tickCount;
        uint optionalDataLength;
        uint dataLength;
      };
      byte[optionalDataLength] optionalData;
      byte[dataLength] data;

      , где
      - data включает в себя Opcode, выравненный до uint
      - dataLength равен размеру data

  • 3. Имя файла.
    • 3.1. имя файла
      имя может быть произвольным и удобным каждому из разработчиков.
    • 3.2. расширение файла
      обязательно .raw или .pkt

Редакция от 25 июля 2010, 21:00, версия 3.0
  • 1. RAW.
    • 1.1. заголовок снифа.
      Код:

      struct MainHeader
      {
        char signature[3]; // 'RAW'.
        byte version[2]; // 0x00, 0x03
        byte snifferID;
        uint build;
        char language[4]; // Язык клиента: 'ruRU', 'enGB' и т.д.
        byte sessionKey[40];
        uint optionalHeaderLength;
      };
      byte[optionalHeaderLength] optionalData;

    • 1.2. чанк
      Код:

      struct ChunkHeader
      {
        char direction[4]; // 'SMSG', 'CMSG'
        uint unixTime;
        uint tickCount;
        uint optionalDataLength;
        uint dataLength;
      };
      byte[optionalDataLength] optionalData;
      byte[dataLength] data;

  • 2. PKT.
    • 2.1. заголовок снифа.
      Код:

      struct MainHeader
      {
        char signature[3]; // 'PKT'
        byte version[2]; // 0x00, 0x03
        byte snifferID;
        uint build;
        char language[4]; // Язык клиента: 'ruRU', 'enGB' и т.д.
        byte sessionKey[40]; // может быть заполнено нулями
        uint optionalHeaderLength;
      };
      byte[optionalHeaderLength] optionalData;

    • 2.2. чанк
      Код:

      struct ChunkHeader
      {
        char direction[4]; // 'SMSG', 'CMSG'
        uint unixTime;
        uint tickCount;
        uint optionalDataLength;
        uint dataLength;
      };
      byte[optionalDataLength] optionalData;
      byte[dataLength] data;

      , где
      - data включает в себя Opcode, выравненный до uint
      - dataLength равен размеру data

Предложения
SnifferID:
Код:

0 - Wad // 2005 и ранее
1 - Nomad // 2005 и ранее
2 - WoWCore // 2006
3 - Mangos (TOM_RUS) // 2006
4 - User456 // 2007
5 - Delfin // 2007
6 - Burlex // 2007
7 - WCell // 2008
8 - Kobold // 2009
9 - abdula123 // 2010
10 - Konctantin/LordJZ // 2010
11 - Йоха // 2010


Konctantin 23.07.2010 12:26

Вот появилось свободное время, и хотелось бы продолжить дискуссию.

Мне как-то не очень понравилась мысль о создании своего формата снифа. Лучше немножко доработать существующий.

Сразу объясню почему:
1) Зачем плодить кучу форматов, потом писать конвертеры, потом опять чего-то. Это все лишний код.
2) Хоть снифы и не нужны широкому кругу пользователей, да и используются фактически только в определенными людьми, позиция многоформатности теряет свой смысл. Свой собственный формат следует вводить только в том случае, если хочется кардинально выделить свой "продукт" и сделать его "уникальным". В нашем случае это ненужно.

Я изначально за обобщенный, централизованный формат.
Давайте в этой тебе оставим свои "за" и "против" и согласуем надо а что не надо.

Саму архитектуру формата можно разделить на 3 уровня:
1. Имя файла
2. Заголовок
3. Тело


1) Как уже говорил RomanRom2, имя файла должно носить информационных характер.
Код:

[build]_[datetime(yyyy-MM-dd_HH-mm-ss-ffff)]_[SessionIndex]_[LogIndex]_[RealmIP].[pkt | raw]
Я бы предложил стандартный формат (yyyy-MM-dd_HH-mm-ss-ffff), если есть какие-то нюансы с формированием даты, хотелось бы услышать. (это более читабельно)
FirstClientOpcode - я даже не знаю, по большему счету будет всего 2 варианта, или же это CMSG_AUTH_SESSION или CMSG_REDIRECTION_AUTH_PROOF и особой информационной составляющей не носит, так как у меня раз получилось 4 сессии
фактически вышло получилось бы следующее:
Код:

ххх_CMSG_AUTH_SESSION_ххх
ххх_CMSG_REDIRECTION_AUTH_PROOF_ххх
ххх_CMSG_REDIRECTION_AUTH_PROOF_ххх
ххх_CMSG_REDIRECTION_AUTH_PROOF_ххх

Я бы предложил писать номер сессии, в формате SessionIndex_LogIndex
почему так спросите вы? отвечу, наша прокси позволяет включать и выключать логирование трафика и SessionIndex в данном случае это номер сессии, а LogIndex это порядковый номер лога. (это опционально, но желательно, если запись в отдельный файл), правда в этом случае FirstClientOpcode уже будут разные.

2) Заголовок, я думаю вполне хватит и вот этого:
Код:

[PKT | RAW]
Version
ClientBuild
ClientLanguage
SessionKey

так как я думаю, имя файла - это информация для человека, а хедер - это техническая информация для самой тулзы.

3) и само тело снифа.
Код:

(byte)Direction;
(uint)UnixTime
(uint)TickCount
(uint)Opcode
(byte)Flags // для того чтобы выделять что это за пакет (опционально, тоже можно договорится о спецификации)
(uint)Data.Length
(byte[])Data

Жду продолжения дискуссии, а в первый пост потом можно написать результат (готовый централизованный формат снифа)

TOM_RUS 23.07.2010 12:31

Писать разные сессии в отдельнный файл очень не удобно. Теоретически это одна сессия, и все пакеты в ней взаимосвязаны. В таком случае теряется последовательность пакетов, а она для меня очень важна.

Konctantin 23.07.2010 12:35

я же писал:
Цитата:

это опционально, но желательно, если запись в отдельный файл

RomanRom2 23.07.2010 22:20

выскажусь и я.

согласен с "архитектурой":
1. Имя файла
2. Заголовок
3. Тело

итак, давайте рассматривать потенциальный будущий формат 3.0;
1.
===
имя файлы, как я уже говорил - носит рекомендательный характер. по этому пункту мы скорее всего не договоримся, тут почему то кому что нравится. но позволю себе высказаться по этому поводу. за 5 лет снифанья и использования снифов выработались следующие ... "пожелания", назовем это так. визуально удобно, когда при вгляде на файлы идентифицируется сразу:
- билд клиента
- откуда снифф, название реалма. при некоторых обстоятельствах, но по факту почти не нужно.
- что бы снифы все располагались по порядку
- поле "имя аккаунта" реально не пригодилось.

итак, что получается:
12604_4C497974.PKT

теперь поговорим о формате "дата снифа". опять же, опираясь на опыт прошлых лет, полная читабельная дата в имени файла вроде yyyy-MM-dd_HH-mm-ss-ffff нафиг не нужна. по трем причинам как минимум:
- дату файла можно посмотреть у самого файла. обычно эти даты совпадают :)
- смотреть на файлы и видеть дату реально не пригодилось. важнее вот билдом клиента больше всего оперируем при обработке. например сразу видно, что вот эти сниффы будет парсить вот этим снифером. не важно какая дата снифов.
- ну длиновато имя файла получается :)

единственная цель в поле "дата" - для сортировки файлов в файловых панелях (far, tc, проводник, кто чем еще пользуется). реально больше ни для чего не нужно оказалось.

в связи с вышесказанным считаю запись UnixDateTime(Now) самой оптимальной. к слову сказать, это повелось еще во времена динозавров - такое поле использовал еще wad в своем снифере :) но это так, лирическое отступление.

поле "имя реалма" сейчас не просто доставать, да и по факту оно редко когда нужно. а адрес:порт реалма сейчас у меня лишь для небольшой статистики. я уберу.

дальше, есть ньюанс с номером сессии. тут два возможных варианта:
- мы пишем все сессии в один файл и не паримся с этим
- мы каждую сессию пишем в отдельный файл и придется как то помечать файлы. почему?

вторая сессия может быть начата в ту же секунду что и первая и тогда имя файла для второй сессии будет одинаковым. т.е. получается что то вроде такого тогда:
12604_4C497974_[1].PKT
12604_4C497974_[2].PKT
именно по этой причине в имени файла у меня появились номера опкодов. я просто посчитал что это гораздо прикольней, чем просто 1, 2, ...
12604_4C497974_[01ED].PKT
12604_4C497974_[0512].PKT
и поскольку у нас всего два (в последнем катаклизме три) варианта, мы прекрасно знаем, что 01ED - первая сессия и обычно не несет в своем сниффе никакой полезной информации и я такие снифы просто удаляю. а 0512 - вторая сессия, которая нам и нужна.

кстати, со временем оказалось, что есть еще одна полезная фишка с записью опкода в имя файла: на катаклизме как вы знаете сейчас часто меняют опкоды. в общем это теперь сразу видно и сразу видно на что именно поменяли в этом билде :) не надо открывать снифф и искать там.

по поводу SessionIndex_LogIndex. собственно опкод это и есть SessionIndex, а LogIndex честно говоря не знаю - зачем делать разные файлы для одной сессии. ну раз такое нужно, что ж, ничего в этом такого нет - делайте. и помечайте. получится что то вроде:
12604_4C497974_[01ED].PKT
12604_4C497974_[0512_1].PKT
12604_4C497999_[0512_2].PKT
12604_4C499376_[0512_3].PKT
...
только смысла опять же не очень понимаю. время ведь тоже меняется.

в общем по первому пункту (имя файла), как я уже сказал, мы скорее всего не договоримся. но повторюсь - вышесказанное есть мое видение и предложение, поддержанное пятилетним опытом работы со снифами. наверное никто так много и долго с этим делом не работал :yes3:

единственно о чем мы должны договориться, это о расширении файла. многие редакторы фильтруют файлы по расширению. в общем предлагаю очевидные .raw и .pkt

2.
===
по второму пункту полностью поддерживаю. к существующему заголовку версии 2.1 нужно добавить только ClientLanguage. оно реально нужно для автоматического определения языка при парсинге респонсов.
3 байта: [PKT | RAW]
2 байта: Version
2 байта: ClientBuild
4 байта: ClientLanguage. варианты [enUS] [enGB] [ruRU], т.е. прям с клиентского пакета (они там наоборот, SUne, BGne, URur).
40 байт: SessionKey

но хочу предложить сюда, скажем, 8 байт DevelopersData
3 байта: [PKT | RAW]
2 байта: Version
2 байта: ClientBuild
4 байта: ClientLanguage
8 байт: DevelopersData
40 байт: SessionKey
пусть сюда каждый разработчик складывает все что ему хочется, что ему удобно. и это поле не поддается какому либо форматированию.
да и вообще, FutureFields можно сказать.
поле является обязательным (наличие), но требований к полю нет никаких. такой вот прикол :censored:

3.
===
данные. заголовок каждого чанка данных:
предложенная структура
(byte)Direction;
(uint)UnixTime
(uint)TickCount
(uint)Opcode
(byte)Flags

(uint)Data.Length
(byte[])Data

от текущей отличается выделенными полями.
два вопроса:
1. зачем в заголовке опкод? он ведь в самом чанке. плюс у raw мы не можем знать опкод.
2. для чего поле Flags?
я просто предлагаю здесь ничего не менять. инфы более чем достаточно.

LordJZ 23.07.2010 22:38

Ну Flags у нашего сниффера только требуется (вроде я не видел больше), а опкод у нас отдельно выделен, не в самом чанке он — не удобно нам по-другому. Просто в коде неудобно.

Еще я у себя храню SessionLength — время сессии в секундах, и PacketCount. Последний для корректного чтения пакетов, чтобы в конец файла можно было вдруг, если понадобится, подпись.

RomanRom2 23.07.2010 22:52

ну так ответов на вопросы нет.
1. зачем опкод? в данном случае вопрос по другому: в чем неудобство опкода в чанке?
я просто рассматриваю чанк как
- опкод
- данные, соответствующие этому опкоду
т.е. вполне закономерно и логически законченная сущность. чанк. задумайтесь :)
а размер чанка - в заголовке. по этому полю в заголовке удобно "пробегать" по снифу.
2. для чего флаг чанка? что там в нем? какие флаги бывают? для чего используются?

я вот сейчас придумал пока писал это сообщение, что чанку можно прибавить поле в 1 байт SessionIndex. оно возможно нужно при условии, что все сессии пишутся в один снифф. без чего сейчас не может жить TOM_RUS :)
ну и действительно, было бы удобно смотреть что в какой момент отправлено в какую сессию.
а если в будущем близзы сделают несколько сессий, то поле просто необходимо будет.

в общем это нужно предварительно решить, в один снифф мы сессии пишем или в разные.

LordJZ 23.07.2010 23:00

У опкода разная длина, плюс мы между модулями сниффа переносим чистые данные, без опкодов, поэтому и пишем в лог чистые данные. А чтобы читать чанк с опкодом, нужно знать направление пакета, прочитать опкод нужной длины, а затем данные. И зачем? Гораздо проще прочитать 4 байта опкода (учитывая, что сейчас 2 байта из них не используются вообще) и потом уже Х байт чистых данных.

Флаги у нас сейчас такие:
0x01 — пакет был создан искусственно, и подставной отправитель о нем не знает
0x02 — пакет был остановлен искусственно, и получатель его не принял
0x04 — пакет был вытащен из хвоста другого пакета (таких 85%)
0x08 — пакет был получен по-частям

Konctantin 23.07.2010 23:15

Цитата:

в общем это нужно предварительно решить, в один снифф мы сессии пишем или в разные.
я думаю надо писать в 1 файл.

RomanRom2 23.07.2010 23:18

Цитата:

Сообщение от LordJZ (Сообщение 11156)
У опкода разная длина, плюс мы между модулями сниффа переносим чистые данные, без опкодов, поэтому и пишем в лог чистые данные. А чтобы читать чанк с опкодом, нужно знать направление пакета, прочитать опкод нужной длины, а затем данные. И зачем? Гораздо проще прочитать 4 байта опкода (учитывая, что сейчас 2 байта из них не используются вообще) и потом уже Х байт чистых данных.

все равно недоумеваю. вы ведь это не руками делаете, это делает программа :) один раз написал и всё.
тем более непонятна следующая вещь: ну вот к примеру я, прежде чем работать с опкодом, читаю заголовок. ПОЛНОСТЬЮ. соответственно с направлением и вообще со всеми атрибутами. а вы как то частично его читаете?

ну хорошо. допускаю, что заголовок чанка можно привести к формату:
(byte)Direction;
(uint)UnixTime (время)
(uint)TickCount (точное время)
(uint)Data.Length (длина Data, опкод сюда не входит. или входит???)
(uint)Opcode (для RAW тут FFFFFFFF)
(byte[])Data (данные без опкода)
возможно это действительно немного удобнее и универсальней, в плане выравнивания полей. я за выравнивание. и за такой вот на мой взгляд логический порядок полей.

Цитата:

Сообщение от LordJZ (Сообщение 11156)
Флаги у нас сейчас такие:
0x01 — пакет был создан искусственно, и подставной отправитель о нем не знает
0x02 — пакет был остановлен искусственно, и получатель его не принял
0x04 — пакет был вытащен из хвоста другого пакета (таких 85%)
0x08 — пакет был получен по-частям

это у вас какие то число проксевые заморочки. ChunkDevelopersData.
может быть такой тип данных и в чанк включить? 4х байт нам хватит?

Цитата:

Сообщение от LordJZ (Сообщение 11156)
Еще я у себя храню SessionLength — время сессии в секундах, и PacketCount. Последний для корректного чтения пакетов, чтобы в конец файла можно было вдруг, если понадобится, подпись.

в HeaderDevelopersData, имхо, можно сложить.
тоже не знаю зачем оно вам так необходимо, когда эти данные можно легко прямо со снифа считать :declare: просто не придумаю, где оно мне могло бы пригодится...

добавлено:
вот сейчас подумал, что DevelopersData чисто информативные поля. например если вы сюда будете складывать жизненноважные данные, то например мои снифы не сможете обработать/распарсить. например если вы каким то специальным образом обрабатываете пакеты с флагом
Цитата:

Сообщение от LordJZ (Сообщение 11156)
0x04 — пакет был вытащен из хвоста другого пакета (таких 85%)

то я такие пакеты просто не помечаю. я его собираю весь на этапе первого куска и сюда же и складываю в снифф.
т.е. например:

- C.пакеты
- S.пакеты
- S.01F6 жирный. но от него пришел то кусочек 1420 байт. бегу по всему снифу и собираю все все все куски и складываю в pkt уже готовый и полный пакет.
а все те пакеты, которые встречались пока я собирал эти недостающие куски в pkt будут записаны позже. так работает мой декодер raw-to-pkt.

т.е. если вам очень нужны такие пакеты, то у меня их просто не будет. кстати, а зачем они вам потом в готовом pkt?
мне вот снифы нужны для:
- наполнения базы респонсов, справочников и т.п., где нужны полностью собранные и законченные пакеты.
- наполнения заселения. тут я парсю пакеты А9 по сути только.
- ну и конечно же посмотреть, в какой последовательности что когда отсылается, для реализации какой либо системы. тоже не вижу, зачем нужно знать, что конкретно этот 01F6 был "вытащен из хвоста другого пакета" :) ну серьезно :) расскажите? мне интересно.

LordJZ 23.07.2010 23:18

А зачем? Тем более, что в нашей реализации этого тупо не получится сделать

LordJZ 23.07.2010 23:21

Цитата:

Сообщение от RomanRom2 (Сообщение 11159)
все равно недоумеваю. вы ведь это не руками делаете, это делает программа :) один раз написал и всё.
тем более непонятна следующая вещь: ну вот к примеру я, прежде чем работать с опкодом, читаю заголовок. ПОЛНОСТЬЮ. соответственно с направлением и вообще со всеми атрибутами. а вы как то частично его читаете?

ну хорошо. допускаю, что заголовок чанка можно привести к формату:
(byte)Direction;
(uint)UnixTime (время)
(uint)TickCount (точное время)
(uint)Data.Length (длина Data, опкод сюда не входит. или входит???)
(uint)Opcode
(byte[])Data (данные без опкода)
возможно это действительно немного удобнее и универсальней, в плане выравнивания полей. я за выравнивание. и за такой вот на мой взгляд логический порядок полей.

Длина именно Data.Length — т.е. размер данных, который должен быть прочитан. Размер из пакета вообще не используется.
Цитата:

это у вас какие то число проксевые заморочки. ChunkDevelopersData.
может быть такой тип данных и в чанк включить? 4х байт нам хватит?
Да можно вообще включить один байт как размер этой самый DevelopersData — тогда всем одновременно станет хорошо. И назвать ее как-нибудь SpecialData.
Цитата:

в HeaderDevelopersData, имхо, можно сложить.
тоже не знаю зачем оно вам так необходимо, когда эти данные можно легко прямо со снифа считать :declare: просто не придумаю, где оно мне могло бы пригодится...
А зачем их считать со сниффа, если можно положить количество пакетов в файл, тем самым на 100% исключив ошибки?

RomanRom2 23.07.2010 23:43

Цитата:

Сообщение от LordJZ (Сообщение 11160)
А зачем? Тем более, что в нашей реализации этого тупо не получится сделать

не понял, что зачем и что не получится сделать?

Цитата:

Сообщение от LordJZ (Сообщение 11161)
Длина именно Data.Length — т.е. размер данных, который должен быть прочитан. Размер из пакета вообще не используется.

ммм... мне казалось что размер из пакета - это то что будут ожидать клиент/сервер и это именно тот размер, который должен быть прочитан. если вы не используете размер из пакета, то откуда вы знаете, какой размер данных должен быть прочитан? не уловлю.

Цитата:

Сообщение от LordJZ (Сообщение 11161)
Да можно вообще включить один байт как размер этой самый DevelopersData — тогда всем одновременно станет хорошо. И назвать ее как-нибудь SpecialData.

можно.

Цитата:

Сообщение от LordJZ (Сообщение 11161)
А зачем их считать со сниффа, если можно положить количество пакетов в файл, тем самым на 100% исключив ошибки?

а какие ошибки, собственно? :pardon:
у меня вот очень просто все, пока есть данные в файле, я их читаю.
если чтото завершилось с ошибкой (чтение заголовка или чтение уже данных), я такой чанк вообще не обрабатываю. и заканчиваю обработку вообще, т.к. обычно это случается в момент END_OF_FILE.

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

Konctantin 23.07.2010 23:45

Цитата:

зачем нужно знать, что конкретно этот 01F6 был "вытащен из хвоста другого пакета" ну серьезно расскажите? мне интересно.
в итоге, они все равно складываются и записываются как один пакет, этот флаг ставится в самом процессе пакета, что знать что с ним делать дальше.

Konctantin 23.07.2010 23:47

Цитата:

не понял, что зачем и что не получится сделать?
это был ответ на мой пост http://ru-mangos.ru/showpost.php?p=11158&postcount=9

это можно сделать, правда с реконструкцией, а то наша система "немножко" зависит от самих коннектов.
Для каждого соединения создаются свои экземпляры

LordJZ 23.07.2010 23:51

Цитата:

Сообщение от RomanRom2 (Сообщение 11164)
не понял, что зачем и что не получится сделать?

Это я Konctantin отвечал, до того как вы свой пост отправили...
Цитата:

ммм... мне казалось что размер из пакета - это то что будут ожидать клиент/сервер и это именно тот размер, который должен быть прочитан. если вы не используете размер из пакета, то откуда вы знаете, какой размер данных должен быть прочитан? не уловлю.
У нас так получилось (и, я считаю, правильно), что переводом tcp траффика в классы типа Packet занимается один модуль, а собственно складыванием пакетов в файл — другой модуль, не имеющий самих данных из tcp пакета — т.е. только полезные данные. А размер там не нужен — есть byte[], у кого есть Length.
Цитата:

а какие ошибки, собственно? :pardon:
у меня вот очень просто все, пока есть данные в файле, я их читаю.
если чтото завершилось с ошибкой (чтение заголовка или чтение уже данных), я такой чанк вообще не обрабатываю. и заканчиваю обработку вообще, т.к. обычно это случается в момент END_OF_FILE.

ну сложите вы количество пакетов. ну будете их проверять каждый раз. по моему лишняя головная боль. это выглядит как защита, но от чего?
Дак зачем лишний раз обрабатывать исключение? Мы сделаем фиксированное количество байт в файле, и потом туда можно будет что-то приписать. Например, ту же подпись.

RomanRom2 24.07.2010 00:07

Цитата:

Сообщение от Konctantin (Сообщение 11166)
в итоге, они все равно складываются и записываются как один пакет, этот флаг ставится в самом процессе пакета, что знать что с ним делать дальше.

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

Цитата:

Сообщение от Konctantin (Сообщение 11167)
это был ответ на мой пост http://ru-mangos.ru/showpost.php?p=11158&postcount=9
это можно сделать, правда с реконструкцией, а то наша система "немножко" зависит от самих коннектов.
Для каждого соединения создаются свои экземпляры

всё, понял.
у меня сейчас тоже так же, свои экземпляры. но мне кажется это удобнее, чем в один файл писать.
на самом деле один файл со всеми сессиями нужно записать только один раз, что бы понять в какой последовательности слать пакеты, что бы реализовать эту фичу у себя на сервере.
но задайте честно себе вопрос. а вы правда будете использовать эту фичу у себя на сервере? :)
лично мне и из разных файлов понятно стало, что когда слать и что когда ожидать. ну это в общем личное.

Цитата:

Сообщение от LordJZ (Сообщение 11168)
У нас так получилось (и, я считаю, правильно), что переводом tcp траффика в классы типа Packet занимается один модуль, а собственно складыванием пакетов в файл — другой модуль, не имеющий самих данных из tcp пакета — т.е. только полезные данные. А размер там не нужен — есть byte[], у кого есть Length.

спору нет, я тоже считаю правильным, что каждый должен заниматься только своим делом. вот ваш byte[], у которого есть Length, собственно этот самый Length - кем, когда и из чего заполняется? наверняка так или иначе - из размера опкода =)))

Цитата:

Сообщение от LordJZ (Сообщение 11168)
Дак зачем лишний раз обрабатывать исключение? Мы сделаем фиксированное количество байт в файле, и потом туда можно будет что-то приписать. Например, ту же подпись.

хмм... ну тут я опять в недоумении. это ж программа. всегда бывают исключения :)
смотрите:
- в вашем случае лишние данные, их подсчет, запись, потом их чтение. опять подсчет при чтении, сравнение. ну и что делать, если вдруг они не совпадут? реально (к примеру) один байт в конце потерялся, у последнего чанка. а снифф 50 мегов. все в помойку?
- в моем случае читаем до тех пор, пока не возникнет END_OF_FILE. всё :)

LordJZ 24.07.2010 00:12

Цитата:

Сообщение от RomanRom2 (Сообщение 11172)
...
спору нет, я тоже считаю правильным, что каждый должен заниматься только своим делом. вот ваш byte[], у которого есть Length, собственно этот самый Length - кем, когда и из чего заполняется? наверняка так или иначе - из размера опкода =)))

byte[] заполняется из пакета, с размером Size (от клиента/сервера) минус размер опкода, и потом уже измеряется размер этого byte[] по надобности. Но мы за это не отвечаем.
Цитата:

хмм... ну тут я опять в недоумении. это ж программа. всегда бывают исключения :)
смотрите:
- в вашем случае лишние данные, их подсчет, запись, потом их чтение. опять подсчет при чтении, сравнение. ну и что делать, если вдруг они не совпадут? реально (к примеру) один байт в конце потерялся, у последнего чанка. а снифф 50 мегов. все в помойку?
- в моем случае читаем до тех пор, пока не возникнет END_OF_FILE. всё :)
Нет, почему. PacketCount-же не определяет количество байт. Он определяет количество пакетов, чтобы уже после пакетов можно было засунуть подпись, не позволяющую отвалиться/поменяться какому-либо байту.

Konctantin 24.07.2010 00:32

давайте не спорится, это 1 из вариантов использования DevelopersData

Konctantin 25.07.2010 00:36

итог на сегодня, текста много, а результата так и не видно... пора уже бы и договорится...

А то получается как у нас в стране, обсуждения и базара много, а результата 0...

так что господа, давайте подобьем итоги, и придем к какому-то консенсусу.

формат:
1) имя (мы ни к чему не договоримся, да и на чтение файла это не повлияет) по этому оставим как есть, пусть каждый пишет что хочет, но давайте оставим расширения файлов [PKT | RAW].

2) вариант:
Код:

[PKT | RAW]
Version
ClientBuild
ClientLanguage
DevelopersData
SessionKey

думаю вполне подойдет, если у кого-то что-то созреет, то поле DevelopersData (8 байт) к вашим услугам

3)
Код:

(byte)Direction;
(uint)UnixTime
(uint)TickCount
(uint)Opcode
(byte)ChunkDevelopersData
(uint)Data.Length
(byte[])Data

если кого-то что-то не устраивает, а я уже перечитал эту тему дважды, и всего вполне должно хватить, то пожалуйста жесткий и конструктивный аргумент, для опровержения и свое виденье данного формата.

Если ответа не будет, то думаю можно закончить данную дискуссию и утвердить данный формат (результат в 1 пост).

ЗЫ. Если мы столько будем споить и принимать решения, то позор нам всем, и никогда жить в нашей стране хорошо (я про весь СНГ) мы не будем, так как наш менталитет нам этого не даст..

RomanRom2 25.07.2010 15:49

ок. по пунктам:

1.
согласен. имя файла - на свое усмотрение. расширение файла обязательно либо .pkt либо .raw.

2.
Header, bytes[3] (R,A,W; P,K,T;)
HeaderVersion, word (3.0)
ClientBuild, uint, (число)
ClientLanguage, uint
DevelopersData, uint64
SessionKey, bytes[40]

несколько слов о полях:
- HeaderVersion. в дампе это должно выглядеть "младший байт, старший байт", т.е. так:
Код:

0000000000:  50 4B 54 00 03 CB 2D 89 │ 9D 6F C4 9B 85 20 75 6D  PKT☺☻╦-ЙЭo─ЫЕ um
- ClientLanguage. раньше это можно было легко вытащить из авторизационного трафика, там был дамп байтов enGB, enUS, буквы прямо. сейчас это переехало соттветственно в батлнет-трафик. в реалм-трафике на сколько я знаю таких данных не ходит. есть мысли, как мы будем добывать эту информацию?

3.
(byte) Direction; для серверных чанков 0хFF, для клиентских 0хСС.
(uint) UnixTime; UnixDateTime(Now).
(uint) TickCount; GetTickCount();
(byte) ChunkDevelopersData; нам точно одного байта хватит? мы же хотели переменную длину заюзать?
(uint) PKT.Length; длина данных, ВКЛЮЧАЯ Opcode
(uint) PKT.Opcode
(byte[]) PKT.Data

несколько слов о полях:
- ChunkDevelopersData
существуют два варианта реализации - с переменной длиной и с фиксированной. лично я за фиксированную длину, читать данные проще. т.е. давайте выберем один из вариантов:
1.
(uint64) ChunkDevelopersData (8 байт нам точно должно хватить на долго, учитывая что разработчиков сниферов по пальцем можно пересчитать)
2.
(byte) ChunkDevelopersData.Length
(bytes[])ChunkDevelopersData.Data

второй вариант представляется мне гиморным в плане пробегания по снифу. представьте, что бы прочитать следующий чанк нужно
1. по первому варианту:
- прочитать хидер, 1+4+4+8+4+4 байт
- прочитать PKT.Data размером PKT.Length-4 байт
2. по второму варианту:
- прочитать часть хидера, 1+4+4+1 байт
- прочиать ChunkDevelopersData.Data размером ChunkDevelopersData.Length байт
- дочитать хидер, 4+4 байт
- прочитать PKT.Data размером PKT.Length-4 байт

в общем я за первый вариант с фиксированной длиной ChunkDevelopersData. вопрос только в ее длине. 4 или 8 байт?

- PKT
формат записи пакета я настоятельно предлагаю в естественном и привычном исполнении:
- длина, включая опкод
- опкод
- данные опкода

только сделать длину поля опкода не переменной, как сейчас 2 или 4 байт, а фиксированной 4 байта. это позволит вам избежать трудности чтения невыравненных данных (подобный пример у ChunkDevelopersData с переменной длиной).

еще предлагаю ввести поле SnifferID в заголовок снифа.
все вы прекрасно понимаете, что поля DevelopersData каждой командой могут быть использованы на свое усмотрение. и если бы мы собрали такую информацию, то SnifferID помог бы понять, что именно находится в DevelopersData. и на стадии утверждения документа принять разработать и принять эти ID. ну например:
1 - WoWCore
2 - TOM_RUS
3 - Konctantin, LordJZ and Co.
и так далее.



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

в кратце обычно план такой:
- создается документ, описывающий некую функциональность и удовлетворяющий все стороны.
- создается ревью документа с длительностью на какой то срок. скажем, на неделю. вот тут да, можно говорить, если за ревью ничего не было, то документ принимается и присваивается статус "релиз".

а у нас пока что первый пункт не выполнен. то что мы долго это обсуждаем - это не долго, поверьте :) конечно, в бизнес-процессе существуют некие чекпоинты. давайте тоже будет цивилизованными и сделаем их. мое видение такое:

- в срок до 31 июля включительно мы должны разработать и утвердить документ, описывающий формат 3.0, который всех бы удовлетворил.
- в срок до 7 августа включительно будет проходить ревью документа.
- 8 августа состоится релиз документа.
- и еще один момент. ревью проводится среди каких то людей. кто у нас будет ревьюить? :) всем по моему пофигу, кроме 2-3 человек. но все же я хотел бы пригласить на ревью следющих людей:
- Konctantin
- LordJZ
- TOM_RUS
- RomanRom2
- VDm
- Deamon
- Nomad
- abdula123
- user456
- Aven
- йоха

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



на самом деле многие сейчас могут сказать, чо вы ерундой страдаете, что бы создать какой то сраный формат из 10 байт. быстренько обсудили и сделали.

давайте попробую ответить:
во первых, ключевая фраза "быстренько". вот у нас всё так, быстренько тяп ляп и погнали. нет четких процессов. и потом получается, тут сказал, тут не сказал, тут слышал, тут не слышал. денег уже нет, а дорога еще не построена. а где деньги то? ну и так далее. да, мы в данном случае быть может стреляем из пушки по воробьям, но блин, это нужно делать!

во вторых, "быстренько" мы сделать не можем, по очень простой причине - мы не собираемся каждый день вместе в своем офисе. было бы так, все было бы гораздо быстрее и легче.



итак, один из финальных вариантов документа.

1. RAW.
1.1. заголовок снифа.
- Header, bytes[3]
R,A,W

- HeaderVersion, word
3.0
Код:

0000000000:  50 4B 54 00 03 CB 2D 89 │ 9D 6F C4 9B 85 20 75 6D  PKT☺☻╦-ЙЭo─ЫЕ um
- ClientBuild, uint
число, актуальная на данную сессию версия клиента. билд может быть добыт из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами

- ClientLanguage, uint
enGB, ruRU. актуальная на данную сессию локализация клиента. может быть добыта из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами

- DevelopersData, uint64
вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.

- SessionKey, bytes[40]
ключ текущей сессии.

1.2. заголовок чанка
- Direction, byte
для серверных чанков 0хFF, для клиентских 0хСС.

-UnixTime, uint
стандартная функция UnixDateTime(Now).

- TickCount, uint
стандартная функция GetTickCount().

- ChunkDevelopersData, bytes[8]
вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.

- RAW.Length, unit
длина данных, которые были "пойманы" снифером и подлежат записи в файл.

- RAW.Data, bytes[]
пойманные данные

2. PKT.
2.1. заголовок снифа.
- Header, bytes[3]
P,K,T

- HeaderVersion, word
3.0
Код:

0000000000:  50 4B 54 00 03 CB 2D 89 │ 9D 6F C4 9B 85 20 75 6D  PKT☺☻╦-ЙЭo─ЫЕ um
- ClientBuild, uint
число, актуальная на данную сессию версия клиента. билд может быть добыт из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами

- ClientLanguage, uint
enGB, ruRU. актуальная на данную сессию локализация клиента. может быть добыта из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами

- DevelopersData, uint64
вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.

- SessionKey, bytes[40]
ключ текущей сессии. для PKT может быть равно нулю.

2.2. заголовок чанка
- Direction, byte
для серверных чанков 0хFF, для клиентских 0хСС.

-UnixTime, uint
стандартная функция UnixDateTime(Now).

- TickCount, uint
стандартная функция GetTickCount().

- ChunkDevelopersData, bytes[8]
вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.

- PKT.Length, unit
длина игровых данных, ВКЛЮЧАЯ Opcode.

- PKT.Opcode, unit
значение опкода, выравненное до 32х бит.

- PKT.Data, bytes[]
игровые данные опкода

Konctantin 25.07.2010 15:56

Цитата:

все же я хотел бы пригласить на ревью следющих людей:
может ветку вынести из админки?

RomanRom2 25.07.2010 15:58

Цитата:

Сообщение от Konctantin (Сообщение 11320)
может ветку вынести из админки?

естесственно. сделаешь?

Konctantin 25.07.2010 16:03

сделал

Konctantin 25.07.2010 16:06

я со всем согласен http://ru-mangos.ru/showpost.php?p=11319&postcount=21

RomanRom2 25.07.2010 16:12

ок, на всякий случай, давайте я выпишу оставшиеся на данный момент нерешенные вопросы, помимо финального варианта документа.

1. - ClientLanguage. раньше это можно было легко вытащить из авторизационного трафика, там был дамп байтов enGB, enUS, буквы прямо. сейчас это переехало соттветственно в батлнет-трафик. в реалм-трафике на сколько я знаю таких данных не ходит. есть мысли, как мы будем добывать эту информацию?

2. - ChunkDevelopersData
существуют два варианта реализации - с переменной длиной и с фиксированной. лично я за фиксированную длину, читать данные проще. т.е. давайте выберем один из вариантов

3. - PKT
формат записи пакета я настоятельно предлагаю в естественном и привычном исполнении:
- длина, включая опкод
- опкод
- данные опкода

4. еще предлагаю ввести поле SnifferID в заголовок снифа.
все вы прекрасно понимаете, что поля DevelopersData каждой командой могут быть использованы на свое усмотрение. и если бы мы собрали такую информацию, то SnifferID помог бы понять, что именно находится в DevelopersData. и на стадии утверждения документа принять разработать и принять эти ID. ну например:
1 - WoWCore
2 - TOM_RUS
3 - Konctantin, LordJZ and Co.
и так далее.

Konctantin 25.07.2010 16:24

Цитата:

2. - ChunkDevelopersData
фиксированная длинна
Цитата:

- длина, включая опкод
это мне не очень нравится, по причине того, что потом надо производить еще одну математическую операцию, по вычислению длинны данных, в которых уже нет самого опкода. А фактически пользы от этого не вижу...

LordJZ 25.07.2010 16:24

Оформил.
Цитата:

  • 1. RAW.
    • 1.1. заголовок снифа.
      byte[3] Header — R,A,W
      word HeaderVersion — 3.0
      Код:

      0000000000:  50 4B 54 00 03 CB 2D 89 ¦ 9D 6F C4 9B 85 20 75 6D  PKTOOT-ЙЭo-ЫЕ um
      uint ClientBuild — число, актуальная на данную сессию версия клиента. билд может быть добыт из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами
      uint ClientLanguage — enGB, ruRU. актуальная на данную сессию локализация клиента. может быть добыта из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами
      ui64 CDevelopersData — вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.
      byte[40] CSessionKey — ключ текущей сессии.
    • 1.2. заголовок чанка
      byte Direction — для серверных чанков 0хFF, для клиентских 0хСС.
      uint UnixTime — стандартная функция UnixDateTime(Now).
      uint TickCount — стандартная функция GetTickCount().
      word ChunkDevelopersData — вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.
      uint RAW.Length — длина данных, которые были "пойманы" снифером и подлежат записи в файл.
      byte[]RAW.Data — пойманные данные
  • 2. PKT.
    • 2.1. заголовок снифа.
      byte[3] Header — P,K,T
      word HeaderVersion — 3.0
      Код:

      0000000000:  50 4B 54 00 03 CB 2D 89 ¦ 9D 6F C4 9B 85 20 75 6D  PKTOOT-ЙЭo-ЫЕ um
      uint ClientBuild — число, актуальная на данную сессию версия клиента. билд может быть добыт из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами
      uint ClientLanguage — enGB, ruRU. актуальная на данную сессию локализация клиента. может быть добыта из VersionInfo экзешника, из бинарных данных экзешника, из сетевого трафика, иными способами
      ui64 DevelopersData — вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.
      byte[40] SessionKey — ключ текущей сессии. для PKT может быть равно нулю.
    • 2.2. заголовок чанка
      byte Direction — для серверных чанков 0хFF, для клиентских 0хСС.
      uint UnixTime — стандартная функция UnixDateTime(Now).
      uint TickCount — стандартная функция GetTickCount().
      word ChunkDevelopersData — вспомогательные данные на усмотрение разработчика. это поле не может быть использовано для хранения данных, которые могут влиять на чтение снифа.
      uint PKT.Length — длина игровых данных, ВКЛЮЧАЯ Opcode.
      uint PKT.Opcode — значение опкода, выравненное до 32х бит.
      bytes[] PKT.Data — игровые данные опкода

RomanRom2:
1) Пока нету. В нашей реализации я не представляю, как это делать
2) Давайте с фиксированной. Плюс, не надо аж 8 байт к каждому пакету. 2 хватит, имхо. В моей цитате стоит word.
3) Согласен
4) Согласен

Nomad 25.07.2010 16:29

Цитата:

Сообщение от RomanRom2
2. - ChunkDevelopersData

я за плавающую длину. "сложность парсинга" одного байта для писателей
серверов и сниферов звучит несерьезно :)

Цитата:

Сообщение от RomanRom2
3. - PKT
формат записи пакета я настоятельно предлагаю в естественном и привычном исполнении:
- длина, включая опкод
- опкод
- данные опкода

только сделать длину поля опкода не переменной, как сейчас 2 или 4 байт, а фиксированной 4 байта. это позволит вам избежать трудности чтения невыравненных данных (подобный пример у ChunkDevelopersData с переменной длиной).

предлагаю не придумывать велосипед с длиной опкода, а писать тут 1в1 данные в том виде, что скушал бы клиент, если бы не шифрование.

Цитата:

Сообщение от RomanRom2
4. еще предлагаю ввести поле SnifferID в заголовок снифа.

это лучше куда-нить в п.2, к дев данным.

LordJZ 25.07.2010 16:31

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

Konctantin 25.07.2010 16:39

Цитата:

я за плавающую длину. "сложность парсинга" одного байта для писателей
серверов и сниферов звучит несерьезно
это только лишний геморой

user456 25.07.2010 16:44

Господи, ну сделайте короткий хедер, в котором к примеру оффсет (или фиксированно с адреса там 20) на структуру блоков и длина структуры, затем оффсет данных. В самой структуре отложить типы полей, возможно с названиями (ну примерно как близзы юзают для структур в dbc, да и вообще многие структуры бд так делают). Позволит забыть на долгие годы изменения в структуре пакетов.
Насчет однобайтового признака: wad как-то юзал RECV/SEND, я предпочитал SMSG/CMSG. Временами спасало если какой-то сбой происходил. Вероятность что каша совпадет с таким признаком нулевая. И если сбой произошел то не теряется весь файл до конца, просто ищеш следующий признак.

RomanRom2 25.07.2010 16:50

Цитата:

Сообщение от Konctantin (Сообщение 11325)
фиксированная длинна

Цитата:

Сообщение от LordJZ (Сообщение 11327)
RomanRom2:
1) Пока нету. В нашей реализации я не представляю, как это делать
2) Давайте с фиксированной. Плюс, не надо аж 8 байт к каждому пакету. 2 хватит, имхо. В моей цитате стоит word.
3) Согласен
4) Согласен

ок,
1) вопрос пока открыт.
2) решили фиксированную. 16 бит нам точно хватит? может уж все же 32? мало ли чего запихать сюда понадобится, значением больше чем 65535. еще один какой нибудь тиккаунт... винты сейчас у всех вроде большие.
3) решили. см. ниже...
4) тогда предлагаю его поместить прямо перед SessionKey.

Цитата:

Сообщение от Konctantin (Сообщение 11325)
это мне не очень нравится, по причине того, что потом надо производить еще одну математическую операцию, по вычислению длинны данных, в которых уже нет самого опкода. А фактически пользы от этого не вижу...

да брось, +4 или -4 - вот и все тебе математические операции.
а сокральный смысл всего этого в двух вещах:

1. унифицированность логики с RAW. где сначала идет длина данных (абстрактных), затем собственно эти данные. так и в PKT, длина и затем конкретные данные, соответствующие этой длине. прибавив к хидеру такую длину мы переместимся сразу на начало хидера следующего чанка. ну удобно же! иначе придется в этом месте применять эту математическую операцию.

2. давайте думать, логически завершенные данные, это все же опкод+данные. это законченная еденица сущности, чтоли. формат любого опкода можно представить как из двух полей:
- ID
- DATA, соответствующая этому ID
никто же не пилит А9 на составлящие. там ведь еще круче:
Код:

- ID = 0xA9
- DATA
  - ObjectsCount
  - UpdateType
      - UpdateType = 1 (create from Object)
        - свой набор данных
      - UpdateType = 2 (update Fields)
        - свой набор данных
      - UpdateType = 3 (create for self)
        - свой набор данных
, где (например)
свой набор данных UpdateType = 3
- ObjectType = 1 (item)
  - свой набор данных ObjectType = 1
- ObjectType = 2 (container)
  - свой набор данных ObjectType = 2
- ObjectType = 3 (unit)
  - свой набор данных ObjectType = 3
- ObjectType = 4 (player)
  - свой набор данных ObjectType = 4
, где (например)
свой набор данных ObjectType = 4
- свой move-block
- в завимости от флагов плюс дополнительные данные

а у ObjectType = 1 такие флаги вообще не встречаются и соответственно данных нет...

ну короче не грузись :) я хотел сказать, что логически законченную еденицу данных нельзя разделять, да чото увлекся :)

эти две причины достаточно убедительны для тебя?

VDm 25.07.2010 16:56

Создайте, где-нибудь Wiki-страницу формата.
На форуме минимальные отличия в описании формата не видны совершенно.

Nomad 25.07.2010 16:57

Цитата:

Сообщение от Konctantin (Сообщение 11331)
это только лишний геморой

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

RomanRom2 25.07.2010 16:59

Цитата:

Сообщение от Nomad (Сообщение 11336)
а если я хочу имя аккауна своего агента держать? чтобы знать, кому пистонить за не вычищеный кеш и пр? тут уж вариант с доп данными в конце файла интереснее звучит. писать туда оффсет своего блока данных.

у тебя есть CMSG_AUTH_SESSION с именем аккунта :secret:

LordJZ 25.07.2010 17:00

32 бита на DevelopersData при каждом пакете и 64 в заголовке файла — согласен

VDm 25.07.2010 17:19

Если никак не получается решить для всего формата сразу, давайте хотя-бы определимся с заголовком:
Код:

struct FileHeader
{
  byte signature[3]; // 'PKT' | 'RAW'.
  word version; // == 0x0003 - для версии 3.0.
  byte snifferID; // Распределить уникальные номера.
  uint build; // Номер сборки клиента, обратите внимание, тип uint (4 байта).
  byte language[4]; // Язык клиента: 'ruRU', 'enGB' и т.д.
  byte sessionKey[40]; // Ключ сессии, для PKT не используется и может быть заполнен как угодно (лучше нулями).
  uint optionalHeader; // Размер опционального заголовка в байтах,
                      // который идет сразу после заголовка файла и содержит все, что угодно.
                      // Если optionalHeader == 0, тогда опциональный заголовок в файле отсутствует.
};
// sizeof(FileHeader) == 3 + 2 + 1 + 4 + 4 + 40 + 4 = 58 байт (align == 1)


RomanRom2 25.07.2010 17:20

господа, поступило шикарное предложение по формату чанка:

(byte)Direction;
(uint)UnixTime
(uint)TickCount
(uint)Data.Length
(uint)DD.Length
(byte[])Data
(byte[])DD

как вам?
при этом хидер читается структурой, что удобно само по себе.
после хидера идут данные опкода.
после данных опкода идут DevelopersData, если DD.Length больше нуля.
в данном варианте сведены к минимуму все затраты и DD стал переменной длины, что тоже должно всех устроить.

правда в этом случае, к великому сожалению Константина, (uint)Data.Length будет содержать данные вместе с опкодом, а Data данные вместе с опкодом. ну в прочем это само по себе и вытекло бы, как ни крути.

хех. вон VDm предлагает ту же идею и с хидером снифа.

LordJZ 25.07.2010 17:23

RomanRom2, только опкод все-равно форматируем до 32 бит, ага?


Текущее время: 16:45. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS