9.3 KiB
Internet Protocol over Incidental Medium
IPoIM - это средство для туннелирования SOCKS5 соединения через среду передачи, которая не предназначена для туннелирования таких соединений. IPoIM разрабатывается в расчёте на то, что к нему можно без больших усилий дописывать расширения на языке C.
Терминология
- среда передачи - то, через что передаются данные. Например, расширение
vk-msgреализует передачу данные через сообщения ВК. Значит, в контексте расширенияvk-msg"отправить данные через среду передачи" означает "отправить данные, закодировав их в сообщение"; а "принятие данных из среды передачи" - "принятие сообщения в ВК и его декодировка в двоичный вид".
Архитектура
main.c- входная точка приложения, оркестраторevent_loop.c,event_loop.h- реализация событийного цикла
Здесь реализована асинхронная обработка событий черезepollconnection.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>_init(), которая инициализирует всё необходимое для работы расширения. Функция должна вызвать medium_set_callbacks(...), чтобы IPoIM могло взаимодействовать с расширением. Кроме этого расширение должно инициализировать всё, что ему необходимо для работы.
Также расширение должно реализовывать функцию void medium_<NAME>_deinit(), которая освобождает ресурсы и выполняет "правильное" завершение всего, что было инициализировано в ходе работы расширения.
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
- No-op, если
- Что делает:
void medium_set_ready_to_send(bool state)- Что делает:
- Сообщает IPoIM, готово ли расширение к вызову
cbmed_on_send_data(...)
- Сообщает IPoIM, готово ли расширение к вызову
- Когда вызывать:
- При изменении готовности к вызову
cbmed_on_send_data(...)и при инициализации
- При изменении готовности к вызову
- Заметки:
- Изначально IPoIM предполагает, что среда передачи недоступна. Поэтому эта функция должна быть вызвана, как только расширение становится готовым к вызову
cbmed_on_send_data(...)после инициализации
- Изначально IPoIM предполагает, что среда передачи недоступна. Поэтому эта функция должна быть вызвана, как только расширение становится готовым к вызову
- Что делает:
void medium_set_max_send_size(int32_t size)- Что делает:
- Сообщает IPoIM, какое максимальное количество байтов можно передать
cbmed_on_send_data(...)
- Сообщает IPoIM, какое максимальное количество байтов можно передать
- Когда вызывать:
- При изменении максимального количества байтов
cbmed_on_send_data(...)
- При изменении максимального количества байтов
- Заметки:
- Изначально IPoIM предполагает, что среда передачи может передать 1024 Б за один вызов
cbmed_on_send_data(...) - Не допускается
size <= 0
- Изначально IPoIM предполагает, что среда передачи может передать 1024 Б за один вызов
- Что делает:
Необходимые колбеки
Все колбеки, которые вызывает IPoIM рекомендуется называть с префиксом cbmed_ (callback medium).
Время от времени IPoIM обращается к расширению, чтобы отправить данные. Чтобы IPoIM мог это делать, расширение должно реализовывать следующие колбеки:
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(...))
- Гарантируется
- Когда вызвается: