|
nedoPC.orgCommunity for electronics hobbyists, established in 2002 |
|
Author |
Message |
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Вплотную подошёл к реализации API в ПЗУ. Я думаю, что надо железобетонно зафиксировать распределение буферов по сокетами при начальной инициализации (точка входа #D000): Сокет 0 - 4кб в буфере RX и 4кб в буфере TX (основной пользовательский сокет); Сокет 1 - 2кб в буфере RX и 2кб в буфере TX (второстепенный пользовательский сокет); Сокет 2 - 1кб в буфере RX и 1кб в буфере TX (запасной пользовательский сокет на всякий пожарный); Сокет 3 - 1кб в буфере RX и 1кб в буфере TX (системный сокет для обращения к внешним сервисам). Вызов функции socket (не имеет аналога в визнете, но должен будет работать как в BSD сокетах) будет возвращать следующий свободный сокет с указанными параметрами (область применения AF_LOCAL, AF_INET или AF_PACKET и тип сокета SOCK_STREAM, SOCK_DGRAM или SOCK_RAW) для использования в пользовтельской программе - от 0 до 2 для интернет-сокетов (AF_INET) или raw-сокетов (AF_INET для IPRAW или AF_PACKET для MACRAW) и >=0x10 для локальных сокетов (AF_LOCAL или что тоже самое AF_UNIX - это всё пойдёт мимо визнета). Сокет 3 всегда будет использоваться системой для "подводных" обращений к sprinternet.io:8080 (например для резолва доменных имён).
|
26 Feb 2021 21:38 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Пока вызовы такие получаются (флаг C - ошибка): #D000 - netinit (HL - адрес буфера 64 символа) -> ABC (версия фирмваре) - вызов берёт из EEPROM настройки и записывает их в визнет, подготавливая его для работы, а также копирует содержимое идентификационной строки с версией прошивки в буфер; #D003 - getconf (возврат IP-конфигурации путём копирования 32 байт с адреса HL и 6 байт мака с адреса DE) - возвращает конфигурацию в том виде, как она сохранена в EEPROM (имя пользователя, IP-адрес, маска, гейтвей, 3 экстра байта для DHCP и 1 байт таймзона) + MAC; #D006 - getvar (HL=name, DE=buf, A=maxsize) -> C,A - прочитать переменную с именем, взятым по указателю HL из persistent storage (возвращает количество скопированных байт в C и сколько жизни осталось у переменной в минутах в регистре A, причём #FF будет означать >=255 минут); #D009 - setvar (HL=name, DE=value, A=minutes) -> C,A - записать (поменять) значение переменной с именем, взятым по указателю HL, новое значение берётся по указателю DE (обе строки заканчиваются нулём) - опционально можно указать время жизни переменной в persistent storage (0 - вечная переменная, 255 - живёт 24 часа, а остальные значения - это время жизни в минутах от 1 минуты до 4ч14м), в регистре C вернётся количество записанных байтов, в регистре A вернётся смещение, по которому переменная была записана в EEPROM - если оно #FF, то это значит, что место в EEPROM закончилось и переменная была записана в ОЗУ (хотя наверное для первой версии можно просто ошибку возвращать - памяти EEPROM должно хватить на размещение 95 коротких переменных (когда имя=значение умещается в 26 байт) либо чуть меньшее количество, если имя или значение длинные - можно длину имени переменной ограничить скажем в 25 байтов, а длину значения - в 100); #D00C - setip (изменение IP-конфигурации с адреса HL) -> A - запись в EEPROM IP-адреса, маски и гейтвея (если IP-адрес нулевой, то в недалёком будущем оно будет в рамках локальной сети делать DHCP запрос) и возвращает код ошибки (0 если всё Ок)- изменение конфигурации повлечёт за собой ре-инициализацию визнета; #D00F - socket (D=domain, E=type) -> A - возвращает следующий свободный сокет (если тип сокета AF_INET или AF_PACKET, то сокетов может быть максимум 3, а если AF_LOCAL, то скажем 16); #D012 - bind (A=sock, HL=my_addr, E=addrlen) -> A - устанавливает порт для сокета (вызывает функцию визнета OPEN для открытия серверного сокета) и возвращает код ошибки (0 если всё Ок); #D015 - listen (A=sock, E=backlog) -> A - слушает входящие сообщения серверного TCP сокета (backlog в данный момент может принимать значения от 0 до 2 - вызывает функцию визнета LISTEN если сокет один либо OPEN/LISTEN несколько раз, если требуемых сокетов больше чем 1) и возвращает код ошибки (0 если всё Ок); #D018 - accept (A=sock, HL=in_addr, E=addrlen) - в регистре A возвращает сокет, к которому подцепился TCP клиент (функция не имеет аналога в визнете и будет реализована программно - возвращаемый сокет может совпадать или не совпадать с входящим); #D01B - shutdown (A=sock, E=param) - закрывает соединение правильным образом с серверной стороны в случае TCP (вызывает функцию визнета DISCON); #D01E - connect (A=sock, HL=their_addr, E=addrlen) -> A - коннектится к серверу по TCP со стороны клиента, используя параметры адреса (вызывает функции визнета OPEN и CONNECT), возвращает код ошибки (0 если всё Ок); #D021 - send (A=sock, HL=buf, DE=size, NO flags) -> BC - послать данные по TCP и вернуть количество переданных байт (вызывает функцию визнета SEND); #D024 - recv (A=sock, HL=buf, DE=size, NO flags) -> BC - получить данные по TCP и вернуть количество принятых байт (вызывает функцию визнета RECV); #D027 - sendto (A=sock, HL=buf, DE=size, NO flags, IY=out_addr) -> BC - послать данные по UDP и вернуть количество принятых байт (устанавливает адрес и порт удалённого конца и вызывает функцию визнета SEND); #D02A - recvfrom (A=sock, HL=buf, DE=size, NO flags, IY=in_addr) -> BC - получить данные по UDP и вернуть количество принятых байт (вызывает функцию визнета RECV и копирует адрес и порт с которых пришло сообщение в in_addr); #D02D - close (A=sock) - закрывает сокет (вызывает функцию визнета CLOSE, однако в случае серверных сокетов логика будет более запутанная, т.к. закрываемый сокет надо будет снова переиспользовать в accept); #D030 - httpget (IY=url, HL=buf, DE=maxsize) -> BC - прочитать данные из интернета по урлу в буфер ограниченного размера (в BC возвращается количество скопированных байт либо код ответа HTTP если был установлен флаг C - причём 0 будет обозначать ошибку соединения); #D033 - resolv (HL=host) -> BCDE - выдает IP-адрес в регистрах по имени сайта, расположенному по адресу HL и заканчивающемся нулевым байтом (в первой версии IP-адрес будет искаться в записях hosts и если там не найдено или просрочилось - будет производится запрос к шлюзу, а в будущем может быть реализован честный DNS-запрос); #D036 - time (A=желаемая точность в секундах, HL=опционально указатель на буфер, куда будет записано GMT время в человеческом формате) -> BCDE (unixtime) - делает запрос к шлюзу, чтобы узнать текущее время, если сохранённое время с предыдущего раза было запрошено более чем A секунд назад, а в случае A=0 оно также будет подправлять системные часы в соответствии с выставленной таймзоной, если они показывают неточное время; #D039 - hash (A=mode, HL=dataptr, DE=datasz, IY=hashptr) -> запись 20-байтового хэша RIPEMD-160 по указателю IY (A=0 для одного куска данных в памяти, A=1 инициализация для последовательности вызовов, A=2 повторение 64-байтных блоков, A=3 последний блок размером меньше 64 и выдача результата) либо запись 12-байтовой подписи в соответствии с алгоритмом HMAC-RIPEMD-160-96 по указателю IY (в случае A=4); #D03С - code (A=mode, HL=dataptr, DE=datasz, IY=outdataptr) -> кодирование/декодирование произвольного блока данных - при кодировании A=0 для hex, A=1 для urlencode, A=2 для uuencode, A=3 для base32, A=4 для base64, A=5 для base64url (по завершению IY указывает на первый байт за последним закодированным) - для декодирования к A надо прибавить 80h; #D03F - auth (HL=passptr) -> A=0 если Ок иначе ошибка + появление непустой переменной sid - авторизация в сети SprinterNet. Как можно легко догадаться, это просто цепочка джампов в начале ПЗУ (шаг между точками входа - 3 байта). P.S. Небольшое усложнение серверных функций вызвано тем, что визнет сам не поддерживает accept - если надо сделать сервер, способный обработать несколько входящих запросов одновременно, то на визнете просто открывают несколько слушающих сокетов на одном и том же порту - визнет тупо передаст входящий коннект на этот порт первому свободному сокету, который этот порт указал - это несколько противоречит апи беркли-сокетов, поэтому я решил написать некую прослойку, которая будет это несоответствие прятать и показывать наружу API как по книжке (socket -> listen -> accept) - хотя в первой версии можно просто поддержать сервера с одним обработчиком - в этом случае accept будет отдавать управление, когда произошёл коннект, и будет возвращать тот же самый сокет. P.P.S. Пока это всё про блокирующие сокеты, а в будущем можно сделать неблокирующую опцию: #D0XX - nonblock (A=sock) - установить non-blocking режим для сокета - на си это включается через fcntl(sock, F_SETFL, O_NONBLOCK) - чисто логическая функция, которая меняет поведение чтения и записи для сокета с точки зрения внешней программы. P.P.P.S. Вообще если всё пространство до #D100 разбить под джампы, то это будет 85 джампов - запас на будущие расширения Последний джамп при этом будет #D0FC и далее с адреса #D100 будет располагаться идентификационная строка, заканчивающаяся нулевым символом: P.P.P.P.S. На самом деле последним "джампом" можно сделать #D0FF, но по этому адресу будет не джамп, а RST 0 P.P.P.P.P.S. 22 марта 2021 года освободил регистровую пару BC, чтобы была возможность вызывать эти функции через DSS (RST 10h) - в этом случае подключение ISA-платы в третье окно процессора будет происходить автоматически и незаметно для пользователя.P.P.P.P.P.P.S. 18 мая 2021 года убрал флаги из функций отправки и получения данных - когда возникнет необходимость заиметь флаги, то я просто добавлю второй набор функцийP.P.P.P.P.P.P.S. 15 июля 2021 года добавил вызов #D039 для подсчёта хэша RIPEMD-160 или для подписки блока данных по алгоритму HMAC-RIPEMD-160-96, вызов #D03C для кодирования и декодирования блока данных и вызов #D03F для авторизации в сети SprinterNet (к вопросу о том, что такое base32, base64 и base64url можно почитать тут: https://datatracker.ietf.org/doc/html/rfc4648)
|
26 Feb 2021 22:28 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
В описании выше спрятал подпрограммы установки имени пользователя и таймзоны в setvar - они будут обрабатываться setvar и getvar как особые случаи (время жизни BC в данном случае будет игнорироваться): @ будет обозначать переменную с именем пользователя, которое будет записываться в EEPROM перед конфигурацией сети (ip-адрес, маска, гейтвей) - там как раз есть незанятые 16 байт; TZ будет обозначать переменную с таймзоной, причём для пользователя она будет в человеческом формате: -12 или +11:45 (а внутри она всё также будет представлена одним байтом в EEPROM) - причём при изменении таймзоны оно сразу может и системные часы поправить, чтобы показывали точное время. P.S. IP и MAC тоже можно сделать особыми случаями в getvar, при которых IP-адрес и MAC-адрес из EEPROM (на самом деле лучше из WizNET) будут возвращаться в человеческом формате скажем для вывода на экран. При попытке изменить значение таких переменных через setvar сразу будет возвращаться ошибка (взведённый флаг C). P.P.S. Может и MSK (маску) с GW (гейтвей) тоже возвращать таким же образом? Это будет полезно в будущем, чтобы узнать текущие настройки сети, когда появится DHCP - при этом в конфигурации будут также задействованы 3 байта для представления DHCP lease expiration time - это unixtime с откушенным младшим байтом, представляющим момент времени, после которого надо делать перезапрос DHCP - его также можно сделать особой переменной скажем LT, которая будет возвращать unixtime в виде шестнадцатиричного числа, например #603b8f00 (если "lease expiration" нулевой, то настройка сети является "ручной", а если нет - автоматической). Подробнее про протокол DHCP: https://www.netmanias.com/en/post/techdocs/5998/dhcp-network-protocol/understanding-the-basic-operations-of-dhcpP.P.P.S. Ещё один возможный особый случай для getvar - возвращение переменной не только по имени, но и по смещению, когда в качестве имени указывается "#xx" где xx есть 16-ричное представление такого смещения - в нашем случае от #00 до #5E - смещение умноженное на 32 задаёт адрес в EEPROM, откуда надо вычитать переменную. Если по данному смещению нет начала переменной (предыдущая переменная "заползла" в этот блок, то вернётся взведённый флаг C и A=FF. Если по данному смещению находится пустая область (либо область с просроченной переменной), то вернётся взведённый флаг C и A=0. Если переменная будет обнаружена, то флаг C будет сброшен, а в DE запишется строка вида "var=value", в BC вернётся число скопированных байт и в A вернётся оставшееся время жизни переменной в минутах (#FF если это вечная переменная либо её время оставшейся жизни больше 4ч15м). P.P.P.P.S. Ну и в дополнение можно скажем добавить восклицательный знак к предыдущему варианту "#xx!" если надо вернуть инфу как есть, без проверки expiration time (и без запроса времени со шлюза).
|
28 Feb 2021 05:12 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Пока привязка к системе нужна только по времени - чтение и запись системных часов: В будущем возможно появятся и другие точки привязки - например выделение памяти под переменные с длинными значениями... P.S. В данный момент возможны только 2 системы где этот код будет запускаться - Спринтер и TS2068, которые отличить очень просто - у первого по адресу #0000 находится инструкция #C3, а у второго - #F3 P.P.S. На TS2068 для внутреннего эмулятора часов можно использовать счётчик кадров (а можно и свои CMOS-часики поставить на сетевую платку), а для Спринтера будет 2 функции для связки с DSS: - Прочитать дату и время из системных часов, записав данные в BCD-формате по указателю HL: YYYYMMDDhhmmss (7 байтов) плюс в C будет день недели 1..7;
- Записать дату и время в системные часы, взяв данные в BCD-формате по указателю HL: YYYYMMDDhhmmss (7 байтов).
|
28 Feb 2021 17:56 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Написал инициализацию визнета параметрами из EEPROM и тут же заработал ping снаружи
|
05 Mar 2021 03:01 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
По поводу уже написанных мной и протестированных SPI-подпрограмм:
SPI_WRITE_BYTE - будет работать для любого SPI-интерфейса SPI_READ_BYTE - будет работать для любого SPI-интерфейса SPI_END - будет работать для любого SPI-интерфейса SPI_WREN - специфично только для EEPROM SPI_WRDI - специфично только для EEPROM SPI_RDSR - специфично только для EEPROM SPI_WRITE_START - содержит инициализацию для EEPROM, но можно сделать варианты для других SPI SPI_READ_START - содержит инициализацию для EEPROM, но можно сделать варианты для других SPI
Специфичные для EEPROM вещи я вытягивать в публичный API не хочу, поэтому туда пойдут только универсальные подпрограммы либо варианты для других SPI-интерфейсов (SD/MMC и внешний EXT SPI):
#D042 - SPI_WRITE_START_MMC #D045 - SPI_WRITE_START_EXT #D048 - SPI_READ_START_MMC #D04B - SPI_READ_START_EXT #D04E - SPI_END #D051 - SPI_WRITE_BYTE #D054 - SPI_READ_BYTE
#D057 - READ_INPUTS (8 bits to A) #D05A - WRITE_OUTPUTS (3 bits from A) #D05D - ???
P.S. 18 июля 2021 года дописал точки входа для SPI-функций и добавил функционал по чтению-записи GPIO
|
07 Mar 2021 03:37 |
|
|
nihirash
Junior
Joined: 17 Jul 2020 11:26 Posts: 5
|
И так, есть нюансы, которые стоит озвучить. Не стоит завязываться на единственную имплементацию сети, а по сему необходимо внести правки. Инициализация сети - стоит проводить при установке dll, благо точка входа для этого есть. Если очень хочется - первой точкой можно сделать reset - сброс сетевого контроллера(закрытие всех подключений, очищение буферов). Далее адреса писать не буду для предполагаемых входных точек, просто перечислю. Для обработки ошибок стоит использовать регистр A. Проверка на ошибку - and a : jr nz, .error. При этом позволяет сохранить и код ошибки. - Получение информации о реализации(A - набор данных).
A=1. Ответ HL = реализация может:
- отправлять ICMP PING
- автоматический ответ на PING
- резолвить имена через hosts
- резолвить имена через dns
- активные tcp-соединения
- пассивные tcp-соединения
- отправка данных по tcp до достижения состояния ESTABLISHED
- работать с UDP
- работать "сырыми сокетами"
- получение настроек сети по DHCP
- устанавливать DNS-сервер принудительно
- устанавливать IP-адрес принудительно
- не блокирующий резолвинг dns
A=2. Пул соединений Ответ B = Максимальное число TCP сокетов С = Максимальное число UDP-сокетов H = Максимальное число "сырых" сокетов L = Количество свободных "сырых" сокетов D =Количество свободных TCP-сокетов E = Количество свободных UDP-сокетов
A=3. Максимальный размер датаграммы Ответ: HL = исходящей датаграммы DE = входящей датаграммы
A=4. HL - строковый буфер(не более 40 символов). Информация о реализации Ответ: В буфер по HL - название реализации. H - мажорная версия реализации L - минорная версия
- Получение IP-адреса(A - тип IP-адреса) A = 1 - IP-адрес компьютера, A = 2 - IP-адрес шлюза, A = 3 - DNS Server, A = 4 DNS Server 2.
Ответ ip адрес в L.H.E.D
- Состояние сети.
Ответ B = 0 - закрыто подключение, 1 - установка соединения, 2 - установлено, 3 - происходит закрытие соединения(можно использовать 0).
- Резолвинг доменного имени. HL - указатель на ASCIIZ с доменом или IP-адресом. В случае, если передали ip-адрес - то его нужно просто сконвертировать в бинарное представление.
Ответ L.H.E.D - IP-адрес(если синхронный или ip-адрес получен за время работы точки входа), B = 0 - ip-адрес получен, B = 1 - операция асинхронная.
Если имеется активный асинхронный запрос - он отбрасывается и принимается новая операция.
- Получение IP-адреса при асинхронном резолвинге. Аналогично прошлому вызову, но не передается строка с доменом, используется результат прошлой операции.
Если резолвинг dns синхронный - все равно просто отдать последний результат резолвинга.
- Открытие UDP сокета. HL - порт. В случае передачи нуля в качестве порта - порт выбирается случайно
Ответ B -> socket id.
- Закрытие UDP сокета. A - socket id
- Статус UDP соединения. A - socket id.
Ответ HL - локальный порт, DE - размер датаграммы в буфере(если приняли).
- Отправка датаграммы. A - socket id, HL - указатель на структуру: dest-ip[4 byte], dest-port[2], data-len, data-pointer.
- Вычитать из буфера датаграм. A - socket id, HL - указатель на буфер, BC - максимальное число байт для получения.
Ответ L.H.E.D - IP адрес отправителя, IX - порт отправителя, BC - размер реально полученных данных.
- Открытие TCP сокета. A = 0 пассивное соединение, A = 1 активное, L.H.E.D - IP, BC - порт. B - socket id
- Закрытие TCP сокета. A = socket id
- Состояние TCP-сокета. A = socket id.
Ответ B = 0(неизвестно или закрыто), 1 = LISTEN, 2 = SYN-SENT, 3 = SYN-RECEIVED, 4 = ESTABLISHED, 5 = FIN-WAIT-1, 6 = FIN-WAIT-2, 7 = CLOSE-WAIT, 8 = CLOSING. HL - количество байт в буфере. Количество состояний можно сокращать до статусов 0, 1, 4.
- Отправка данных в TCP-стрим. A = socket id, HL - указатель на буфер, BC - число байт для отправки.
- Получение данных из TCP-стрима. A = socket id, HL - указатель на буфер, BC - число байт для отправки.
Ответ BC - сколько реально байт вычитали
- Принудительная установка IP адресов. L.H.E.D. - IP адрес, A - тип ip(1 - IP-адрес компьютера, A = 2 - IP-адрес шлюза, A = 3 - DNS Server, A = 4 DNS Server 2)
- Принудительное управление состоянием сети A = 1 подключиться, 0 = отключиться.
Каждый результатом каждого обращения в регистре A отражается статусом операции: - 0 - Операция успешна
- 1 - Операция не реализована
- 2 - Нет сетевого подключения
- 3 - Данные отсутствуют(при попытке чтения из сокета)
- 4 - Не правильный параметр
- 5 - Неправильный ip-адрес
- 6 - DNS не настроен
- 7 - ошибка DNS сервера
- 8 - нет свободных соединений
- 9 - такое соединение уже присутствует(например, при попытке открыть пассивный tcp-сокет на порт, который уже слушает пассивный сокет).
- 10 - соединение отсутствует(socket id не действителен)
- 11 - состояние соединение не подходит для операции
- 12 - датаграмма слишком большая
|
22 Mar 2021 13:14 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
> Инициализация сети - стоит проводить при установке dll, благо точка входа для этого есть. Ну во первых, это не DLL, а API в бортовом ПЗУ, которое подключается в третье окно. А в DLL этот API не влезет, т.к. мой DLL подразумевает, что регистровые пары BC и HL заняты. > Для обработки ошибок стоит использовать регистр A. Проверка на ошибку - and a : jr nz, .error. При этом позволяет сохранить и код ошибки. В Спринтере заведено ошибку возвращать через флаг C - если он взведён, то регистр A может содержать код ошибки. > Получение информации о реализации Ну может быть > Пул соединений Тут не понятно - любой сокет может быть UDP-сокетом, TCP-сокетом или RAW-сокетом - зачем их считать отдельно? > Максимальный размер датаграммы В каком месте посикса такое есть? > Состояние сети У меня каждый сокет может быть подключен или не подключен > Ответ L.H.E.D - IP-адрес( Всю жизнь сетевые числа записывались в Big-Endian - почему LHED? HLDE ведь (ну или BCDE для пущей логичности) Далее твои варианты открытия/закрытия UDP и TCP нифига не стандарт - ни посикс, ни никакой другой > Принудительное управление состоянием сети A = 1 подключиться, 0 = отключиться. Что значит подключиться/отключиться? Шнур Ethernet выдернуть? По поводу статусов и кодов ошибок - у визнета они свои и так как в BSD сокетах оно наружу не торчит, то я решил пока о них скромно умолчать. И кстати где обещанный SSL?
|
22 Mar 2021 20:02 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
| | | | Shaos wrote: | | | | Shaos wrote: Возможно надо всё объединить в один index.php, чтобы обращаться сюда как http://sprinternet:8080/?host=...&op=... и т.д. (IP-адрес имени sprinternet уже будет сохранён в hosts компьютера). Кроме того это упростит ведение учёта - каждое использование объединённого PHP-скрипта будет фиксироваться в базе данных. Возможный набор операций: op=resolv - возвращает IP-адрес по имени сервера host (операция по умолчанию); op=version - возвращает версию серверного программного обеспечения; op=unixtime - возвращает количество секунд прошедших с нуля часов 1 января 1970 года относительно сейчас либо относительно момента указанного в параметрах запроса (url-encoded param); op=https - забирает содержимое указанной веб-страницы по HTTPS и возвращает по HTTP (имя сервера указано в параметре host, а необязательный путь к файлу - в url-encoded параметре param). | | | | |
Возможное расширение для передачи сообщений: op=auth - в параметре user передаётся имя пользователя, в param - хэш пароля (зависит от даты, т.е. пригоден только до полуночи по гринвичу), а в ответ с сервера уходит sid (Session ID) со временем жизни скажем сутки; op=chat - вернуть все сообщения для пользователя (который идентифицируется полем sid) и если в param что-то есть, то это новое сообщение от пользователя (там в начале может быть указан идентификатор канала куда пишем), а для перемотки прочитанного можно пользоваться числовым параметром start (у каждого сообщения есть ID, который инкрементируется автоматически). Та же самая авторизация может быть использована для некоторых других операций, например op=https и может быть даже op=resolv (чтобы исключить abuse со стороны случайных интернетчиков)... | | | | |
Операция по умолчанию op=login (вход из обычного браузера по HTTPS) Ещё есть операция регистрации op=register (тоже из браузера и тоже по HTTPS) И как уже писалось ранее op=unixtime заменяется на op=time, т.к. оно теперь будет ещё и дату-время GMT в человеческом формате добавлять в ответ: P.S. Возможная дополнительная операция op=salt, возвращающая "соль" - строку, которая будет принимать участие в формировании криптографически защищённого хэша пароля...
|
10 Jul 2021 05:15 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
В этой таблице поле "usr" по сути чисто как комментарий, чтобы глазами было видно кто мог ту или иную операцию запросить - оно в БД запишется даже если авторизация не прошла (имя юзера неправильное или пароль не подходит). А вот таблица юзеров будет существовать отдельно. Таблица компьютеров тоже т.к. одному юзеру могут принадлежать несколько компьютеров и компьютеры можно будет передавать друг другу (надо продумать процедуру как это делать, но пока видимо ручками админа по просьбе с обоих сторон). Хеш-алгоритмом для передачи закодированного пароля может стать ещё не взломанный RIPEMD-160 ( https://homes.esat.kuleuven.be/~bosselae/ripemd160.html ) в котором хэш имеет длину 160 бит или 20 байт или 40 шестнадцатиричных символов. При регистрации пароль можно закодировать перед сохранением в БД (на тот случай если база утечёт чтобы никто не смог подобрать пароли). При аутентификации на стороне Спринтера надо будет посчитать хэш введённого пользователем пароля, слепить его с текущей датой по гринвичу, идентификатором материнской платы и "солью", а потом снова посчитать хэш - и вот его уже посылать как хэш пароля (всё тоже самое сервер может сделать на своей стороне и сравнить хэши). Значит при регистрации по HTTPS на сервер будет посылаться: - имя пользователя (текстовая строка из латинских букв и цифр с разрешённым подчёркиванием длиной от 3 до 16 символов); - пароль (текстовая строка из латинских букв и цифр длиной от 8 до 16 символов); - адрес электронной почты (текстовая строка длиной от 6 до 50 символов); - пин код (некое десятичное число, вычисленное из серийного номера платы). При успешной регистрации надо будет добавить запись в таблице пользователей, созданной по такой схеме: | | | | Code: CREATE TABLE spr_user ( id int unsigned primary key not null auto_increment, usr char(16) not null, pwd char(40) not null, email varchar(50) not null, utime int unsigned not null default 0, numc tinyint unsigned not null default 1, status tinyint unsigned not null default 1, unique index spr_uu (usr), unique index spr_ue (email), index spr_uc (usr,numc), index spr_ut (utime) ) ENGINE=InnoDB;
| | | | |
а также запись в таблице машин, созданной по такой схеме: | | | | Code: CREATE TABLE spr_machine ( id int unsigned primary key not null auto_increment, usr_id int unsigned not null, pin int unsigned not null, utime int unsigned not null default 0, etime int unsigned not null default 0, sig char(40), sid char(40), adr char(16) not null default "127.0.0.1", cnt int unsigned not null default 0, unique index spr_mp (pin), index spr_ms (usr_id,sid), index spr_mt (utime) ) ENGINE=InnoDB;
| | | | |
pwd, sig и sid будут хешами RIPEMD-160, поэтому они все по 40 символов (строка в виде шестнадцатиричного числа) etime это unixtime момента времени, когда должен протухнуть sid sig это ключ для подписывания посылаемого пользовательского контента (например сообщений чата или файлов) ключи sig могут быть разные для разных машин (т.к. они храняться на машине в EEPROM) и соответственно они скорее не пользователя идентифицируют, а компьютер, с которого этот пользовательский контент посылается
|
11 Jul 2021 01:08 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Всё - регистрация на https://sprinternet.io открыта!
|
11 Jul 2021 22:28 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Примеры поддерживаемых на текущий момент операций: http://sprinternet.io:8080/?op=version - версия бекенда (сейчас v1.0.0) http://sprinternet.io:8080/?op=salt - возвращает шестнадцатиричную "соль", которая будет использоваться при аутентификации для получения sid http://sprinternet.io:8080/?op=time - текущее время GMT (unixtime в хексе и дата-время в человеческом виде) http://sprinternet.io:8080/?op=time¶m=Jun%201%2002:42:33%20PDT%202021 - преобразование строки даты-времени с таймзоной в unixtime и GMT http://sprinternet.io:8080/?op=resolv&host=nedopc.org - резолвер доменных имён (пока не поддержим полноценный протокол DNS) Теперь уже можно начинать что-то кодить под эмулятор
|
12 Jul 2021 02:14 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
| | | | Shaos wrote: В описании выше спрятал подпрограммы установки имени пользователя и таймзоны в setvar - они будут обрабатываться setvar и getvar как особые случаи (время жизни BC в данном случае будет игнорироваться): @ будет обозначать переменную с именем пользователя, которое будет записываться в EEPROM перед конфигурацией сети (ip-адрес, маска, гейтвей) - там как раз есть незанятые 16 байт; TZ будет обозначать переменную с таймзоной, причём для пользователя она будет в человеческом формате: -12 или +11:45 (а внутри она всё также будет представлена одним байтом в EEPROM) - причём при изменении таймзоны оно сразу может и системные часы поправить, чтобы показывали точное время. P.S. IP и MAC тоже можно сделать особыми случаями в getvar, при которых IP-адрес и MAC-адрес из EEPROM (на самом деле лучше из WizNET) будут возвращаться в человеческом формате скажем для вывода на экран. При попытке изменить значение таких переменных через setvar сразу будет возвращаться ошибка (взведённый флаг C). P.P.S. Может и MSK (маску) с GW (гейтвей) тоже возвращать таким же образом? Это будет полезно в будущем, чтобы узнать текущие настройки сети, когда появится DHCP - при этом в конфигурации будут также задействованы 3 байта для представления DHCP lease expiration time - это unixtime с откушенным младшим байтом, представляющим момент времени, после которого надо делать перезапрос DHCP - его также можно сделать особой переменной скажем LT, которая будет возвращать unixtime в виде шестнадцатиричного числа, например #603b8f00 (если "lease expiration" нулевой, то настройка сети является "ручной", а если нет - автоматической). Подробнее про протокол DHCP: https://www.netmanias.com/en/post/techdocs/5998/dhcp-network-protocol/understanding-the-basic-operations-of-dhcpP.P.P.S. Ещё один возможный особый случай для getvar - возвращение переменной не только по имени, но и по смещению, когда в качестве имени указывается "#xx" где xx есть 16-ричное представление такого смещения - в нашем случае от #00 до #5E - смещение умноженное на 32 задаёт адрес в EEPROM, откуда надо вычитать переменную. Если по данному смещению нет начала переменной (предыдущая переменная "заползла" в этот блок, то вернётся взведённый флаг C и A=FF. Если по данному смещению находится пустая область (либо область с просроченной переменной), то вернётся взведённый флаг C и A=0. Если переменная будет обнаружена, то флаг C будет сброшен, а в DE запишется строка вида "var=value", в BC вернётся число скопированных байт и в A вернётся оставшееся время жизни переменной в минутах (#FF если это вечная переменная либо её время оставшейся жизни больше 4ч15м). P.P.P.P.S. Ну и в дополнение можно скажем добавить восклицательный знак к предыдущему варианту "#xx!" если надо вернуть инфу как есть, без проверки expiration time (и без запроса времени со шлюза). | | | | |
Для "lease expiration" можно использовать имя EXP вместо LT - наверное так будет понятнее (пока там всегда будет 0). P.S. Может быть все спец-имена начинать с символа @ чтобы точно ни с чем не перепуталось? P.P.S. На линуксе подсчитать хэш RIPEMD-160 у файла можно через openssl: openssl rmd160 filename
|
14 Jul 2021 23:36 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
Надо ещё одно поле добавить info varchar(100) куда писать дополнительную инфу, чтобы не перегружать поле usr - типа параметры операций, коды ошибок и т.д.
|
17 Jul 2021 20:37 |
|
|
Shaos
Admin
Joined: 08 Jan 2003 23:22 Posts: 23388 Location: Silicon Valley
|
| | | | Shaos wrote: | | | | Shaos wrote: | | | | Shaos wrote: Возможно надо всё объединить в один index.php, чтобы обращаться сюда как http://sprinternet:8080/?host=...&op=... и т.д. (IP-адрес имени sprinternet уже будет сохранён в hosts компьютера). Кроме того это упростит ведение учёта - каждое использование объединённого PHP-скрипта будет фиксироваться в базе данных. Возможный набор операций: op=resolv - возвращает IP-адрес по имени сервера host (операция по умолчанию); op=version - возвращает версию серверного программного обеспечения; op=unixtime - возвращает количество секунд прошедших с нуля часов 1 января 1970 года относительно сейчас либо относительно момента указанного в параметрах запроса (url-encoded param); op=https - забирает содержимое указанной веб-страницы по HTTPS и возвращает по HTTP (имя сервера указано в параметре host, а необязательный путь к файлу - в url-encoded параметре param). | | | | |
Возможное расширение для передачи сообщений: op=auth - в параметре user передаётся имя пользователя, в param - хэш пароля (зависит от даты, т.е. пригоден только до полуночи по гринвичу), а в ответ с сервера уходит sid (Session ID) со временем жизни скажем сутки; op=chat - вернуть все сообщения для пользователя (который идентифицируется полем sid) и если в param что-то есть, то это новое сообщение от пользователя (там в начале может быть указан идентификатор канала куда пишем), а для перемотки прочитанного можно пользоваться числовым параметром start (у каждого сообщения есть ID, который инкрементируется автоматически). Та же самая авторизация может быть использована для некоторых других операций, например op=https и может быть даже op=resolv (чтобы исключить abuse со стороны случайных интернетчиков)... | | | | |
Операция по умолчанию op=login (вход из обычного браузера по HTTPS) Ещё есть операция регистрации op=register (тоже из браузера и тоже по HTTPS) И как уже писалось ранее op=unixtime заменяется на op=time, т.к. оно теперь будет ещё и дату-время GMT в человеческом формате добавлять в ответ: P.S. Возможная дополнительная операция op=salt, возвращающая "соль" - строку, которая будет принимать участие в формировании криптографически защищённого хэша пароля... | | | | |
Пишу op=auth и op=https - ответ сервера на порту 8080 всегда будет считаться шестнадцатиричной строкой (за исключением ответа на корректные запросы https или chat) и в случае ошибки это будет 1 байт (2 шестнадцатиричных символа), обозначающий ошибку: 00 - неизвестное имя сервера (1 или 4 нулевых байта) 01 - неизвестная операция 02 - неуспешная авторизация (неизвестное имя пользователя или неправильный хэш) 03 - неправильная сессия (неизвестное имя пользователя либо с другого адреса либо просроченное время жизни) P.S. Думаю надо добавить возможность узнать свой внешний IP-адрес, скажем через op=resolv, указав некое специальное имя в качестве имени хоста, например myself: http://sprinternet.io:8080/?op=resolv&host=myself
|
21 Jul 2021 02:38 |
|
|
Who is online |
Users browsing this forum: No registered users and 2 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|