diff --git a/src/stream/stream.h b/src/stream/stream.h index 74f13260..37803e0f 100644 --- a/src/stream/stream.h +++ b/src/stream/stream.h @@ -60,6 +60,8 @@ int stream_service_init(struct UTUN_INSTANCE *inst); void stream_service_destroy(struct UTUN_INSTANCE *inst); void stream_cancel_group(struct UTUN_INSTANCE *inst, uint64_t group_id); void stream_set_event_callback(struct UTUN_INSTANCE *inst, stream_event_fn callback, void *arg); +/* Локальный owner удерживает эффективный ACTIVE; желаемый frontend-режим ядро восстанавливает после последнего close. */ +int stream_service_needs_activity(const struct UTUN_INSTANCE *inst); /* out заранее NULL. parameters=NULL — 6+2 и полный подписанный блок 1300 байт. * Одна публикация этого узла в группе; новый запуск получает новый source_epoch. */ diff --git a/src/utun_instance.c b/src/utun_instance.c index 57379bd1..adda712f 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -120,6 +120,7 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u instance->client_type = config->global.client_type; instance->keepalive_interval = (uint16_t)(config->global.keepalive_interval > 0 ? config->global.keepalive_interval : 200); instance->client_activity = (instance->client_type == CLIENT_TYPE_MOBILE) ? CLIENT_ACTIVITY_STANDBY : CLIENT_ACTIVITY_ACTIVE; + instance->client_activity_requested = instance->client_activity; // Set my keys if (sc_init_local_keys(&instance->my_keys, config->global.my_public_key_hex, config->global.my_private_key_hex) != SC_OK) { @@ -1155,20 +1156,26 @@ int utun_set_client_activity(struct UTUN_INSTANCE* instance, int active) { return -1; } if (instance->client_type == CLIENT_TYPE_SERVER) return 0; - int state = active ? CLIENT_ACTIVITY_ACTIVE : CLIENT_ACTIVITY_STANDBY; + int requested = active ? CLIENT_ACTIVITY_ACTIVE : CLIENT_ACTIVITY_STANDBY; + int held = stream_service_needs_activity(instance); + int state = held ? CLIENT_ACTIVITY_ACTIVE : requested; int previous = instance->client_activity; + int previous_requested = instance->client_activity_requested; + instance->client_activity_requested = requested; instance->client_activity = state; #ifdef UTUN_HAVE_STANDBY - if (instance->client_type == CLIENT_TYPE_MOBILE && standby_set_enabled(instance, !active) < 0) { + if (instance->client_type == CLIENT_TYPE_MOBILE && standby_set_enabled(instance, state != CLIENT_ACTIVITY_ACTIVE) < 0) { instance->client_activity = previous; + instance->client_activity_requested = previous_requested; DEBUG_ERROR(DEBUG_CATEGORY_BGP, "client_activity: standby transition failed node=%016llx requested=%d previous=%d", (unsigned long long)instance->node_id, state, previous); return -1; } #endif if (previous == state) return 0; - DEBUG_INFO(DEBUG_CATEGORY_BGP, "client_activity set %s until explicit change node=%016llx type=%u", - active ? "ACTIVE" : "STANDBY", (unsigned long long)instance->node_id, instance->client_type); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "client_activity effective=%s requested=%s stream_hold=%d node=%016llx type=%u", + state ? "ACTIVE" : "STANDBY", requested ? "ACTIVE" : "STANDBY", held, + (unsigned long long)instance->node_id, instance->client_type); utun_fire_activity_cbk(instance, state); return 0; } diff --git a/src/utun_instance.h b/src/utun_instance.h index 69b6a859..d7e827db 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -254,6 +254,7 @@ struct UTUN_INSTANCE { uint8_t client_type; // CLIENT_TYPE_SERVER/DESKTOP/MOBILE (from config) uint16_t keepalive_interval; // желаемый keepalive (ms), из конфига. для handshake uint8_t client_activity; // CLIENT_ACTIVITY_STANDBY/ACTIVE + uint8_t client_activity_requested; // режим frontend; stream owners могут временно удерживать эффективный ACTIVE struct utun_activity_cbk_entry* activity_cbks; // подписки на смену client_activity struct peer_sleep_cbk_entry* peer_sleep_cbks; // подписки на смену спячки пира (keepalive) @@ -306,7 +307,8 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance); /* Глобальные переключатели создания TUN/топологии для тестов и встраивания. */ void utun_instance_set_tun_init_enabled(int enabled); void utun_instance_set_topo_group_enabled(int enabled); -/* Применяет активность и мобильный standby до уведомления подписчиков; выполнять в uasync-потоке. +/* Сохраняет желаемый режим frontend; stream owners удерживают ACTIVE до последнего close. + * Применяет эффективную активность и мобильный standby до уведомления подписчиков; выполнять в uasync-потоке. * Повторная команда согласует фактический режим без повторного BGP-события. 0 — успех, <0 — ошибка. */ int utun_set_client_activity(struct UTUN_INSTANCE* instance, int active); void utun_add_activity_cbk(struct UTUN_INSTANCE* instance, utun_activity_cbk_fn fn, void* arg);