|
Здравствуйте, гость ( Вход | Регистрация )
|
![]() ![]()
Сообщение
#41
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
Protocol NMDC Структурированное описание протокола NeoModus Direct Connect (NMDC), под управлением которого на сегодняшний день работает подавляющее большинство хабов. Хотя уже внедряется новый протокол ADC, однако, как говориться, всему своё время. По мере написания, на каждую команду будет появляться ссылка на пост, описывающий эту команду. Делаю тему закрытой, дабы структурировано описать команды. О структуре команд Все команды протокола начинаются с символа $. Исключение составляет команда сообщения чата, которая должна иметь следующую структуру: Код <Ник> Сообщение| При этом, данный синтаксис команды чата обязателен в направлении клиент -> хаб, в то время, как хаб может отсылать клиенту любые сообщения, не начинающиеся с символа $, и клиент должен принимать такие сообщения, однако обработка таких сообщение не регламентирована протоколом (клиент может отображать такие сообщения как в чате, так и в статусной строке, или же вовсе игнорировать такие сообщения).Символы-разделители протокола: $, | и пробел. Протокол не имеет экранирующих символов, поэтому для отсылки символов $ и | в параметрах команд нужно использовать их коды: $ и | Строка сообщения разделяется на команды по средствам символа |. Пример трёх команд, отосланных одной строкой: Код $Cmd1 параметр|$Cmd2|$Cmd3 параметр1 параметр2$параметр3| Взаимодействие хаб-клиент $BadPass $Close $ConnectToMe $ForceMove $GetINFO $GetNickList $GetPass $Hello $HubIsFull $HubName $HubTopic $Key $Kick $Lock $LogedIn $MyINFO $MyPass $MultiConnectToMe $MultiSearch $NickList $OpForceMove $OpList $Quit $RevConnectToMe $Search $SR $Supports $UserCommand $UserIP $Version $ValidateNick $ValidateDenide Взаимодействие клиент-клиент $Cancel $Canceled $Direction $Error $Failed $FileLength $Get $GetListLen $Key $Lock $MaxedOut $MyNick $Ping $Send $To Взаимодействие хаб-хаб $FeaturedNetworks $ConnectToMe $Search $SR $Up $UpToo Взаимодействие хаб-хаблист $Key $Lock $Supports Взаимодействие пингер-хаб $BotINFO $HubINFO $Key $Lock $Supports Команды характеристик $ADCGET / $ADCSND $BotList $Capabilities $FeaturedNetworks $GetZBlock $MCTo $Sending $UGetBlock $UGetZBlock $Z $ZOn Разное TTH Lock2Key Известные характеристики Хаб-Клиент: BotList ClientID Feed HubTopic IN MCTo NoGetINFO NoHello OpPlus QuickList TTHSearch UserCommand UserIP2 ZLine ZPipe0 Клиент-Клиент: ADCGet BZList CHUNK ClientID GetCID GetTestZBlock GetZBlock MiniSlots TTHL TTHF XmlBZList ZLIG Общая (обязательная) последовательность входа на хаб. "Рукопожатие" между клиентом и хабом. Общая (обязательная) последовательность входа на хаб Хаб: Код $Lock [Код] Pk=[PrimaryKey]| Клиент: Код $Key [Рассчитанный_ключ]|$ValidateNick [Ник]| Хаб: Код $HubName [Имя_хаба]|$Hello [Ник]| Клиент: Код $Version [Версия]|$GetNickList|$MyINFO [Строка]| Хаб: Код Отсылает список пользователей. Примечания:
Вход на пальцах выглядит так: Клиент коннектится, сервер отвечает командой $Lock, что мол я такой-то сервер, на что клиент отвечает: ок раз ты такой-то сервер - вот тебе ключ ($Key) и проверь мой ник ($ValidateNick), сервер проверяет ник и отправляет клиенту приглашение на вход под этим ником ($Hello), на что клиент отправляет на сервер внутреннюю версию ($Version), запрашивает список пользователей ($GetNickList) и отправляет информацию о себе ($MyINFO), а сервер отсылает ему список пользователей хаба. Последовательность входа на хаб, который поддерживает характеристику QuickList. Входа на хаб при поддержке характеристики QuickList (быстрый вход) Хаб: Код $Lock EXTENDEDPROTOCOL[Код] Pk=[PrimaryKey]| Клиент: Код $Supports QuickList|$Key [Рассчитанный_ключ]| Хаб: Код $Supports QuickList| Клиент: Код $MyINFO [Строка]|$GetNickList| Хаб: Код Отсылает список пользователей. См. подробности в характеристике QuickList Последовательность действий хаба при регистрации в хаб-листе Последовательность действий хаба при регистрации в хаб-листе Хаб коннектится к хаб-листу. Хаб-лист: Код $Lock [Код] Pk=[PrimaryKey]| Хаб: Код $Key [Рассчитанный_ключ]|[Имя_хаба]|[Хост_хаба(:порт)]|[Описание_хаба]|[Число_юзеров]|[Текущая_шара]| Тут хаб выступает в роли клиента. Он коннектится к прописанным в настройках хаб-листам и передаёт им текущую информацию о себе. Коннект к хаб листу должен производится не чаще чем раз в 15 минут, в противном случае, хаб может быть забанен хаб-листом)). Последовательность входа на хаб PtokaX (последовательные команды могут отсылаться одной строкой, разделённой символом | ) Последовательность входа на хаб PtokaX Хаб -> Клиент: ---> $Lock EXTENDEDPROTOCOL[некий_ключ_хаба] Pk=PtokaX Примечание: Команда $LogedIn отсылается только в случае если у вас есть ключ (операторские права). Внимание! Последовательность входа указана для одного потока. Для разных потоков она может быть произвольной, поэтому никогда не используйте глобальные таблицы пользователей, дабы сохранить принцип многопоточности. Последовательность команд при получении списка пользователей (GetNickList) на хабе PtokaX Последовательность команд при получении списка пользователей (GetNickList) на хабе PtokaX Клиент -> Хаб: ---> $GetNickList| Последовательность входа на хаб HeX (последовательные команды могут отсылаться одной строкой, разделённой символом | ) Последовательность входа на хаб HeX Хаб -> Клиент: ---> $Lock EXTENDEDPROTOCOL[некий_ключ_хаба] Pk=versiunea5.03 Примечание: Данный хаб различает вход и переподключение к хабу! Это достигается с помощью задержки в отправлении команды $Quit. Материал из этой темы перенесён в вики: Сообщение отредактировал Setuper - 18.1.2012, 21:48 |
|
|
![]() |
![]()
Сообщение
#42
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$MCTo
Синтаксис: Код $MCTo: [Ник_принимающего] $[Ник_отсылающего] [Сообщение]| Направление команды: Клиент ---> Хаб Описание: Данная команда отсылает сообщение пользователю, которое видно в чате только ему. Спасибо сказали: |
|
|
![]()
Сообщение
#43
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$MyNick
Синтаксис: Код $MyNick [Ник]| Направление команды: Клиент ---> Клиент Описание: Первая команда, которую нужно послать клиенту при соединении с другим клиентом. Команда $Lock должна быть послана вслед за данной командой. Специфичность: DC++ проверяет, чтобы указанный в этой команде ник был найден хотя бы на одном из хабов, в противном случае соединение закрывается немедленно. Спасибо сказали: |
|
|
![]()
Сообщение
#44
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$Send
Синтаксис: Код $Send| Направление команды: Клиент ---> Клиент Описание: Данная команда посылается скачивающим клиентом в ответ на команду $FileLength отдающего клиента. Команда просит отдающего клиента начать отдачу файла. Спасибо сказали: |
|
|
![]()
Сообщение
#45
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$To
Синтаксис: Код $To: [Ник_получателя] From: [Ник_отправителя] $<[Ник]> [Сообщение]| Направление команды: Клиент ---> Хаб Хаб ---> Клиент Описание: Эта команда используется для отправки личного сообщения. [Ник] - этот параметр не обязан совпадать с ником отправителя (это может быть, например, бот), НО он не обязан совпадать только в случае поступления этой команды от хаба клиенту, а не от клиента хабу! При поступлении команды от клиента хабу, последний может (обязан) проверять совпадение ника с ником отправителя. [Ник_получателя] - ник получателя приватного сообщения. При поступлении данной команды от клиента, хаб просто транслирует эту команду в соответствующее соединение. |
|
|
![]()
Сообщение
#46
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$FeaturedNetworks
Синтаксис: APN мульти-хаб-чат сообщение обычно выглядит следующим образом: Код <(YYY)XXX> MMM| Где YYY - это префикс, XXX - это ник пользователя и MMM - это сообщение. Код $FeaturedNetworks YYY$$YYY$YYY$$| YYY - идентификатор хаба в сети. На настоящее время APN MultiHubChat система может иметь до 5 таких идентификаторов, а в некоторых случаях и больше. Направление команды: Хаб ---> Хаб Описание: Команда $FeaturedNetworks - это команда дополнения к протоколу Access Point Name (APN) MultiHubChatsystem, для того, чтобы определить другие хабы и другие точки входа (IRC, Telnet) и тд. Первоначально команда была создана для того чтобы помочь разработчикам APN и для того чтобы добиться лучшей интеграции между мульти-хабами. На мульти-хабах сообщения в чат поступают с уникальными префиксами (идентификаторами), обычно длинной в 3 символа (в нике). Хаб, который получает сообщение от какого-то "своего" пользователя должен разослать его по всем остальным хабам. Реализация: Если хаб отсылает данную команду, то на хабе должен быть определён какой-то префикс, который будет применяться к пользователям хаба. Префикс хаба определяет админ хаба. Однако существуют следующие префиксы: APx - Хаб x (DC, где x - это ¹, ² или ³). APt - Telnet доступ (Telnet Чат Плагин) IRC - IRC доступ (IRC Плагин) APs - Shoutcast (Shoutcast Announcer Плагин) Команда $FeaturedNetworks может использоваться практически любым хабом или MHC ботом. Спасибо сказали: |
|
|
![]()
Сообщение
#47
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$MultiConnectToMe
ЧАСТИЧНО ПОДДЕРЖИВАЕТСЯ КЛИЕНТОМ DC++ Синтаксис: Код $MultiConnectToMe [Удалённый_ник] [IP_отправителя]:[Порт_отправителя] Направление команды: Клиент ---> Хаб Описание: Эта команда была придумана как команда со стороны клиента, для того чтобы иметь преимущество перед слинкованным хабом. Клиент отсылает команду $MultiConnectToMe на хаб, хаб, в свою очередь, пересылает команду $ConnectToMe по UDP на все связанные с ним хабы, на подобие того, как команда $Search отсылается хабом всем пользователям хаба. Данная команда используется совместно с командой $MultiSearch. Поддержка этой команды была ограничена в версиях oDC. Было проблематично поддерживать эту команду, потому как NMDC хаб не мог контролировать все свои линкованые части и не мог транслировать соединение с удалёнными пользователями. Таким образом, oDC клиент должен был отсылать команду $MultiConnectToMe даже тогда, когда пользователь находился в оффлайне. Пример: Код $MultiConnectToMe RemoteNick 10.10.10.10:13671
Спасибо сказали: |
|
|
![]()
Сообщение
#48
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$MultiSearch
ЧАСТИЧНО ПОДДЕРЖИВАЕТСЯ КЛИЕНТОМ DC++ Синтаксис: Активный пользователь: Код $MultiSearch [IP]:[Порт] [Строка_поиска] Направление команды: Клиент ---> Хаб Описание: Данная команда является командой со стороны клиента для того чтобы иметь преимущество перед линкованым NMDC хабом. Клиент отсылает команду $MultiSearch на хаб, хаб, в свою очередь, пересылает команду $Search по UDP на все связанные с ним хабы, на подобие того, как команда $Search отсылается хабом всем пользователям хаба. Данная команда используется совместно с командой $MultiConnectToMe. Поддержка этой команды была ограничена в версиях oDC. Её поддержка вызвана некоторыми проблемами. Для детального разбора проблем смотрите описание команды $MultiConnectToMe. Описание синтаксиса параметров смотрите в команде $Search. Спасибо сказали: |
|
|
![]()
Сообщение
#49
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$BotINFO / $HubINFO
Синтаксис: Запрос клиента на пинг: Код $BotINFO [Описание_бота]| Ответ сервера Код $HubINFO [Имя_хаба]$[Адрес_хаба:Порт]$[Описание_хаба]$[Макс_юзеров]$[Мин_шара]$[Мин_слотов]$[Макс_хабов]$[Тип]$[Владелец]| Направление команд: Клиент ---> Хаб ($BotINFO) Хаб ---> Клиент ($HubINFO) Описание: Данная команда нужна для получения более полной информации о хабе. [Описание_бота] - может быть любой строкой, обычно это информация об адресе или хаб-листе. [Имя_хаба], [Адрес_хаба] и [Описание_хаба] - это пункты, которые будут показаны в хаб-листе (некоторые хабы имеют несколько адресов это помогает определит главный адрес). Описание хабов меняется часто, поэтому требует частого обновления. [Макс_юзеров], [Мин_шара], [Мин_слотов], [Макс_хабов] - соответственно максимально допустимое число пользователей, минимально допустимая шара на хабе, минимальное число слотов, максимальное число подключенных хабов. [Тип] - этот параметр даёт информацию о программе, под управлением которой работает хаб. [Владелец] - владелец хаба или email адрес владельца хаба Если адрес хаба 127.0.0.1, то Hublist.org удалит информацию об этом хабе из своей базы данных. Поддержка: Данные команды поддерживаются следующими программами: • PtokaX • Verlihub • Yhub • SDCH • PHPDC-Hub • DB Hub >= 0.314 • GeneralBot >= 0.24 (NMDCH Script) • HubRules >= 1.11 (DCH++ Plugin) • HubList >= 0.1.0 (ODC(#)H Plugin) На поддержку данных команд указывают характеристики BotInfo/HubInfo в команде $Supports Различные хабы по разному обрабатывают данные команды, - некоторые отключают пингера после отсылки ему команды, а некоторые продолжают держать пингера на хабе, предполагая, что пингер сам разорвёт соединение с хабом. Спасибо сказали: |
|
|
![]()
Сообщение
#50
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$Ping
НЕ ПОДДЕРЖИВЕТСЯ КЛИЕНТОМ DC++ Синтаксис: Код $Ping [IP]:[Порт]| Направление команды: Клиент ---> Клиент Описание: [IP]:[Порт] - это IP и UDP порт, который отправитель пытается прослушать. Пинг измеряет время ожидания сигнала. Если вы своим клиентом пытаетесь пинговать, то вы должны быть уверены в том, что данная команда соответствует протоколу NMDC v1.0 beta 9 и поддерживается другим клиентом. Спасибо сказали: |
|
|
![]()
Сообщение
#51
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$ADCGET / $ADCSND
Направление команды: Клиент ---> Клиент Описание: Данная команда является дополнительной клиент-клиент командой протокола NMDC, указываемая по средствам характеристики ADCGet в команде $Supports. Эта характеристика указывает на поддержку команды GET нового протокола ADC, и используется для скачивания файлов между клиентами. Команды должны выполняться после того как клиенты уже связались друг с другом и готовы получать или отдавать файлы. ZLIG, TTHL, и TTHF - это все доступные дополнения команды $ADCGET запрос: Код $ADCGET file TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 1154 ZL1| ответ: Код $ADCSND file TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 1154 ZL1|[Содержимое_файла] Файл-лист: запрос Код $ADCGET file files.xml.bz2 0 -1 ZL1| ответ: Код $ADCSND file files.xml.bz2 0 8775 ZL1|[Содержимое_файла] а также запрос по контрольной сумме TTH: Код $ADCGET tthl TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 -1| ответ: Код $ADCSND tthl TTH/PPUROLR2WSYTGPLCM3KV4V6LJC36SCTFQJFDJKA 0 24|[Interleaves]
Спасибо сказали: |
|
|
![]()
Сообщение
#52
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$Capabilities
Синтаксис: Код $Capabilities [Характеристика1]$[Характеристика2]$ ... $[ХарактеристикаN]| Характеристики: Поддерживается: Valknut (Hub to Client) Направление команды: Клиент ---> Хаб Хаб ---> Клиент Описание: Команда $Capabilities является расширением протокола (используется в клиенте DCGUI). Цель данной команды такая же как и у более популярной команды $Supports. Известные Характеристики: UniSearch XSearch MD4x Спасибо сказали: |
|
|
![]()
Сообщение
#53
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$GetINFO
Синтаксис: Код $GetINFO [Ник_жертвы] [Ник]| Направление команды: Клиент ---> Хаб Описание: Запрос команды $MyINFO с хаба. [Ник] - ник отправителя. [Ник_жертвы] - ник пользователя, о котором нужно узнать информацию. Сервер должен отправить строку MyINFO указанного клиента. Спасибо сказали: |
|
|
![]()
Сообщение
#54
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$GetZBlock
Синтаксис: Код $GetZBlock [Число] [Число_байт] [Имя_файла]| Направление команды: Клиент ---> Клиент Описание: Данная команда является дополнением к протоколу. На поддержку данной команды указывает характеристика GetZBlock в команде $Supports. Вместо команд $Get и $Send используется вышеприведенная команда. Параметр [Число] начинается с 0 (именно с 0, в отличии от команды $Get, в которой данный параметр начинается с 1) и обозначает начальную точку загрузки файла. [Число_байт] - это число отправляемых байт (или -1 для неизвестного или целого файла). [Имя_файла] - очевидно, что это имя файла. После этого второй клиент отвечает командой "$Sending [Байты]|[Сжатие]", если отправка прошла успешно или командой "$Failed [Описание_ошибки]|" в противном случае. Если всё в порядке, то данные будут отправляться до тех пор пока не отошлёться вся не сжатая длина файла. [Байты] - указывает сколько будет извлечено отосланных байт без сжатия, потому как отсылающий клиент не знает на сколько хорошо был сжат файл. Одна отсылка туда и обратно оптимизирует механизм передачи файла. Сжатие: Для сжатия используется библиотека ZLib (v 1.1.4 в DC++ начиная с версии 0.21), использующая динамическое сжатие. Уровень сжатия может изменяться для того чтобы снизить нагрузку на процессор или в случае если файл не сжимается. Уровень сжатия регулируется с помощью хеш-функции adler32. Команда $GetZBlock устарела, но согласно DC++ 0.696 её поддержка ещё существует. Новая реализация этой команды используется в команде $ADCGET с параметром ZL1. Спасибо сказали: |
|
|
![]()
Сообщение
#55
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$Sending
Синтаксис: Код $Sending [Конечный_байт - Начальный_байт]| Если запрошенные байты равны -1, то: Код $Sending| Направление команды: Клиент ---> Клиент Описание: Данная команда является расширением протокола. Отсылается в ответ на команду $GetZBlock, $UGetBlock, или $UGetZBlock. Оба параметра [Начальный_байт] и [Конечный_байт] имеют номера, начиная с 0; первый принятый байт будет байт с номером 0. Сначала, во время тестирования этой команды (GetTestZBlock), не было никаких параметров. Спасибо сказали: |
|
|
![]()
Сообщение
#56
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$UGetBlock
Синтаксис: Код $UGetBlock [старт] [число_байт] [имя_файла]| Пример Код $UGetBlock 0 -1 files.xml.bz2| Направление команды: Клиент ---> Клиент Описание: Это дополнение к протоколу DC++, используется вместо команд $Get и $Send. На поддержку этого дополнения указывает параметр XmlBZList в команде $Supports. • [старт] - начальный индекс файла • [число_байт] - число байт для получения или -1, если число байт неизвестно (когда файл целый) • [имя_файла] - имя получаемого файла (utf8) Отметим, что начальный индекс 0 для команды $UGetBlock подобен начальному индексу 1 для команды $Get. Другой клиент затем отсылает команду "$Sending [байты]|[данные]", если всё в порядке, иначе он отправляет команду "$Failed [описание_ошибки]|". Имя файла [имя_файла] в кодировке UTF-8 для того, чтобы допустить символы, которые отсутствуют в обычной кодировке DC (cp1252). Существует другая версия этой команды $UGetZBlock, которая поддерживает сжатие данных. Спасибо сказали: |
|
|
![]()
Сообщение
#57
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$UGetZBlock
Синтаксис: Код $UGetZBlock [старт] [число_байт] [имя_файла]| Направление команды: Клиент ---> Клиент Описание: Это дополнение к протоколу DC++. На поддержку этого дополнения указывает параметр XmlBZList в команде $Supports. Другой клиент отсылает команду "$Sending [байты]|[данные]", если всё в порядке, иначе он отправляет команду "$Failed [описание_ошибки]|". Где [байты] - это несжатое число байт (клиент не знает до какой степени сжат файл). Более детальное описание параметров смотрите в команде $UGetBlock Сжатие: Сжатие выполняется библиотекой zlib, использующей динамический уровень сжатия. Уровень сжатия может изменяться для того чтобы снизить нагрузку на процессор или в случае если файл не сжимается. Уровень сжатия регулируется с помощью хеш-функции adler32. Спасибо сказали: |
|
|
![]()
Сообщение
#58
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$Z / ZLine
Синтаксис: Код $Z [Блок]| Направление команды: Хаб -> Клиент Описание: Команда $Z используется расширением ZLine протокола NMDC. Данная команда была предложена Jove и обсуждается в основном на DCDev хабе. Команда предназначена для сжатия блоков команд. Команда $Z [Блок]| будет развёрнута в строку: $Search ... |$MyINFO...|... Используется простое zlib сжатие и дополнительное экранирование. Символ "\" экранируется так: "\\", а символ "|" так: "\P". Этого достаточно чтобы использовать взамен bzip. Данную команду следует использовать только в одном направлении хаб -> клиент. В любом другом направлении она только создаст лишнюю нагрузку. Клиент должен поддерживать эту команду. Он сообщает об этом хабу путём отсылки в команде $Supports флага ZLine Оценка: Проводились тесты для оценки эффективности данного дополнения. Программа тестирования работала следующим образом: сначала пользователи соединялись, потом пользователи генерировали события: Задержки между соединениями и событиями могут варьироваться. Настройки по умолчанию были выбраны следующими: 100 мсек между входами (10 соединений/сек) и 50 мсек между событиями (20 событий/сек). Короткий тест (приблизительно 700 сек) со 100 пользователями. Без ZLine Общий трафик: Входящий 1986998, Исходящий 58506319 С ZLine Общий трафик: Входящий 1549938, Исходящий 15913487 Тест с 1000 пользователями на хабе. Продолжительность теста примерно 22000 секунд (чуть больше 6 часов) в обоих случаях. Без ZLine Общий трафик: Входящий 58562006, Исходящий 18932614671 С ZLine Общий трафик: Входящий 48040395, Исходящий 3987767021 Тест с 4000 пользователями на хабе. Продолжительность теста примерно 5000 секунд в обоих случаях. Без ZLine Общий трафик: Входящий 11675512, Исходящий 14732322239 С ZLine Общий трафик: Входящий 11102441, Исходящий 2805387234 Ниже приведены немного другие тесты. Тесты с другими сообщениями. Основные сообщения те же самые, но кроме этого есть сообщения с произвольным числом символов. На результат влияют большие сообщения, которые труднее сжать. 1000 пользователей: Без ZLine Общий трафик: Входящий 26426307, Исходящий 8802244496 С ZLine Общий трафик: Входящий 27070505, Исходящий 4003114560 Выводы: Эффективность сжатия варьируется от 50% до 80% и зависит от количества пользователей и типа трафика. Данную команду нельзя применять для того, чтобы сжимать всё подряд. Хаб должен находить баланс между шириной полосы пропускания и ресурсностью процессора и памяти. В сущности, сжимаются только блоки команд, посылаемые клиентам. Поэтому нагрузка на процессор и память почти незаметна. Хабы, поддерживающие данное дополнение: Aquila BDCH (планируется) DDCH tkhub YnHub (планируется) NitroHub (> 0.7) Клиенты, поддерживающие данное дополнение: DCDM++ iDC++ McDC++ Z++ Спасибо сказали: |
|
|
![]()
Сообщение
#59
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
$ZOn
Синтаксис: Код $ZOn|[Блок_данных] Направление команды: Хаб -> Клиент Описание: Команда сжатия данных с использованием библиотеки zlib. Используется в хабе PtokaX. Данная команда указывает на то, что после неё идёт блок данных, который сжат при помощи библиотеки zlib. Сжатый блок распаковывается на стороне клиента, после получения. Библиотека сжатия zlib использует алгоритм сжатия LZ77. Для использования данной команды необходимо, чтобы в команде $Supports присутствовала характеристика ZPipe0. Нолик на конце характеристики указывает на тестирование данной характеристики. В конечной реализации (не тестовой) данная характеристика имеет вид: ZPipe. Окончание блока сжатых данных трактуется символом EOF (End-Of-File). См. также команду $Z Спасибо сказали: |
|
|
![]()
Сообщение
#60
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
TTH (Tiger Tree Hashing)
Описание: Тип хэш-кода. Служит для однозначной идентификации файлов в p2p сетях. Впервые появился в клиенте DC++ 0.400. Пример TTH для 0б: Код LWPNACQDBZRYXW3VHJVCJ64QBZNGHOHHHZWCLNQ Вычисления TTH: Сначала данные делим на блоки не более 1024 байта на блок. Далее к каждому получившемуся блоку спереди добавляется байт 00 - эта какт называемый Leaf Tiger Hash. Затем для каждой пары хешей вычисляется так называемый Internal Tiger Hash - это хеш от пары хешей Internal Tiger Hash или Leaf Tiger Hash с добавлением в начале байта 01. После хеширования всех пар получается один хеш, который называется Tiger Tree Root, и который является хешем всего дерева. Именно его используют для однозначной идентификации файла и указывают в различных P2P ссылках. Схема хеширования:
Вычисление количества хешей на уровне: Количество хешей на уровне можно посчитать циклически от нижнего до верхнего уровня следующим образом:
Поиск ($Search): На данный момент в DC клиентах за поиск по TTH отвечает девятый тип поиска. Строка поиска девятого типа обязательно должна содержать TTH:[base32_encoded_tth_hash] Результаты поиска ($SR): Когда клиенту известен корневой хеш файла, клиент в команде $SR не должен отсылать имя хаба. Вместо имени хаба должен стоять TTH:[base32_encoded_tth_hash]. См. описание команды $SR. Спасибо сказали: |
|
|
![]()
Сообщение
#61
|
|
![]() RusHub team lead ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Модераторы Сообщений: 4 030 Регистрация: 20.6.2008 Из: г. Королёв (Моск. обл.) Пользователь №: 46 Спасибо сказали: 1708 раз ![]() |
Lock2Key
Описание: Реализация в различных языках функции lock2key для нахождения ключа по параметру команды $Lock. Язык С/C++: CODE char *lock2key(char *lock) { int len = strlen(lock); char *key = (char *)calloc(1, len + 1); int i; for(i = 1; i < len; ++i) key[i] = lock[i] ^ lock[i-1]; key[0] = lock[0] ^ lock[len-1] ^ lock[len-2] ^ 5; for(i = 0; i < len; ++i) key[i] = ((key[i]<<4) & 0xF0) | ((key[i]>>4) & 0x0F); char *newkey = (char *)calloc(1, len + 100); char *newkey_p = newkey; for(i = 0; i < len; ++i) { switch(key[i]) { case 0: case 5: case 36: case 96: case 124: case 126: sprintf(newkey_p, "/%%DCN%03d%%/", key[i]); newkey_p += 10; break; default: *newkey_p = key[i]; ++newkey_p; } } *newkey_p = '\0'; return newkey; } Язык C++: CODE /// DCN экранирование void DCN_Escape(const char *sBuf, int iLen, string &sDest) { sDest.clear(); unsigned char c; char buf[11]; while(iLen-- > 0) { c = *(sBuf++); switch© { case 0: case 5: case 36: case 96: case 124: case 126: sprintf(buf, "/%%DCN%03d%%/", c); sDest += buf; break; default: sDest += c; break; } } } /// DCN разэкранирование void DCN_UnEscape(const string &sSrc, char *sDest, int &iLen) { string sStart = "/%DCN", sEnd = "%/"; unsigned char c; size_t iPos = sSrc.find(sStart), iPos2 = 0; iLen = 0; while((iPos != sSrc.npos) && (iLen < sSrc.size())) { if(iPos > iPos2) { memcpy(sDest + iLen, sSrc.c_str() + iPos2, iPos - iPos2); iLen += iPos - iPos2; } iPos2 = sSrc.find(sEnd, iPos); if((iPos2 != sSrc.npos) && (iPos2 - iPos <= sStart.size() + 3)) { c = atoi(sSrc.substr(iPos + sStart.size(), 3).c_str()); sDest[iLen++] = c; iPos2 += sEnd.size(); } iPos = sSrc.find(sStart, iPos + 1); } if (iPos2 < sSrc.size()) { memcpy(sDest + iLen, sSrc.c_str() + iPos2, sSrc.size() - iPos2 + 1); iLen += sSrc.size() - iPos2; } } /// Функция кодирования void lock2key(const string &sLock, string &sKey) { int iCount = 0, iLen = sLock.size(); char *key = 0, *lock = new char[iLen + 1]; DCN_UnEscape(sLock, lock, iLen); key = new char[iLen + 1]; key[0] = lock[0] ^ lock[iLen - 1] ^ lock[iLen - 2] ^ 5; while(++iCount < iLen) key[iCount] = lock[iCount] ^ lock[iCount - 1]; key[iLen] = 0; iCount = -1; while(++iCount < iLen) key[iCount] = ((key[iCount] << 4)) | ((key[iCount] >> 4)); DCN_Escape(key, iLen, sKey); delete [] key; delete [] lock; } Язык C#: CODE private static string lock2key(string Lock) { int i, len = Lock.Length; byte[] key = new byte[len]; for(i = 1; i < len; ++i) key[i] = (byte)(Lock[i] ^ Lock[i - 1]); key[0] = (byte)(Lock[0] ^ Lock[len - 1] ^ Lock[len - 2] ^ 5); for(i = 0; i < len; ++i) key[i] = (byte)(((key[i] << 4) & 0xF0) | ((key[i] >> 4) & 0x0F)); string Buf = "", Key = Encoding.Default.GetString(key); for(i = 0; i < len; ++i) switch((int)Key[i]) { case 0: case 5: case 36: case 96: case 124: case 126: Buf += String.Format("/%DCN{0:000}%/", (int)Key[i]); break; default: Buf += Key[i]; break; } return Buf; } Язык Lua (5.1): CODE function lock2key(lock) local function bitwise(x, y, bw) local c, p = 0, 1 local function bODD(x) return x ~= math.floor(x / 2) * 2 end while x > 0 or y > 0 do if bw == "xor" then if (bODD(x) and not bODD(y)) or (bODD(y) and not bODD(x)) then c = c + p end elseif bw == "and" then if bODD(x) and bODD(y) then c = c + p end elseif bw == "or" then if bODD(x) or bODD(y) then c = c + p end end x = math.floor(x / 2) y = math.floor(y / 2) p = p * 2 end return c end local key = {} table.insert(key, bitwise(bitwise(bitwise(string.byte(lock, 1), string.byte(lock, -1), "xor"), string.byte(lock, -2), "xor"), 5, "xor")) for i=2, string.len(lock),1 do table.insert(key, bitwise(string.byte(lock, i), string.byte(lock, i - 1), "xor")) end local function nibbleswap(bits) return bitwise(bitwise(bits * (2 ^ 4), 240, "and"), bitwise(math.floor(bits / (2 ^ 4)), 15, "and"), "or") end local g = {["5"] = 1, ["0"] = 1, ["36"] = 1, ["96"] = 1, ["124"] = 1, ["126"] = 1} for i=1, #key do local b = nibbleswap(rawget(key, i)) rawset(key, i, (g[tostring(b)] and string.format("/%%DCN%03d%%/", b) or string.char(b))) end return table.concat(key) end Язык PHP: CODE function lock2key($_LOCK, $port) { $lockLength = strlen($_LOCK); $LockToKey = ''; for ($j = 0; $j < strlen($_LOCK); $j++) { if($j == 0) { $h = ord($_LOCK{0}) ^ ord( $_LOCK{ $lockLength - 1} ) ^ ord( $_LOCK{ $lockLength - 2} ) ^ 5; } else { $h = ord($_LOCK{$j}) ^ ord($_LOCK{$j-1}); } $h = $h % 256; $a = (($h<<4) & 240) | (($h>>4) & 15); if($a == '126' or $a == '124' or $a == '96' or $a == '36' or $a == '5' or $a == '0') { $LockToKey .= "/%DCN"; if ($a < 100) $LockToKey .= "0"; if ($a < 10) $LockToKey .= "0"; $LockToKey .= $a; $LockToKey .= "%/"; } else { $LockToKey .= chr($a); } } return $LockToKey; } Язык Perl: CODE sub lock2key($) { my @lock = split(//, shift); my $i; my @key = (); # convert to ordinal map {$_=ord} @lock; # calc key[0] with some xor-ing magic push(@key,$lock[0]^5); # calc rest of key with some other xor-ing magic for ($i=1;$i<@lock;$i++) { push(@key, ($lock[$i]^$lock[$i-1])); } # nibble swapping for ($i=0;$i<@key;$i++) { $key[$i] = ((($key[$i] << 4) & 240) | (($key[$i] >> 4) & 15)) & 0xff; } $key[0] = $key[0] ^ $key[ @key - 1 ]; # escape some foreach (@key) { $_ = ( $_ == 0 || $_ == 5 || $_ == 36 || $_ == 96 || $_ == 124 || $_ == 126 ) ? sprintf('/%%DCN%03i%%/', $_) : chr; } # done return join('', @key); } Язык Delphi / Pascal: CODE function lock2key(StrLock : string) : string; // The follow function converts "1" (byte) to "001" (string), "10" to "010" and so on function ByteToThreeCharStr (Value : byte) : string; begin if value < 10 then result := '00'+inttostr(value) else if value < 100 then result := '0'+inttostr(value) else result := inttostr(value); end; var i : byte; Temp : string; TempChar : byte; begin result := ''; if length (StrLock) < 3 then begin result := 'BROKENCLIENT'; setlength (result,length(strlock)); exit; end; // First char temp := chr (ord (StrLock[1]) xor ord (StrLock[length(StrLock)]) xor ord (StrLock[length(strLock)-1]) xor 5); for i := 2 to length (StrLock) do temp := temp + chr (ord(StrLock[i]) xor ord (StrLock[i-1])); for i := 1 to length (temp) do begin TempChar := ord (temp[i]); // I now used assembler. In the visual basic code the same was done with ugly math asm // <- Nibble swap! We swap the last four // bits with the first four: 00101111 -> 11110010 ror TempChar, 4 end; // Some chars need to be replaced with a string like "/%DCN005%/" If (TempChar = 0) or (TempChar = 5) or (TempChar = 36) or (TempChar = 96) or (TempChar = 124) or (TempChar = 126) then result := result + '/%DCN' + ByteToThreeCharStr(TempChar) + '%/' else result := result + chr (TempChar); end; end; Язык Java: CODE private static final String CHARENCODING = "windows-1252"; public static String generateKey(String lockstr) throws UnsupportedEncodingException { byte[] lock = lockstr.split(" ", 3)[1].getBytes(CHARENCODING); byte[] key = new byte[lock.length]; for (int i = 1; i < lock.length; i++) { key[i] = (byte) ((lock[i] ^ lock[i - 1]) & 0xFF); } key[0] = (byte) ((((lock[0] ^ lock[lock.length - 1]) ^ lock[lock.length - 2]) ^ 5) & 0xFF); for (int i = 0; i < key.length; i++) { key[i] = (byte) ((((key[i] << 4) & 0xF0) | ((key[i] >> 4) & 0x0F)) & 0xFF); } String modifiedLock = new String(key,CHARENCODING); return dcnEncode(modifiedLock); } private static String dcnEncode(String lockstring) { for (int i: new int[]{0,5,36,96,124,126}) { String paddedDecimal = String.format("%03d", i); String paddedHex = String.format("%02x", i); lockstring = lockstring.replaceAll("\\x"+paddedHex, "/%DCN"+paddedDecimal+"%/"); } return "$Key "+lockstring+"|"; } Язык Visual Basic: CODE Public Function Lock2Key(StrLock As String) As String Dim TLock2Key As String, TChar As Integer If Len(StrLock) < 3 Then Lock2Key = Left$("BROKENCLIENT", Len(StrLock)) Exit Function End If TLock2Key = Chr$(Asc(Left$(StrLock, 1)) Xor Asc(Right$(StrLock, 1)) Xor Asc(Mid$(StrLock, Len(StrLock) - 1, 1)) Xor 5) For i = 2 To Len(StrLock) TLock2Key = TLock2Key & Chr$(Asc(Mid$(StrLock, i, 1)) Xor Asc(Mid$(StrLock, i - 1, 1))) Next i For i = 1 To Len(TLock2Key) TChar = Asc(Mid$(TLock2Key, i, 1)) TChar = TChar * 16 + TChar \ 16 'Swap bits 11110000 -> 00001111 TChar = TChar Mod 256 If TChar = 0 Or TChar = 5 Or TChar = 36 Or TChar = 96 Or TChar = 124 Or TChar = 126 Then Lock2Key = Lock2Key & "/%DCN" & Right$("000" & TChar, 3) & "%/" Else Lock2Key = Lock2Key & Chr$(TChar) End If Next i End Function Case "$LOCK" 'You've recived $LOCK, convert it to $KEY Dim sLock2 As String sLock2 = Split(Mid(sData2, 7), " Pk=")(0) sLock2 = Lock2Key(sLock2) Язык Python: CODE lock = self.sock.recv(1024) lock = re.findall('\$Lock[\s](.*?)[\s]', lock)[0] key = {} for i in xrange(1, len(lock)): key[i] = ord(lock[i]) ^ ord(lock[i-1]) key[0] = ord(lock[0]) ^ ord(lock[len(lock)-1]) ^ ord(lock[len(lock)-2]) ^ 5 for i in xrange(0, len(lock)): key[i] = ((key[i]<<4) & 240) | ((key[i]>>4) & 15) out = "" for i in xrange(0, len(lock)): out += unichr(key[i]) out = out.replace(u'\0', u'/%DCN000%/').replace(u'\5', u'/%DCN005%/').replace(u'\44', u'/%DCN036%/') out = out.replace(u'\140', u'/%DCN096%/').replace(u'\174', u'/%DCN124%/').replace(u'\176', u'/%DCN126%/') Язык Python 2.5.2 (Ubuntu 8.10): CODE # "lock" must be the exact lock character sequence, not the whole command.
# i.e. if the command is $Lock blah pk=bleh|, lock should be "blah" def lock_to_key(lock): "Decrypts lock to key." key = {} for i in xrange(1, len(lock)): key[i] = ord(lock[i]) ^ ord(lock[i-1]) key[0] = ord(lock[0]) ^ ord(lock[len(lock)-1]) ^ ord(lock[len(lock)-2]) ^ 5 for i in xrange(0, len(lock)): key[i] = ((key[i]<<4) & 240) | ((key[i]>>4) & 15) out = "" for i in xrange(0, len(key)): if key[i] in (0, 5, 36, 96, 124, 126): out += "/%%DCN%03d%%/" % (key[i],) else: out += chr(key[i]) return out |
|
|
![]() ![]() |
Похожие темы
Тема | Ответов | Автор | Просмотров | Последнее сообщение | |
---|---|---|---|---|---|
![]() |
Описание протокола DC Для созадния PHP клиента-"клиента" |
7 | Ацкий Слон | 15 366 | 25.6.2020, 21:37 Посл. сообщение: Alexey |
![]() |
Расширения протокола Обсуждение новых расширений протокола |
2 | alex82 | 7 092 | 11.1.2017, 16:41 Посл. сообщение: PPA |
![]() |
![]() Делаю программу |
26 | Master255 | 28 848 | 12.1.2015, 0:38 Посл. сообщение: Master255 |
![]() |
От: вопрос по NMDC. От темы с ID: 4932 |
0 | MIKHAIL | 5 436 | 25.1.2013, 19:48 Посл. сообщение: MIKHAIL |
![]() |
вопрос по NMDC. . |
6 | Lamo | 13 147 | 29.5.2012, 19:35 Посл. сообщение: Lamo |
![]() |
![]() Спецификация и тестирование IPv6 в NMDC |
109 | gif-t | 93 710 | 26.2.2012, 10:12 Посл. сообщение: AMD |
![]() |
NMDC Extensions Расширения и новые команды NMDC протокола |
10 | Meloun | 18 088 | 19.2.2012, 16:39 Посл. сообщение: gif-t |
![]() |
От: NMDC Extensions От темы с ID: 5095 |
0 | Артём | 5 495 | 4.1.2012, 18:56 Посл. сообщение: Артём |
![]() |
Поддержка сетевого протокола SCTP | 2 | CSRedRat | 6 841 | 30.12.2011, 14:57 Посл. сообщение: pro |
![]() |
ВАЖНО: ![]() Eximius |
14 | Saymon21 | 22 909 | 2.10.2011, 16:59 Посл. сообщение: Артём |
![]() |
![]() Ударим опенсорсом по нездоровой шняге |
23 | alex82 | 38 132 | 11.4.2011, 18:12 Посл. сообщение: alex82 |
![]() |
От: Пингер NMDC-хабов От темы с ID: 4787 |
1 | Invisible | 6 590 | 4.4.2011, 1:10 Посл. сообщение: EvilNico |
![]() |
ВАЖНО: Описание Протокола ADC Advanced Direct Connect Protocol |
31 | Setuper | 74 606 | 14.3.2011, 15:15 Посл. сообщение: Setuper |
![]() |
Скачивание файл-листа, nmdc Последовательность команд |
16 | HackFresse | 25 676 | 3.11.2010, 12:48 Посл. сообщение: Atlant |
![]() |
Описание | 3 | denis | 9 208 | 13.2.2010, 14:27 Посл. сообщение: Артём |
![]() |
Сейчас: 8.9.2024, 2:55 |