Files
ipoim/README.md
2026-03-27 01:04:25 +03:00

140 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Internet Protocol over Incidental Medium
**IPoIM** - это средство для туннелирования SOCKS5 соединения через среду передачи, которая не предназначена для туннелирования таких соединений. IPoIM разрабатывается в расчёте на то, что к нему можно без больших усилий дописывать расширения на языке C.
## Терминология
- **среда передачи** - то, через что передаются данные. Например, расширение `vk-msg` реализует передачу данных через сообщения ВК.
Значит, в контексте расширения `vk-msg` "отправить данные через среду передачи" означает "отправить данные, закодировав их в сообщение";
а "принять данные из среды передачи" - "принять сообщение в ВК и декодировать его в двоичный вид".
## Архитектура
- **`main.c` - входная точка приложения**
- **`event_loop.c`, `event_loop.h` - реализация событийного цикла**\
Здесь реализована асинхронная обработка событий через `epoll`
- **`connection.c`, `connection.h` - реализация соединения**\
Здесь реализован контроль за существующим соединением.
- **`client.c`, `client.h` - реализация клиента**\
Здесь реализовано установление соединения с сервером.
- **`server.c`, `server.h` - реализация сервера**\
Здесь реализован сервер.
- **`priv_medium.c`, `priv_medium.h`**\
Здесь реализованы внутренние функции IPoIM, связанные с Medium API. Эти функции не должны вызываться из кода расширений.
- **`medium.c`, `medium.h`**\
Здесь реализованы функции Medium API, которые вызываются из кода расширения.
- **`mediums/medium_<NAME>.c`, `mediums/medium_<NAME>.h`**\
Реализация расширений. Например, файлы `medium_vk_msg.c` и `medium_vk_msg.h` реализуют среду передачи `vk-msg`.
## Разработка расширений
В своем заголовочном файле расширение должно реализовывать только функцию `void medium_<NAME>_setup_callbacks()`, которая настроит колбеки (см. далее). Никаких других "публичных" функций у расширения быть не должно, поскольку всё взаимодействие с расширением производится через колбеки, которое оно настраивает.
### Medium API
IPoIM реализует функции, которые позволяют расширению общаться с остальным приложением:
- **`void medium_epoll_ctl(int op, int fd, struct epoll_event *ev)`**
- **Что делает:**
- Вызывает `epoll_ctl` для дескриптора epoll, который отвечает за событийный цикл
- **Когда вызывать:**
- Когда нужно добавить, модифицировать или удалить описание файлового дескриптора в epoll
- **Заметки:**
- Если был вызван `close(...)` для файлового дескриптора, то не нужно вызывать эту функцию, чтобы удалить описание дескриптора из epoll. Ядро Linux само удаляет описание из epoll, если дескриптор закрывается
- **`void medium_set_callbacks(/* колбеки в порядке их перечисления в следующей главе */)`**
- **Что делает:**
- Сообщает IPoIM, какие функции соответствуют каким колбекам
- **Когда вызывать:**
- Инициализация расширения
- **Заметки:** нет
- **`void medium_on_recv_data(const void *data, int32_t size)`**
- **Что делает:**
- Сообщает IPoIM, что из среды передачи были получены данные
- **Когда вызывать:**
- При получении данных из среды передачи
- **Заметки:**
- No-op, если `data == NULL` или `size <= 0`
- **`void medium_set_ready_to_send(bool state)`**
- **Что делает:**
- Сообщает IPoIM, готово ли расширение к вызову `cbmed_on_send_data(...)`
- **Когда вызывать:**
- При изменении готовности к вызову `cbmed_on_send_data(...)` и при инициализации
- **Заметки:**
- Изначально IPoIM предполагает, что среда передачи недоступна. Поэтому эта функция должна быть вызвана, как только расширение становится готовым к вызову `cbmed_on_send_data(...)` после инициализации
- **`void medium_set_max_send_size(int32_t size)`**
- **Что делает:**
- Сообщает IPoIM, какое максимальное количество байтов можно передать `cbmed_on_send_data(...)`
- **Когда вызывать:**
- При изменении максимального количества байтов, которое может принять `cbmed_on_send_data(...)`
- **Заметки:**
- До первого вызова этой функции IPoIM предполагает, что среда передачи может передать 1024 Б за один вызов `cbmed_on_send_data(...)`
- Не допускается `size <= 0`
- **`void medium_start_timer(uint32_t id, int32_t ms)`**
- **Что делает:**
- Ставит таймер #`id` на `ms` миллисекунд. Отрицательные значения `ms` останавливают таймер
- **Когда вызывать:**
- При необходимости выполнить что-либо через какое-либо время по таймеру
- **Заметки:**
- По истечении таймера будет вызван колбек `cbmed_on_timer(...)`, а в качестве аргумента будет передано значение `id`
### Необходимые колбеки
Все колбеки, которые вызывает IPoIM рекомендуется называть с префиксом `cbmed_` (callback medium).
Время от времени `IPoIM` обращается к расширению, чтобы отправить данные. Чтобы `IPoIM` мог это делать, расширение должно реализовывать следующие колбеки:
- **`bool cbmed_on_init()`**
- **Когда вызывается:**
- IPoIM хочет инициализировать расширение
- **Желаемый исход:**
- IPoIM ожидает, что расширение инициализирует всё, что ему нужно для работы, и будет готово к работе
- **Аргументы:** нет
- **Возвращаемое значение:**
- `true` в случае успеха
- `false` в случае провала
- **Заметки**:
- эта функция никогда не будет вызвана больше, чем один раз
- до вызова этой функции работа с расширением не производится
- **`void cbmed_on_deinit()`**
- **Когда вызывается:**
- IPoIM завершает работу и освобождает ресурсы
- **Желаемый исход:**
- IPoIM ожидает, что расширение освободит все ресурсы, которые оно выделило
- **Аргументы:** нет
- **Возвращаемое значение:** нет
- **Заметки**:
- эта функция никогда не будет вызвана больше, чем один раз
- после вызова этой функции работа с расширением не производится
- **`void cbmed_on_timer(uint32_t id)`**
- **Когда вызывается:**
- Истек таймер, который был запущен функцией `medium_start_timer(...)`
- **Желаемый исход:**
- IPoIM ничего не ожидает от расширения, оно может выполнить здесь любые действия
- **Аргументы:**
- `id` - идентификатор таймера, который использовался в `medium_start_timer(...)`
- **Возвращаемое значение:** нет
- **Заметки:**
- даже если этот колбек не используется, он всё равно должен существовать, но иметь пустое тело
- **`void cbmed_on_fd_event(int fd, uint32_t events)`**
- **Когда вызывается:**
- С файловым дескриптором, добавленным при помощи `medium_epoll_ctl(...)`, что-то случилось
- **Желаемый исход:**
- IPoIM ожидает, что расширение выполнит нужные действия над файловыми дескрипторами, которые оно добавило в epoll
- **Аргументы:**
- `fd` - файловый дескриптор
- `events` - битовая маска событий (см. `man epoll_ctl`)
- **Возвращаемое значение:** нет
- **Заметки**: нет
- **`int32_t cbmed_on_send_data(const void *data, int32_t size)`**
- **Когда вызывается:**
- IPoIM хочет отправить данные через среду передачи
- **Желаемый исход:**
- IPoIM ожидает, что после вызова этого колбека, данные отправлены или запланированы к отправке
- **Аргументы:**
- `data` - двоичные данные, которые нужно отправить через среду передачи
- `size` - размер двоичный данных в байтах
- **Возвращаемое значение:**
- В случае успеха колбек должен вернуть число байтов, ушедших в среду передачи
- Если передача провалена, то колбек должен -1
- **Заметки**:
- Гарантируется `size > 0`
- Гарантируется `size <= max_send_size` (см. `medium_set_max_send_size(...)`)
- Гарантируется, что этот колбек не будет вызван, если расширение сообщило, что оно не готово к отправке данных через среду передачи (см. `medium_set_ready_to_send(...)`)