Feature: Add host management and connection management MCP tools

Expose the online-list TLS column through list_online_hosts, search_hosts
and get_host_detail. The value comes from the flag the client reports at
login, so old clients always read false.

Add list_network_connections and kill_network_connection on top of the
connection manager sub-connection protocol. The kill path matches the
original 110-byte record instead of rebuilding addresses, supports a dry
run, refuses UDP/IPv6 targets, and verifies that the quadruple really
disappeared instead of assuming success.

Add a host_* family backed by the machine manager protocol: ten read
tools covering every tab of the host management dialog, and four
recoverable write tools for process freeze/thaw, window restore/hide/
maximize/minimize, service start/stop/pause/continue/restart, and
scheduled task run/stop. Every write re-reads the snapshot before sending
and re-checks afterwards, reporting -32009 for stale targets rather than
acting blindly. The family is gated by McpMachine, the risky subset by
McpMachineDangerous, and writes additionally require read-only mode to
be off.

Route managed sub-connections from MessageHandle and OfflineProc, keep
the single-in-flight rule by sharing the pending table with a request
kind, and move the shared JSON/lock/encoding helpers into McpInternal so
both tool families use one implementation. Settings dialog, design docs
and en_US/zh_TW/de_DE translations are updated accordingly.

Co-Authored-By: deepseek-flash
This commit is contained in:
yuanyuanxianganddeepseek-flash committed 2026-10-21 20:01:41 +02:00
1 parent 6c8336b497
commit 38cd207f5d
17 files changed
+3615 -184

No files matched your search

