20 KiB
2023-02-24
TODO: libpcp-gateway-detection
Посмотреть, как libpcp ищет шлюз.
TODO: gateway-detection
Пытаться обнаружить UPnP gateway что бы просить у него пробросить порт.
Обычно это SOHO роутер, где может функционировать NAT-PMP или UPnP.
Если это модный домашний роутер типа Keenetic, там, скорее всего, будет и то, и другое.
Если это что-то не очень модное (Mac), то там может быть только NAT-PMP и мы не найдем сам gateway методом UPnP.
Что нам остаётся:
- Пытаться обнаружить его через PCP Discovery
- Взять системный Gateway из выхлопа команд (ifconfig, ipconfig и т.п)
- Взять адрес gateway из конфига
- Задавать команду поиска Gateway тоже в конфиге (может быть проблематично)
В случае поиска через UPnP да и в любом вообще случае --- мы не можем быть уверены, что это вообще наш gateway, через который мы ходим в интернет.
Это может быть какая-то L3 топология с цепочкой роутеров, тогда нас, скорее всего, ждёт провал. Мы видим, однако, что узел каким-то образом всё равно в таком случае работает, только почему-то не добавляется в PEX (расследовать).
Вероятно, алгоритмы NAT приоткрывают дырку очень ненадолго.
Таким образом, мы видим, что задача поэтапная и хорошего решения нет, любое вызывает какие-то проблемы.
Таким образом, в первом приближении предлагается пойти по пути Syncthing:
- Найти какой-то роутер по SSDP:
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1900
MAN: "ssdp:discover"
MX: 2
ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1
- Попросить его открыть порты (по NAT-PMP)
Если мы попросим открыть порты по NAT-PMP и он это сделает, скорее всего, это наш роутер.
Первый этап: нахождение роутера
- Взять из конфига, если есть
- Разослать SSDP запрос, посмотреть, кто откликнется
Без рутовых прав мы не можем: сами пользоваться ICMP, слушать сетевые интерфейсы / переводить их в промискуитетный режим.
Не зная на какой мы системе, мы не можем вызывать команды типа ipconfig/ifconfig/ip addr (хотя можем попытаться перебрать их все)
(Посмотреть, как сделать в libpcp --- оно каким-то образом пытается найти default gateway сначала).
2023-02-23
TODO: http-cache-protocol Сделать http worker, который будет поддерживать команды
GET /hash/read
GET /hash/cat
для чтения блока и стриминга блока соответственно. Сделать протокол согласования HTTP CACHE, наподобие
data HttpCache =
HttpCacheRequestRead...
| HttpCacheRequestCat ...
| HttpCacheAnnounceRead ...
| HttpCacheAnnounceCat ...
Смысл в том, что публично доступная нода может просто анонсировать свой HTTP Cache, и все могут качать с него. Файлы будут отдаваться системным вызовом sendfile, снимая всякую нагрузку с нас.
В дальнейшем можно сделать тоже самое для QUIC. То есть, сигнализация будет ходить по нашему UDP, а вот проблематичные жирные процессы будем выносить вовне.
При таком подходе, кстати, можно взять не хаскельную реализацию QUIC, а любую устраивающую.
Нам по факту надо поддержать только скачивание, остальные команды вполне могут ходить по UDP.
Напомним, что пытаться контролировать чтение каким-либо образом, кроме криптографической защиты - бессмысленно. Можно даже не утруждаться аутентификацией.
2023-02-22
TODO: prefer-local-peers Надо запоминать факт, что Peer приехал через локальный AnnouncePeer. В дальнейшем, если приезжает локальный пир с одинаковым nonce - надо брать локального. А если есть локальный и приезжает глобальный --- то надо оставлять локального.
TODO: known-peer-file Сделать опцию known-peer-file при старте hbs2-peer читает все такие файлы и добавляет все known-peer из них к общим known-peer
TODO: known-peer-options-for-config При старте hbs2-peer читает все known-peer из конфига и пингует их
TODO: drop-peer-loop-when-peer-removed
FIXME: unknown-busyloop
FIXME: fix-removing-inactive-peers Сейчас как-то слишком криво удаляет их. Не надо сначала увеличивать счётчик, потом ловить пинги.
2023-02-19
FIXME: peer-does-not-answer-to-pings Вероятно, или проблема формирования обратного адреса (sockaddr) Или проблема с хэшированием/доставанием из кэша (вряд ли). Нужно печатать sockaddr перед посылкой сообщения и отлаживать.
Второй вариант -- какой-то поток падает и исключение глотается в async-ах.
2023-02-17
TODO: reference-basic-implementation
see pep-04.txt
TODO: extract-hbs2-core
$$$ (set workflow backlog)
Оставить в hbs2-core только реализацию Messaging и Peer.
Сам протокол вынести в отдельный пакет, так, что бы на hbs2-core можно было реализовывать самые различные протоколы.
TODO: hbs2-print-acb
TODO: hbs2-create-acb
- From a text script
- ACB is a monoid: ACB + ACB = ACB
- Default ACB has root
2023-02-16
TODO: cat-metadata-command
Добавить команду, которая печатает метаданные ann. merke tree, если они есть и/или тип объекта (merkle, ann-merkle, blob)
Если дерево зашифровано -- выводит в том числе хэш ключа
TODO: check-group-encrypt-case-works
- создать group key
- положить его в store
- сохранить зашифрованный им файл
- достать сохранённый group key
- расшифровать им файл
FIXME: group-key-is-public
cat ./group1.key
# hbs2 groupkey file
# keep it private
group key is actually public. it contains encrypted records
FIXME: group-key-new-brokes-on-empty-line
cat pub
3YpCdSGw7BdTVTpaWUMxF1DbWcTwAsH6ai3wRXfvCYx6
./bin/hbs2 groupkey-new ./pub
bad pubkeys file
2023-02-15
FIXME: create-default-config
FIXME: wrong-default-config-path
TODO: make-key-optional-parameter
-k should be an optional parameter cause it comes from config now
TODO: check-if-block-announce-sufficient
Нужно проверить, достаточно ли BlockAnnounce + BlockChunks для скачивания блоков в обе стороны. Кейс, вызывающий вопросы:
[A] (NAT) [B]
| * block-announce |
+------*--------------------->+
| * |
| * get-block-size |
+<-----*----------------------+
| * |
| * |
| * block-size |
+------*--------------------->+
| * |
| * get-block-chunks |
+<-----*----------------------+
| * |
| * |
Во вторых, если блок A предлагает какой-то блок, то высока вероятность того, что у других участников его еще нет --- и если спрашивать о нём всех и ждать ответа, это может привести к тому, что блок будет качаться очень медленно. Нужно как-то или использовать веса (пиров для данного блока), или же спрашивать параллельно всех о размере блока и на следующей итерации качать блок у того, кто сообщил размер. Кстати говоря, нас тут могут обманывать, возможно, нужно в BlockSize добавить какой-то пруф, что у пира есть такой блок.
2023-02-14
2023-02-12
FIXME: busyloop-postponed
Когда остаются одни posponed блоки в очереди, которых ни у кого нет --- возникает busyloop и флуд GetBlockSize
Кажется, надо в ключ HasTimeLimits добавить хэш пингуемого блока.
TODO: introduce-peer-config
-
На одном хосте может быть несколько пиров.
-
Конфиг пира --- это каталог.
-
Сторейдж --- это стейт, следовательно, конфиг должен быть отдельно
-
Конфиг является в основном линейным, т.е изменение может происходить дописыванием настроек в конец
TODO: introduce-peer-black-list
TODO: peer-accept-block-announce-feature
Смотреть, если пир в чёрном списке --- от отвергать от него BlockAnnounce и handshake.
2023-02-09
TODO: MerkleWrap-to-MerkleAnn-or-AnnMerke
($context (commit d81038140c795e1cf30cfa05e95630ca1e639427) (file hbs2-core/lib/HBS2/Data/Detect.hs 143) )
Заменить MerkleWrap на AnnotatedMerkle или MerkleAnn
Смысл --- Merkle дерево с аннотацией.
AnnRef, получается, более не нужны. Ссылка всегда ссылается на дерево, наверное, всегда аннотированное.
У ссылки, в свою очередь, есть ссылка на AccessControlBlock.
TODO: encryption-keys-into-credentials-file
дизайн данных:
data Credentials = Credentials SignKey [(KeyId, KeyMetadata, KeyPair)]
он же "keyring", это буквально связка ключей.
операции:
hbs2 keyring list <keyring-file>
показывает публичные ключи в связке и их типы и прочее
hbs2 keyring add-new [-n key-id] <keyring-file>
добавляет ключ
hbs2 keyring del -n key-id <keyring-file>
удаляет ключ
Этот же формат ключ можно использовать и самому пиру, т.к. ему тоже нужны будут потом ключи шифрования.
Единственное, пир должен знать какой ключ из связки использовать, но это может быть либо по умолчанию первый ключ, либо передавать как-то в конфиге или же аргументах.
2023-02-07
FIXME: suckless-conf
Настало время выдохнуть и сделать fixme, потому, что их становится слишком много.
FIXME: Более мудрый алгоритм для pokePostponed
Сейчас оно слишком часто просыпается и забрасывает блоки в общую очередь, что приводит к busyloop в blockDownloadLoop. Введение HasTimeLimits улучшило ситуацию, но не сильно. Алгоритм должен быть что-то наподобие:
Посмотрели, сколько раз блок процессировался подряд. Если больше, чем X - то (что?) в общем, выкинули обратно в postponed.
С другой стороны, может GetBlockSize можно рассылать из pokePostponed, и просыпаться, если пришёл размер нашего блока
2023-02-06
Ну а так, базовый PEX заработал
TODO: Добавлять пиров в KnownPeers только после того, как они пинганулись. Т.е пинговать пиров, если их еще нет. Не добавлять в KnownPeers до того, как ответили на пинг.
TODO: Научиться убирать дубликаты пиров.
Их можно распознать по PeerNonce, но непонятно, какой из пиров оставлять. Иначе это будет реально большая проблема при скачивании.
TODO: Убедиться, что subscribe на перманентное событие НИКОГДА не вызывается в рекурсии.
Проверить ВСЕ subscribe. Возможно, вставить проверки в рантайм. Возможно, ограничить число таких событий и ругаться в рантайме.
FIXME: При вычислении burst надо каким-то образом находить плато и не лезть выше него.
FIXME: Задержку в очередь пиров при рассылке GetBlockSize, что бы не спамить пиров, пока запрос не уехал в отстой. Надо для каждого пира поставить задержку в 0.5 defBlockInfoTimeout или наоборот, в 1 defBlockInfoTimeout. #medium #asap
FIXME: добавить peer-nonce в peer-data что бы можно было определять себя при пинге и вычеркивать из known-peers, что бы пакеты по кругу не гонять. #easy
2023-02-05
fixme
Багтрекеры не нужны. Нужно сделать утилиту fixme, которая будет вести список FIXME/TODO из файлов. Формат FIXME/TODO достаточно расслабленный, но с определёнными условностями (TBD).
Каждая такая запись привязывается к файлу/строчке/гитовому коммиту. Оттуда и берёт автора, и как-то трекает историю.
Изменения workflow делаются отдельными записями, можно еще с криптоподписью (взять тот же самый credentials).
Аттачменты и прочее --- добавлять хэш-ссылками на
- объект hbs2/offgrid
- git blob
Тогда, если по этому гитовому хэшу объект где-то находится (в т.ч. вообще в любом репозитории, у нас же может быть глобальный словарь sha1 <-> offgrid-hash) то - рисуем картинку или изображаем аттачмент.
Про PEX
Надо делать PEX. PEX очень простой:
data PEXEntry e = PEXAdd (PeerAddr e)
| PEXDel (PeedAddr e)
| PEX
data PEX e = PEXRequest ???
| PEXResponse ??? [PEXEntry]
На самом деле, кто тут судьи? Кто может нам сказать - добавить пира или удалить.
Только мы сами можем решать. Поэтому, PEX может быть редуцирован до:
data PEX e = PEXRequest ???
| PEXInfo [PeerAddr e] (Maybe ???)
A B
+ -> PEXRequest -> +
| |
+ <- PEXInfo xxx ??? <- +
| |
| |
Вопрос, сколько пиров за раз отдавать, как можно нас зафлудить битыми пакетами и т.д.
Информацию о пирах лучше сделать вообще отдельным протоколом, что бы не загромождать этот.
Тогда останется только
data PEX e = PEXRequest ??? | PEXAnswer [PeerAddr e]
Оценочные суждения, что пир такой-то --- редиска и т.п. можно оставить за кадром. Там нужны пруфы или сеть доверия, для сети доверия надо хранить статистику пиров (что, кстати, можно).
То есть если пир, который у нас на хорошем счету, или его хороший пир говорят нам, что какой-то другой пир --- плохой, то этому можно верить.
Вопрос, база локальная или база глобальная. Вообще, это целая большая история и пока не до неё.
2023-02-03
FIXME: Перестаёт качать ближе к концу файла. После повторного анонса --- докачивает.
FIXME: Надо поднимать burst в процессе скачивания блоков
FIXME: Надо динамически повышать/понижать burst в процессе скачивания
NOTE: Почему вообще получается потеря пакетов? Такого не должно быть.
TODO: Нужно исследовать потерю чанков/блоков, и произвести сравнительные замеры при помощи iperf/netperf что бы понять, теряются ли вообще пакеты или нет.
2023-02-01
Вести баги это слишком формально и накладно, даже в упрощенном виде. Можно вести их в виде девлога.
FIXME: Обработка ошибок в асинхронном приложении. Async-и жрут исключения, даже, когда удаётся их перехватить и пробросить дальше. Например, если не удалось забиндиться на адрес, исключение стреляет, но код ошибки при выходе всё еще 0.