/*++ * File name: * queues.c * Contents: * Supports the linked lists for the clients * and events * Two linked lists: * g_pClientQHead - list of all clients running within smclient * g_pWaitQHead - all events we are waiting for from smclient * * Copyright (C) 1998-1999 Microsoft Corp. --*/ #include #include #include #include #include #include #include #include "tclient.h" #include "protocol.h" #include "gdata.h" #include "bmpcache.h" /* * * ClientQ functions * */ /*++ * Function: * _AddToClientQ * Description: * Adds a client on the top of the list * Arguments: * pClient - the client context * Called by: * SCConnect --*/ VOID _AddToClientQ(PCONNECTINFO pClient) { EnterCriticalSection(g_lpcsGuardWaitQueue); pClient->pNext = g_pClientQHead; g_pClientQHead = pClient; LeaveCriticalSection(g_lpcsGuardWaitQueue); } /*++ * Function: * _RemoveFromClientQ * Description: * Removes a client context from the list * Arguments: * pClient - the client context * Return value: * TRUE on success * Called by: * SCDisconnect --*/ BOOL _RemoveFromClientQ(PCONNECTINFO pClient) { PCONNECTINFO pIter, pPrev = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while (pIter && pIter != pClient) { pPrev = pIter; pIter = pIter->pNext; } if (pIter) { if (!pPrev) g_pClientQHead = pIter->pNext; else pPrev->pNext = pIter->pNext; pIter->pNext = NULL; } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } /*++ * Function: * _SetClientDead * Description: * Marks a client context as dead * Arguments: * dwClientProcessId - ID for the client process * Return value: * TRUE on success * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _SetClientDead(LONG_PTR lClientProcessId) { PCONNECTINFO pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while (pIter && pIter->lProcessId != lClientProcessId) { pIter = pIter->pNext; } if (pIter) pIter->dead = TRUE; LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } /*++ * Function: * _ReplaceProcessId * Description: * the client notifys that the control is in anther process * we have to close the old handles and open handles to * the new pid * * Arguments: * lOldPid - the old pid * lNewPid - the pid to replace with * Return value: * TRUE on success * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _ReplaceProcessId( LONG_PTR lOldPid, LONG_PTR lNewPid ) { BOOL rv = FALSE; HANDLE hNewProcess = NULL; PCONNECTINFO pIter; PWAIT4STRING pWait; hNewProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, PtrToLong((PVOID) lNewPid )); if ( NULL == hNewProcess ) { TRACE((ERROR_MESSAGE, "_ReplaceProcessId: can't open a handle to " "the new process. GetLastError=%d\n", GetLastError())); goto exitpt; } // // find the entry with the old process id // EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while (pIter && pIter->lProcessId != lOldPid) { pIter = pIter->pNext; } if ( NULL == pIter ) { TRACE((WARNING_MESSAGE, "_ReplaceProcessId: can't find old pid\n" )); LeaveCriticalSection(g_lpcsGuardWaitQueue); goto exitpt; } if ( NULL != pIter->hProcess ) CloseHandle( pIter->hProcess ); if ( NULL != pIter->hThread ) CloseHandle( pIter->hThread ); pIter->lProcessId = lNewPid; pIter->hProcess = hNewProcess; pIter->hThread = 0; // // process all waiters // pWait = g_pWaitQHead; while(pWait) { if (pWait->lProcessId == lOldPid) pWait->lProcessId = lNewPid; pWait = pWait->pNext; } LeaveCriticalSection(g_lpcsGuardWaitQueue); rv = TRUE; exitpt: if ( !rv && NULL != hNewProcess ) CloseHandle( hNewProcess ); return rv; } /*++ * Function: * _CheckIsAcceptable * Description: * Checks if we can accept feedback from this RDP client * i.e. if this client is member of the client queue * Arguments: * dwProcessId - clients process Id * Return value: * Pointer to connection context. NULL if not found * Called by: * _FeedbackWndProc within feedback thread --*/ PCONNECTINFO _CheckIsAcceptable(LONG_PTR lProcessId, BOOL bRClxType) { PCONNECTINFO pIter; UNREFERENCED_PARAMETER(bRClxType); EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while(pIter && (pIter->lProcessId != lProcessId #ifdef _RCLX || pIter->RClxMode != bRClxType #endif // _RCLX )) { pIter = pIter->pNext; } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter); } /*++ * Function: * _AddStrToClientBuffer * Description: * Add a string to the clients history buffer * When smclient calls Wait4Str it first checks that buffer * Arguments: * str - the string * dwProcessId - the client process Id * Called by: * _CheckForWaitingWorker --*/ VOID _AddStrToClientBuffer(LPCWSTR str, LONG_PTR lProcessId) { PCONNECTINFO pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while(pIter && pIter->lProcessId != lProcessId) { pIter = pIter->pNext; } if (pIter) { INT_PTR strsize = wcslen(str); if (strsize >= MAX_STRING_LENGTH) strsize = MAX_STRING_LENGTH-1; wcsncpy( pIter->Feedback[pIter->nFBend], str, strsize); pIter->Feedback[pIter->nFBend][strsize] = 0; pIter->nFBend++; pIter->nFBend %= FEEDBACK_SIZE; if (pIter->nFBsize < FEEDBACK_SIZE) pIter->nFBsize++; } LeaveCriticalSection(g_lpcsGuardWaitQueue); } /* * * WaitQ functions * */ /*++ * Function: * _AddToWaitQNoCheck * Description: * Adds an waiting event to the list with checking in the history list * Arguments: * pCI - client context * pWait - the event * Called by: * RegisterChat --*/ VOID _AddToWaitQNoCheck(PCONNECTINFO pCI, PWAIT4STRING pWait) { ASSERT(pCI); EnterCriticalSection(g_lpcsGuardWaitQueue); pWait->pNext = g_pWaitQHead; g_pWaitQHead = pWait; LeaveCriticalSection(g_lpcsGuardWaitQueue); } /*++ * Function: * _AddToWaitQueue * Description: * Add an event to the list. If the event is waiting for string(s) * the history buffer is checked first * Arguments: * pCI - client context * pWait - the event * Called by: * _WaitSomething --*/ VOID _AddToWaitQueue(PCONNECTINFO pCI, PWAIT4STRING pWait) { BOOL bDone = FALSE; int i, strn; ASSERT(pCI); // exit if we are dead if ( #ifdef _RCLX !pWait->waitstr[0] && #endif // _RCLX pCI->dead) { SetEvent(pWait->evWait); goto exitpt; } EnterCriticalSection(g_lpcsGuardWaitQueue); // Check if we're already received this feedback if (pWait->WaitType == WAIT_STRING) // look if the string already came for(i = 0; !bDone && i < pCI->nFBsize; i++) { strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE; if (!pCI->Feedback[strn][0]) continue; bDone = (wcsstr(pCI->Feedback[strn], pWait->waitstr) != NULL); } // In case of waiting multiple strings else if (pWait->WaitType == WAIT_MSTRINGS) { for(i = 0; !bDone && i < pCI->nFBsize; i++) { WCHAR *wszComp = pWait->waitstr; WCHAR *wszLast = pWait->waitstr + pWait->strsize; int idx = 0; strn = (FEEDBACK_SIZE + pCI->nFBend - i - 1) % FEEDBACK_SIZE; if (!pCI->Feedback[strn][0]) continue; while (wszComp < wszLast && *wszComp && !bDone) { if (wcsstr(pCI->Feedback[strn], wszComp)) { int j; // Save the string for(j = 0; wszComp[j]; j++) pCI->szWait4MultipleStrResult[j] = (char)wszComp[j]; // and the index pCI->szWait4MultipleStrResult[j] = 0; pCI->nWait4MultipleStrResult = idx; bDone = TRUE; } else { // Advance to next string wszComp += wcslen(wszComp) + 1; idx ++; } } } } else if (pWait->WaitType == WAIT_CLIPBOARD #ifdef _RCLX && pWait->pOwner->bRClxClipboardReceived #endif // _RCLX ) { bDone = TRUE; } else if (pWait->WaitType == WAIT_DATA #ifdef _RCLX && pWait->pOwner->pRClxDataChain #endif // _RCLX ) { bDone = TRUE; } // The string (or anything else) is in the history list // Set the event if (bDone) { SetEvent(pWait->evWait); pCI->nFBsize = pCI->nFBend = 0; } pWait->pNext = g_pWaitQHead; g_pWaitQHead = pWait; LeaveCriticalSection(g_lpcsGuardWaitQueue); exitpt: ; } /*++ * Function: * _RemoveFromWaitQueue * Description: * Removes an event from the list * Arguments: * pWait - the event * Return value: * TRUE if the event is found and removed * Called by: * _WaitSomething, _RemoveFromWaitQIndirect --*/ BOOL _RemoveFromWaitQueue(PWAIT4STRING pWait) { PWAIT4STRING pIter, pPrev = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while (pIter && pIter != pWait) { pPrev = pIter; pIter = pIter->pNext; } if (pIter) { if (!pPrev) g_pWaitQHead = pIter->pNext; else pPrev->pNext = pIter->pNext; pIter->pNext = NULL; } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } /*++ * Function: * _RemoveFromWaitQIndirect * Description: * Same as _RemoveFromWaitQueue but identifies the event * by client context and waited string * Arguments: * pCI - the client context * lpszWait4 - the string * Return value: * the event * Called by: * UnregisterChat --*/ PWAIT4STRING _RemoveFromWaitQIndirect(PCONNECTINFO pCI, LPCWSTR lpszWait4) { PWAIT4STRING pIter; ASSERT(pCI); // Search the list EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while (pIter && (pIter->pOwner != pCI || wcscmp(pIter->waitstr, lpszWait4)) ) pIter = pIter->pNext; LeaveCriticalSection(g_lpcsGuardWaitQueue); if (pIter) { _RemoveFromWaitQueue(pIter); } return pIter; } /*++ * Function: * _RetrieveFromWaitQByEvent * Description: * Searches the waiting list by event handler * Arguments: * hEvent - the handler * Return value: * The event structure * Called by: * _WaitSomething when responds on chat sequence --*/ PWAIT4STRING _RetrieveFromWaitQByEvent(HANDLE hEvent) { PWAIT4STRING pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while (pIter && pIter->evWait != hEvent) pIter = pIter->pNext; LeaveCriticalSection(g_lpcsGuardWaitQueue); return pIter; } /*++ * Function: * _RetrieveFromWaitQByOwner * Description: * Searches the waiting list by owner record * Arguments: * pCI - pointer to the owner context * Return value: * The event structure * Called by: * RClx_MsgReceived --*/ PWAIT4STRING _RetrieveFromWaitQByOwner(PCONNECTINFO pCI) { PWAIT4STRING pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while (pIter && pIter->pOwner != pCI) pIter = pIter->pNext; LeaveCriticalSection(g_lpcsGuardWaitQueue); return pIter; } /*++ * Function: * _FlushFromWaitQ * Description: * Flush everithing that we are waiting for from the list * the client is going to DIE * Arguments: * pCI - client context * Called by: * _CloseConnectInfo --*/ VOID _FlushFromWaitQ(PCONNECTINFO pCI) { PWAIT4STRING pIter, pPrev, pNext; ASSERT(pCI); pPrev = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; do { while (pIter && pIter->pOwner != pCI) { pPrev = pIter; pIter = pIter->pNext; } if (pIter) { if (!pPrev) g_pWaitQHead = pIter->pNext; else pPrev->pNext = pIter->pNext; pNext = pIter->pNext; pIter->pNext = NULL; // Important stuff if (pIter->evWait) { CloseHandle(pIter->evWait); pIter->evWait = NULL; } free(pIter); pIter = pNext; } } while (pIter); LeaveCriticalSection(g_lpcsGuardWaitQueue); } /*++ * Function: * _CheckForWaitingWorker * Description: * Check the received string against the waited events * Arguments: * wszFeed - the received string * dwProcessId - Id of the sender * Return value: * TRUE if an event is found and signaled * Called by: * _TextOutReceived, _GlyphReceived --*/ BOOL _CheckForWaitingWorker(LPCWSTR wszFeed, LONG_PTR lProcessId) { PWAIT4STRING pIter; BOOL bRun; CHAR szBuff[ MAX_STRING_LENGTH ]; CHAR *szPBuff; DWORD dwBuffLen; LPCWSTR wszPFeed; // // Apply translation if specified // if ( g_bTranslateStrings ) { UINT i; UINT j; UINT_PTR len; LPWSTR szStr2; len = wcslen( wszFeed ); __try { szStr2 = (LPWSTR) _alloca( (len+1)*sizeof( *szStr2 ) ); } __except ((GetExceptionCode() == STATUS_STACK_OVERFLOW)? EXCEPTION_EXECUTE_HANDLER: EXCEPTION_CONTINUE_SEARCH) { _resetstkoflw(); szStr2 = NULL; } if ( NULL == szStr2 ) return FALSE; for ( i = 0, j = 0; i < len + 1; j += (szStr2[j] != L' ')?1:0, i++ ) { if ( wszFeed[i] >= 3 && wszFeed[i] < 0x63 ) { szStr2[j] = wszFeed[i] + L' ' - 3; } else { szStr2[j] = wszFeed[i]; } } wszFeed = szStr2; } if ( NULL != g_pfnPrintMessage ) { wszPFeed = wszFeed; while ( *wszPFeed ) { if ( (unsigned short)(*wszPFeed) > 0xff ) break; wszPFeed ++; } if ( *wszPFeed ) { szBuff[0] = '\\'; szBuff[1] = 'u'; szPBuff = szBuff + 2; wszPFeed = wszFeed; dwBuffLen = MAX_STRING_LENGTH - 3; while ( 4 <= dwBuffLen && 0 != *wszPFeed) { DWORD dwLen; if ( dwBuffLen < 4 ) break; dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x", (BYTE)((*wszPFeed) & 0xff )); szPBuff += dwLen; dwBuffLen -= dwLen; dwLen = _snprintf( szPBuff, dwBuffLen + 1, "%02x", (BYTE)(((*wszPFeed) >> 8) & 0xff )); szPBuff += dwLen; dwBuffLen -= dwLen; wszPFeed ++; dwBuffLen--; } *szPBuff = 0; TRACE((ALIVE_MESSAGE, "Received: %s\n", szBuff)); } else { TRACE((ALIVE_MESSAGE, "Received: %S\n", wszFeed)); } } _AddStrToClientBuffer(wszFeed, lProcessId); EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; bRun = TRUE; while(pIter && bRun) { if (pIter->lProcessId == lProcessId) { // Check for expected string (one) if (pIter->WaitType == WAIT_STRING && wcsstr(wszFeed, pIter->waitstr)) bRun = FALSE; else // Check for expected strings (many) if (pIter->WaitType == WAIT_MSTRINGS) { WCHAR *wszComp = pIter->waitstr; WCHAR *wszLast = pIter->waitstr + pIter->strsize; int idx = 0; while (wszComp < wszLast && *wszComp && bRun) { if (wcsstr(wszFeed, wszComp)) { int i; PCONNECTINFO pOwner = pIter->pOwner; // Save the string for(i = 0; wszComp[i]; i++) pOwner->szWait4MultipleStrResult[i] = (char)wszComp[i]; pOwner->szWait4MultipleStrResult[i] = 0; pOwner->nWait4MultipleStrResult = idx; bRun = FALSE; } else { // Advance to next string wszComp += wcslen(wszComp) + 1; idx ++; } } } } // Advance to the next pointer if (bRun) pIter = pIter->pNext; } if (pIter) { SetEvent(pIter->evWait); } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } /*++ * Function: * _TextOutReceived * Description: * TextOut order is received from the client, the string is * in shared memory. Unmaps the memory and checks if the * strings is waited by anybody. Also adds the string * to the client history buffer * Arguments: * dwProcessId - senders Id * hMapF - handle to shared memory, which contains the string * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _TextOutReceived(LONG_PTR lProcessId, HANDLE hMapF) { PFEEDBACKINFO pView = NULL; PCONNECTINFO pIterCl; HANDLE hDupMapF = NULL; BOOL rv = FALSE; EnterCriticalSection(g_lpcsGuardWaitQueue); pIterCl = g_pClientQHead; while(pIterCl && pIterCl->lProcessId != lProcessId) pIterCl = pIterCl->pNext; LeaveCriticalSection(g_lpcsGuardWaitQueue); if (!pIterCl) goto exitpt; if ( NULL == pIterCl->hProcess || !DuplicateHandle(pIterCl->hProcess, hMapF, GetCurrentProcess(), &hDupMapF, FILE_MAP_READ, FALSE, 0)) { pView = (PFEEDBACKINFO) MapViewOfFile( hMapF, FILE_MAP_READ, 0, 0, sizeof(*pView)); } else pView = (PFEEDBACKINFO) MapViewOfFile(hDupMapF, FILE_MAP_READ, 0, 0, sizeof(*pView)); if (!pView) { TRACE((ALIVE_MESSAGE, "TEXTOUT:Can't map a view, GetLastError = %d\n", GetLastError())); goto exitpt1; } rv = _CheckForWaitingWorker(pView->string, lProcessId); exitpt1: if ( NULL != pView ) UnmapViewOfFile(pView); if ( NULL != hDupMapF ) CloseHandle(hDupMapF); exitpt: return rv; } /*++ * Function: * _GlyphReceived * Description: * Same as _TextOutReceived but for GlyphOut order * the glyph is in shared memory. It is converted to * string by calling Glyph2String!bmpcache.c * Arguments: * dwProcessId - senders Id * hMapF - handle to shared memory * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _GlyphReceived(LONG_PTR lProcessId, HANDLE hMapF) { WCHAR wszFeed[MAX_STRING_LENGTH]; BOOL rv = FALSE; PBMPFEEDBACK pView; PCONNECTINFO pIterCl; HANDLE hDupMapF; UINT nSize; EnterCriticalSection(g_lpcsGuardWaitQueue); pIterCl = g_pClientQHead; while(pIterCl && pIterCl->lProcessId != lProcessId) pIterCl = pIterCl->pNext; LeaveCriticalSection(g_lpcsGuardWaitQueue); if (!pIterCl) goto exitpt; if ( NULL == pIterCl->hProcess || !DuplicateHandle( pIterCl->hProcess, hMapF, GetCurrentProcess(), &hDupMapF, FILE_MAP_READ, FALSE, 0)) { TRACE((ERROR_MESSAGE, "GLYPH:Can't dup file handle, GetLastError = %d\n", GetLastError())); goto exitpt; } pView = (PBMPFEEDBACK) MapViewOfFile(hDupMapF, FILE_MAP_READ, 0, 0, sizeof(*pView)); if (!pView) { TRACE((ERROR_MESSAGE, "GLYPH:Can't map a view, GetLastError = %d\n", GetLastError())); goto exitpt1; } // Get bitmap size nSize = pView->bmpsize; if (!nSize) goto exitpt1; // unmap UnmapViewOfFile(pView); // remap the whole structure pView = (PBMPFEEDBACK) MapViewOfFile(hDupMapF, FILE_MAP_READ, 0, 0, sizeof(*pView) + nSize); if (!pView) { TRACE((ERROR_MESSAGE, "GLYPH:Can't map a view, GetLastError = %d\n", GetLastError())); goto exitpt1; } if (!Glyph2String(pView, wszFeed, sizeof(wszFeed)/sizeof(WCHAR))) { goto exitpt1; } rv = _CheckForWaitingWorker(wszFeed, lProcessId); exitpt1: if ( NULL != pView ) { UnmapViewOfFile(pView); } CloseHandle(hDupMapF); exitpt: return rv; } /*++ * Function: * _CheckForWorkerWaitingDisconnect * Description: * Signals a worker (client thread) wich waits for a disconnect event * Arguments: * dwProcessId - clients Id * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _CheckForWorkerWaitingDisconnect(LONG_PTR lProcessId) { PWAIT4STRING pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && (pIter->WaitType != WAIT_DISC || pIter->lProcessId != lProcessId)) { pIter = pIter->pNext; } if (pIter) { SetEvent(pIter->evWait); } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } /*++ * Function: * _CheckForWorkerWaitingConnect * Description: * Signals a worker waiting for a connection * Arguments: * hwndClient - clients window handle, this is needed for * sending messages to the client * dwProcessId - client Id * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _CheckForWorkerWaitingConnect(HWND hwndClient, LONG_PTR lProcessId) { PWAIT4STRING pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && (pIter->WaitType != WAIT_CONN || pIter->lProcessId != lProcessId)) { pIter = pIter->pNext; } if (pIter) { PCONNECTINFO pOwner = pIter->pOwner; if (pOwner) { pOwner->hClient = hwndClient; pOwner->dead = FALSE; } else TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure")); SetEvent(pIter->evWait); } if ( NULL == pIter ) { PCONNECTINFO pCon; // // in autoreconnect the dead field might be TRUE // pCon = g_pClientQHead; while ( NULL != pCon && pCon->lProcessId != lProcessId) { pCon = pCon->pNext; } if ( NULL != pCon) { pCon->dead = FALSE; } } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } #ifdef _RCLX /*++ * Function: * _CheckForWorkerWaitingConnectAndSetId * Description: * This is intended for RCLX mode. dwProcessId is zero * so this function look for such a client and sets its dwProcessId * Signals a worker waiting for a connection * Arguments: * hwndClient - clients window handle, this is needed for * sending messages to the client * dwProcessId - client Id * Return value: * connection context, NULL if not found * Called by: * _FeedbackWndProc within feedback thread --*/ PCONNECTINFO _CheckForWorkerWaitingConnectAndSetId(HWND hwndClient, LONG_PTR lProcessId) { PWAIT4STRING pIter; PCONNECTINFO pOwner = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && (pIter->WaitType != WAIT_CONN || pIter->lProcessId)) { pIter = pIter->pNext; } if (pIter) { pOwner = pIter->pOwner; if (pOwner) { ASSERT(pOwner->RClxMode); pOwner->hClient = hwndClient; pOwner->lProcessId = lProcessId; pIter->lProcessId = lProcessId; // Disable next lookup in // the same entry } else TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure")); SetEvent(pIter->evWait); } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pOwner); } /*++ * Function: * _CheckForWorkerWaitingReconnectAndSetNewId * Description: * This is intended for RCLX mode. When mstsc wants to reconnect * looks for dwLookupId as an ID to reconnect * then sets the new ID * then gets * Arguments: * hwndClient - clients window handle, this is needed for * sending messages to the client * dwLookupId, dwNewId * Return value: * connection context, NULL if not found * Called by: * _FeedbackWndProc within feedback thread --*/ PCONNECTINFO _CheckForWorkerWaitingReconnectAndSetNewId( HWND hwndClient, DWORD dwLookupId, LONG_PTR lNewId) { PWAIT4STRING pIter; PCONNECTINFO pOwner = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && (pIter->WaitType != WAIT_CONN || !pIter->pOwner || pIter->pOwner->dwThreadId != dwLookupId || !(pIter->pOwner->bWillCallAgain))) { pIter = pIter->pNext; } if (pIter) { pOwner = pIter->pOwner; if (pOwner) { ASSERT(pOwner->RClxMode); pOwner->hClient = hwndClient; pOwner->lProcessId = lNewId; pIter->lProcessId = lNewId; // Disable next lookup in // the same entry pOwner->bWillCallAgain = FALSE; } else TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure")); SetEvent(pIter->evWait); } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pOwner); } #endif // _RCLX /*++ * Function: * _CancelWaitingWorker * Description: * Releases a worker waiting for any event. * Eventualy the client is disconnected * Arguments: * dwProcessId - client Id * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _CancelWaitingWorker(LONG_PTR lProcessId) { PWAIT4STRING pIter; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && pIter->lProcessId != lProcessId) { pIter = pIter->pNext; } if (pIter) { SetEvent(pIter->evWait); } LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); } #ifdef _RCLX /*++ * Function: * _CheckForWorkerWaitingClipboard * Description: * Releases a worker waiting for client's clipboard content. * Arguments: * dwProcessId - client Id * Return value: * TRUE if a client is found and signaled * Called by: * _FeedbackWndProc within feedback thread --*/ BOOL _CheckForWorkerWaitingClipboard( PCONNECTINFO pRClxOwner, UINT uiFormat, UINT nSize, PVOID pClipboard, LONG_PTR lProcessId) { PWAIT4STRING pIter = NULL; HGLOBAL ghNewClipboard = NULL; LPVOID pNewClipboard = NULL; ASSERT(pRClxOwner); TRACE((ALIVE_MESSAGE, "Clipboard received, FormatID=%d, Size=%d\n", uiFormat, nSize)); if (nSize) { // Copy the clipboard content to new buffer ghNewClipboard = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, nSize); if (!ghNewClipboard) { TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't allocate %d bytes\n", nSize)); goto exitpt; } pNewClipboard = GlobalLock(ghNewClipboard); if (!pNewClipboard) { TRACE((ERROR_MESSAGE, "_CheckForWorkerWaitingClipboard: can't lock global memory\n")); goto exitpt; } memcpy(pNewClipboard, pClipboard, nSize); // Unlock the clipboard buffer GlobalUnlock(ghNewClipboard); pNewClipboard = NULL; } else { pClipboard = NULL; } EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pWaitQHead; while(pIter && (pIter->lProcessId != lProcessId || pIter->WaitType != WAIT_CLIPBOARD)) { pIter = pIter->pNext; } if (pIter) { PCONNECTINFO pOwner = pIter->pOwner; // Put the buffer in the worker's context if (pOwner) { ASSERT(pOwner->RClxMode); ASSERT(pOwner == pRClxOwner); // pOwner->ghClipboard should be NULL ASSERT(pOwner->ghClipboard == NULL); pOwner->ghClipboard = ghNewClipboard; pOwner->uiClipboardFormat = uiFormat; pOwner->nClipboardSize = nSize; } else TRACE((WARNING_MESSAGE, "FEED: WAIT4 w/o owner structure")); SetEvent(pIter->evWait); } else { // Can't find anybody waiting, add it to the context owner pRClxOwner->ghClipboard = ghNewClipboard; pRClxOwner->uiClipboardFormat = uiFormat; pRClxOwner->nClipboardSize = nSize; } pRClxOwner->bRClxClipboardReceived = TRUE; LeaveCriticalSection(g_lpcsGuardWaitQueue); exitpt: if (!pIter) // worker not found, clear the allocated buffer { if (ghNewClipboard) GlobalFree(ghNewClipboard); } return (pIter != NULL); } #endif // _RCLX BOOL _SetSessionID(LONG_PTR lProcessId, UINT uSessionId) { PCONNECTINFO pIter; // PCONNECTINFO pPrev = NULL; EnterCriticalSection(g_lpcsGuardWaitQueue); pIter = g_pClientQHead; while (pIter && pIter->lProcessId != lProcessId) pIter = pIter->pNext; if (pIter) pIter->uiSessionId = (uSessionId)?uSessionId:-1; LeaveCriticalSection(g_lpcsGuardWaitQueue); return (pIter != NULL); }