Authorize file transfers before I/O and revoke active group operations
This commit is contained in:
1 parent
dfdd89b5f0
commit
27eb0fa546
3 files changed
+62
-10
No files matched your search
@@ -11,6 +11,7 @@
|
||||
#include "../utun_instance.h"
|
||||
#include "../routing_layer/conn_mgr.h"
|
||||
#include "../routing_layer/etcp_router.h"
|
||||
#include "../routing_layer/topo_group.h"
|
||||
#include "../transport_layer/etcp.h"
|
||||
|
||||
#define FT_REQUEST 1 /* tid:16, object:16, size:8, offset:8 */
|
||||
@@ -61,8 +62,8 @@ static void ft_finish(struct file_transfer_op* op, int error) {
|
||||
while (*p && *p != op) p = &(*p)->next;
|
||||
if (*p) *p = op->next;
|
||||
ft->count--;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: finish peer=%llu receive=%d bytes=%llu/%llu error=%d active=%u",
|
||||
(unsigned long long)op->peer, op->receiving, (unsigned long long)op->offset,
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: finish group=%llu peer=%llu receive=%d bytes=%llu/%llu error=%d active=%u",
|
||||
(unsigned long long)op->group, (unsigned long long)op->peer, op->receiving, (unsigned long long)op->offset,
|
||||
(unsigned long long)op->size, error, ft->count);
|
||||
file_transfer_done_fn done = op->done;
|
||||
void* arg = op->arg;
|
||||
@@ -70,9 +71,21 @@ static void ft_finish(struct file_transfer_op* op, int error) {
|
||||
if (done) done(arg, error);
|
||||
}
|
||||
|
||||
/* Отложенный callback не продолжает I/O после отзыва; до возврата 0 операция уже освобождена. */
|
||||
static int ft_active(struct file_transfer_op* op) {
|
||||
if (topo_group_chat_allowed(op->ft->inst, op->group, op->peer)) return 1;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: revoke group=%llu peer=%llu receive=%d",
|
||||
(unsigned long long)op->group, (unsigned long long)op->peer, op->receiving);
|
||||
ft_finish(op, -2); return 0;
|
||||
}
|
||||
|
||||
/* Отправить подписанную кодограмму, не превышая порог очереди. */
|
||||
static int ft_send(struct file_transfer* ft, uint64_t group, uint64_t peer,
|
||||
uint8_t cmd, const uint8_t* data, size_t size) {
|
||||
if (!topo_group_chat_allowed(ft->inst, group, peer)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file_transfer: send denied group=%llu peer=%llu cmd=%u",
|
||||
(unsigned long long)group, (unsigned long long)peer, cmd); return -1;
|
||||
}
|
||||
struct ETCP_ROUTER_CONN* rc = etcp_router_conn_get(ft->inst, group, peer, ETCP_RT_ID_FILE_TRANSFER);
|
||||
if (!rc) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file_transfer: router allocation failed"); return -1; }
|
||||
queue_set_threshold(rc->send_q, 0, 0);
|
||||
@@ -113,6 +126,7 @@ static void ft_ready(struct ll_queue* q, void* arg) {
|
||||
static void ft_pump(void* arg) {
|
||||
struct file_transfer_op* op = arg;
|
||||
op->pump = NULL;
|
||||
if (!ft_active(op)) return;
|
||||
if (!op->up || op->receiving) return;
|
||||
struct file_transfer* ft = op->ft;
|
||||
if (op->offset < op->size) {
|
||||
@@ -144,6 +158,7 @@ static void ft_connected(struct CONN_MGR_HANDLE* h, uint64_t peer, uint64_t grou
|
||||
enum conn_mgr_event event, void* arg) {
|
||||
(void)h; (void)peer; (void)group;
|
||||
struct file_transfer_op* op = arg;
|
||||
if (!ft_active(op)) return;
|
||||
op->up = event == CONN_EVENT_UP;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "file_transfer: CM event=%d peer=%llu receive=%d offset=%llu",
|
||||
event, (unsigned long long)op->peer, op->receiving, (unsigned long long)op->offset);
|
||||
@@ -157,6 +172,7 @@ static void ft_connected(struct CONN_MGR_HANDLE* h, uint64_t peer, uint64_t grou
|
||||
static void ft_tick(void* arg) {
|
||||
struct file_transfer_op* op = arg;
|
||||
op->timer = NULL;
|
||||
if (!ft_active(op)) return;
|
||||
uint64_t now = get_time_tb();
|
||||
if (now - op->progress_tb >= 300000) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file_transfer: inactivity timeout peer=%llu offset=%llu/%llu",
|
||||
@@ -181,6 +197,10 @@ static struct file_transfer_op* ft_open(struct file_transfer* ft, uint64_t group
|
||||
(unsigned long long)size);
|
||||
return NULL;
|
||||
}
|
||||
if (!topo_group_chat_allowed(ft->inst, group, peer)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file_transfer: open denied group=%llu peer=%llu receive=%d",
|
||||
(unsigned long long)group, (unsigned long long)peer, receiving); return NULL;
|
||||
}
|
||||
struct file_transfer_op* op = u_calloc(1, sizeof(*op));
|
||||
if (!op) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file_transfer: operation allocation failed"); return NULL; }
|
||||
op->ft = ft; op->group = group; op->peer = peer; op->size = size; op->receiving = receiving;
|
||||
@@ -201,8 +221,8 @@ static struct file_transfer_op* ft_open(struct file_transfer* ft, uint64_t group
|
||||
ft_finish(op, -1);
|
||||
return NULL;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: start peer=%llu receive=%d size=%llu active=%u",
|
||||
(unsigned long long)peer, receiving, (unsigned long long)size, ft->count);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: start group=%llu peer=%llu receive=%d size=%llu active=%u",
|
||||
(unsigned long long)group, (unsigned long long)peer, receiving, (unsigned long long)size, ft->count);
|
||||
return op;
|
||||
}
|
||||
|
||||
@@ -242,12 +262,17 @@ static void ft_serve(struct file_transfer* ft, uint64_t group, uint64_t peer, co
|
||||
|
||||
/* Signed source, transfer ID и точные границы отделяют операции и повторы. */
|
||||
static void ft_recv(struct ETCP_CONN* conn, struct ll_entry* e) {
|
||||
if (!e || !conn || !e->dgram || e->len <= ROUTER_SVC_PAYLOAD_OFF) goto done;
|
||||
if (!e || !conn || !e->dgram || e->len < ROUTER_SVC_PAYLOAD_OFF) goto done;
|
||||
struct file_transfer* ft = conn->instance->file_transfer;
|
||||
if (!ft || ft->closing) goto done;
|
||||
uint64_t group, peer;
|
||||
memcpy(&group, e->dgram + ROUTER_SVC_GROUP_OFF, 8);
|
||||
memcpy(&peer, e->dgram + ROUTER_SVC_SRC_OFF, 8);
|
||||
if (e->len == ROUTER_SVC_PAYLOAD_OFF) { file_transfer_revalidate_members(ft, group); goto done; }
|
||||
if (!topo_group_chat_allowed(ft->inst, group, peer)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file_transfer: receive denied group=%llu peer=%llu",
|
||||
(unsigned long long)group, (unsigned long long)peer); goto done;
|
||||
}
|
||||
if (!(e->dgram[ROUTER_SVC_FLAGS_OFF] & ROUTER_FLAG_SIGNED)) {
|
||||
DEBUG_WARN(DEBUG_CATEGORY_MEDIA, "file_transfer: unsigned packet peer=%llu", (unsigned long long)peer);
|
||||
goto done;
|
||||
@@ -299,7 +324,14 @@ struct file_transfer* file_transfer_create(struct UTUN_INSTANCE* inst, file_tran
|
||||
struct file_transfer* ft = u_calloc(1, sizeof(*ft));
|
||||
if (!ft) { DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file_transfer: owner allocation failed"); return NULL; }
|
||||
ft->inst = inst; ft->lookup = lookup; ft->arg = arg;
|
||||
if (etcp_router_bind(inst, ETCP_RT_ID_FILE_TRANSFER, ft_recv) != 0) { u_free(ft); return NULL; }
|
||||
if (etcp_router_bind(inst, ETCP_RT_ID_FILE_TRANSFER, ft_recv) != 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file_transfer: router binding failed"); u_free(ft); return NULL;
|
||||
}
|
||||
if (etcp_router_require_crypto(inst, ETCP_RT_ID_FILE_TRANSFER, ROUTER_FLAG_SIGNED) ||
|
||||
etcp_router_set_authorize(inst, ETCP_RT_ID_FILE_TRANSFER, topo_group_chat_allowed)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEDIA, "file_transfer: router policy setup failed");
|
||||
etcp_router_unbind(inst, ETCP_RT_ID_FILE_TRANSFER); u_free(ft); return NULL;
|
||||
}
|
||||
inst->file_transfer = ft;
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "file_transfer: initialized max_operations=%u", FT_MAX_OPS);
|
||||
return ft;
|
||||
@@ -356,3 +388,15 @@ void file_transfer_cancel_path(struct file_transfer* ft, const char* path) {
|
||||
ft_finish(found, -2);
|
||||
}
|
||||
}
|
||||
|
||||
void file_transfer_revalidate_members(struct file_transfer* ft, uint64_t group) {
|
||||
if (!ft || ft->closing) return;
|
||||
/* done может отменить другие операции: следующий указатель через callback не сохраняем. */
|
||||
for (;;) {
|
||||
struct file_transfer_op* denied = NULL;
|
||||
for (struct file_transfer_op* op = ft->ops; op; op = op->next)
|
||||
if (op->group == group && !topo_group_chat_allowed(ft->inst, group, op->peer)) { denied = op; break; }
|
||||
if (!denied) return;
|
||||
ft_active(denied);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
/* file_transfer — передача неизменяемого файла между явно заданными узлами.
|
||||
* Не знает о чатах, ключах содержимого, custody или БД. lookup авторизует запрос
|
||||
* и возвращает путь; получатель проверяет содержимое в своём done.
|
||||
* Проверяет допуск self/peer к CHAT-группе; lookup отдельно авторизует объект
|
||||
* и возвращает путь. Ключи содержимого, custody и проверка результата принадлежат владельцу.
|
||||
* Каждая операция владеет CM handle до завершения/отмены, включая DOWN/TIMEOUT.
|
||||
* Все API/callbacks в uasync; destroy вызывается вне callbacks, до удаления групп.
|
||||
* До 16 входящих/исходящих операций суммарно. DATA до 8192 байт; router-пакеты подписаны,
|
||||
* До 16 входящих/исходящих операций суммарно. DATA до 8192 байт; router DATA и controls подписаны,
|
||||
* uint64 wire-поля имеют native byte order. Простой 30с завершает операцию ошибкой;
|
||||
* при восстановлении пути/простое приём повторяет REQUEST с непрерывного полученного offset.
|
||||
* Собственное временное назначение передаёт вызывающий: файл открывается с усечением,
|
||||
* в том числе до возможного отказа запуска. При ошибке/cancel файл не удаляется и отбрасывается caller.
|
||||
* после проверки допуска, но до возможного ресурсного отказа запуска. При ошибке/cancel файл не удаляется и отбрасывается caller.
|
||||
* Отзыв отменяет операции/таймеры/waiters данной группы; общий ETCP и другие группы сохраняются.
|
||||
*/
|
||||
#ifndef FILE_TRANSFER_H
|
||||
#define FILE_TRANSFER_H
|
||||
@@ -51,4 +52,9 @@ void file_transfer_cancel_object(struct file_transfer* ft, const uint8_t object[
|
||||
* одного UUID имеют разные файлы; отзыв одного не затрагивает другую копию. */
|
||||
void file_transfer_cancel_path(struct file_transfer* ft, const char* path);
|
||||
|
||||
/* После commit изменения состава отменить операции group, для которых self/peer больше не допущены.
|
||||
* ft=NULL допустим; done вызывается синхронно после освобождения операции с -2 (либо -1 при ошибке fclose).
|
||||
* Новый pull через другую допущенную группу создаёт отдельную операцию; личные данные владельца не удаляются. */
|
||||
void file_transfer_revalidate_members(struct file_transfer* ft, uint64_t group);
|
||||
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "../chat/chat_sync.h"
|
||||
#include "../chat/chat_attachment.h"
|
||||
#include "../member_files/member_files.h"
|
||||
#include "../media_delivery/file_transfer.h"
|
||||
|
||||
#define TOPO_GROUP_UTUN 0x8000000000000000ULL
|
||||
|
||||
@@ -446,6 +447,7 @@ void topo_group_revalidate_members(struct TOPO_GROUP* group) {
|
||||
nat_detection_revalidate_members(group->instance->nat_det, group->group_id);
|
||||
multicast_revalidate_members(group->instance, group->group_id);
|
||||
etcp_router_revalidate_group(group->instance, group->group_id);
|
||||
file_transfer_revalidate_members(group->instance->file_transfer, group->group_id);
|
||||
conn_mgr_revalidate_members(group->conn_mgr);
|
||||
radio_revalidate_members(group);
|
||||
radio_call_revalidate_members(group->instance, group->group_id);
|
||||
|
||||
Reference in new issue
Block a user