+78
View File
@@ -270,6 +270,41 @@ public:
// 超时路径不会对已回收(连接池复用)的 context 误 CancelIO。
void OnManageSubClosed(context* subCtx);
// ===== P8:主机管理 / 连接管理(子连接会话)=====
// 协议:主连接下发 COMMAND_MACHINE_MANAGE(162) / COMMAND_CONNECTION(253) → 客户端新建
// 子连接 → 子连接回就绪包(TOKEN_SYSINFOLIST=61 / TOKEN_CONNECTION_LIST=255)→ 在同一
// 子连接上多步收发。会话复用 m_Pending 表(统一「单设备单飞行」),kind 区分工具族。
// 见 docs/Mcp_Machine_Design.md。
void SetMachineEnabled(bool enabled) { m_machineEnabled = enabled; }
bool IsMachineEnabled() const { return m_machineEnabled; }
void SetMachineDangerousEnabled(bool enabled) { m_machineDangerousEnabled = enabled; }
bool IsMachineDangerousEnabled() const { return m_machineDangerousEnabled; }
// MessageHandle 顶部钩子(终端拦截之后、switch 之前):true = 本包已由 MCP 消费。
// 已绑定的子连接:只保存期望 token 的包与 TOKEN_MACHINE_MSG(42),其余丢弃。
// 未绑定的子连接:仅 61/255 可作为就绪包尝试绑定;否则返回 false(MFC 行为不变)。
bool OnManagedSubPacket(context* subCtx, const BYTE* data, ULONG len);
// OfflineProc 钩子:接管的子连接断开 → 置 closed 唤醒等待者(幂等)。
void OnManagedContextClosed(context* subCtx);
// 工具线程:登记会话(false = 该设备已有挂起请求在飞 → 设备忙)。
bool BeginMachineSession(uint64_t device_id, const std::string& tool, context* mainCtx);
bool BeginConnMgrSession(uint64_t device_id, const std::string& tool, context* mainCtx);
// 工具线程:发命令前清空上一次响应并登记期望 token。
void ArmManagedResponse(uint64_t device_id, BYTE expectedToken);
// 工具线程:等待子连接就绪包 / 指定 token 的响应(超时由调用方按步给)。
enum class ManagedWaitResult { Ok, Timeout, Closed, ClientError };
ManagedWaitResult WaitManagedPacket(uint64_t device_id, BYTE token,
std::vector<BYTE>& out, context*& subCtxOut,
int timeoutMs, std::string& clientError);
// 工具线程:结束会话;cancelIo = 关闭子连接;markOrphan = 打 5s 墓碑
// (吸收迟到的 61/255,避免超时后弹出 MFC 对话框)。
void EndManagedSession(uint64_t device_id, bool cancelIo, bool markOrphan);
// 安全配置(启动时由 CMy2015RemoteDlg 读 THIS_CFG 后设置)。
void SetReadonly(bool readonly) { m_readonly = readonly; }
void SetCmdWhitelist(const std::string& whitelist) { m_cmdWhitelist = whitelist; }
@@ -285,6 +320,15 @@ private:
// POST /mcp 处理器:token 校验 + JSON-RPC 分发。
void HandleMcp(const httplib::Request& req, httplib::Response& res);
// 挂起请求类型:主机管理/连接管理会话与既有一次性请求共用 m_Pending 保证单设备单飞行,
// 但 MessageHandle 的 P2b/P3/P7 拦截分支(IsPending/TakeMainResponse)必须把这两类排除,
// 否则用户手动打开对话框时 UI 包会被 MCP 抢走。
enum class PendingKind { Generic, FollowUp, Machine, ConnMgr };
static bool KindAcceptsToken(PendingKind kind, BYTE token);
bool BeginManagedSession(uint64_t device_id, const std::string& tool,
PendingKind kind, context* mainCtx);
httplib::Server m_server;
std::thread m_thread;
std::atomic<bool> m_running{false};
@@ -306,11 +350,43 @@ private:
std::vector<BYTE> followUp; // 接管后下发的写命令 payload(首字节 = 写命令)
bool followUpSent = false; // false=等子连接就绪(首包);true=已发写命令、等确认包
context* subCtx = nullptr; // 接管的子连接(超时/失败 CancelIO 用,防孤儿子连接)
// ===== P8:主机管理 / 连接管理会话(kind = Machine / ConnMgr 时有效)=====
PendingKind kind = PendingKind::Generic;
context* mainCtx = nullptr; // Begin 时抓取的主连接(只作身份校验,不从其收发)
std::string peer; // mainCtx->GetPeerName()(老客户端子连接 ID=0 时兜底)
BYTE expectedToken = 0; // 期望的响应 token(0 = 未设置)
bool hasResponse = false;
std::vector<BYTE> response; // 含首字节 token
std::string clientError; // TOKEN_MACHINE_MSG(42) 文本(已转 UTF-8)
bool closed = false; // 子连接在等待期间断开
std::chrono::steady_clock::time_point deadline; // 整个会话的截止时间
};
std::mutex m_PendingMutex;
std::condition_variable m_PendingCv;
std::map<uint64_t, PendingRequest> m_Pending;
// ===== P8:子连接路由(受 m_PendingMutex 保护)=====
// 已绑定子连接 → device(该子连接的一切包都由 MCP 消费)。
std::map<context*, uint64_t> m_SubCtxToDevice;
// CancelIO 之后仍可能到达的包:静默丢弃(避免子连接回收前的尾巴包弹对话框)。
std::set<context*> m_AbsorbedSubCtx;
// 会话异常结束后 5s 内的迟到就绪包墓碑(device / peer 两个维度)。
struct OrphanMark {
std::chrono::steady_clock::time_point expiry;
PendingKind kind = PendingKind::Generic;
};
std::map<uint64_t, OrphanMark> m_OrphanByDevice;
std::map<std::string, OrphanMark> m_OrphanByPeer;
// 清理过期墓碑(持 m_PendingMutex 调用)。
void PruneOrphanMarksLocked(std::chrono::steady_clock::time_point now);
// 路由表大小(已绑定 + 已吸收的子连接数)。MessageHandle 每个包都会调用
// OnManagedSubPacket,若无会话在飞则用它无锁快速返回,避免音频/屏幕等高频
// 子连接逐包争用 m_PendingMutex。只在持锁时更新(store)。
std::atomic<int> m_ManagedRoutes{0};
void RefreshManagedRoutesLocked();
// get_screenshot 的 reqId 发生器(16 位,跳过 0)。与 MFC 预览的 m_PreviewReqId 各自独立计数。
std::atomic<uint16_t> m_PreviewReqId{1};
@@ -381,6 +457,8 @@ private:
bool m_remoteControlEnabled = false; // 远程控制开关(默认关;要求 m_readonly=false)
bool m_fileTransferEnabled = false; // 文件传输开关(默认关;download_file)
bool m_manageEnabled = false; // P7 管理控制开关(默认关;要求 m_readonly=false)
bool m_machineEnabled = false; // P8 主机管理族总开关(默认关;16 个 host_* 工具)
bool m_machineDangerousEnabled = false; // P8 高风险子集(冻结/解冻进程、停止/重启服务)
};
// 全局访问器(仿 WebService(),见 WebService.h 末尾)