/** * Function description * * @return 0 on success, otherwise a Win32 error code */ UINT rdpei_server_init(RdpeiServerContext *context) { void *buffer = NULL; DWORD bytesReturned; RdpeiServerPrivate *priv = context->priv; priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->channelHandle) { WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); return CHANNEL_RC_INITIALIZATION_ERROR; } if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) { WLog_ERR(TAG, "WTSVirtualChannelQuery failed or invalid invalid returned size(%d)!", bytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; } CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); return CHANNEL_RC_OK; out_close: WTSVirtualChannelClose(priv->channelHandle); return CHANNEL_RC_INITIALIZATION_ERROR; }
int rdpei_server_init(RdpeiServerContext *context) { void *buffer = NULL; DWORD bytesReturned; RdpeiServerPrivate *priv = context->priv; priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->channelHandle) { fprintf(stderr, "%s: unable to open channel\n", __FUNCTION__); return -1; } if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) { fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", __FUNCTION__, bytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; } CopyMemory(&priv->eventHandle, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); return 0; out_close: WTSVirtualChannelClose(priv->channelHandle); return -1; }
/* * Open a dynamic channel with the name given in szChannelName * the output file handle can be used in ReadFile/WriteFile calls */ DWORD OpenDynamicChannel(LPCSTR szChannelName, HANDLE* phFile) { HANDLE hWTSHandle = NULL; HANDLE hWTSFileHandle; PVOID vcFileHandlePtr = NULL; DWORD len; DWORD rc = ERROR_SUCCESS; hWTSHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, (LPSTR)szChannelName, WTS_CHANNEL_OPTION_DYNAMIC); if (!hWTSHandle) { rc = GetLastError(); printf("WTSVirtualChannelOpenEx API Call Failed: GetLastError() = %d\n", GetLastError()); goto exitpt; } BOOL bSucc = WTSVirtualChannelQuery(hWTSHandle, WTSVirtualFileHandle, &vcFileHandlePtr, &len); if ( !bSucc ) { rc = GetLastError(); goto exitpt; } if ( len != sizeof( HANDLE )) { rc = ERROR_INVALID_PARAMETER; goto exitpt; } hWTSFileHandle = *(HANDLE *)vcFileHandlePtr; bSucc = DuplicateHandle( GetCurrentProcess(), hWTSFileHandle, GetCurrentProcess(), phFile, 0, FALSE, DUPLICATE_SAME_ACCESS ); if ( !bSucc ) { rc = GetLastError(); goto exitpt; } rc = ERROR_SUCCESS; exitpt: if ( vcFileHandlePtr ) { WTSFreeMemory( vcFileHandlePtr ); } if ( hWTSHandle ) { WTSVirtualChannelClose( hWTSHandle ); } return rc; }
static void* tf_debug_channel_thread_func(void* arg) { void* fd; STREAM* s; void* buffer; UINT32 bytes_returned = 0; testPeerContext* context = (testPeerContext*) arg; freerdp_thread* thread = context->debug_channel_thread; if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE) { fd = *((void**) buffer); WTSFreeMemory(buffer); thread->signals[thread->num_signals++] = CreateFileDescriptorEvent(NULL, TRUE, FALSE, ((int) (long) fd)); } s = stream_new(4096); WTSVirtualChannelWrite(context->debug_channel, (BYTE*) "test1", 5, NULL); while (1) { freerdp_thread_wait(thread); if (freerdp_thread_is_stopped(thread)) break; stream_set_pos(s, 0); if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) { if (bytes_returned == 0) break; stream_check_size(s, bytes_returned); if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) { /* should not happen */ break; } } stream_set_pos(s, bytes_returned); printf("got %d bytes\n", bytes_returned); } stream_free(s); freerdp_thread_quit(thread); return 0; }
static void* tf_debug_channel_thread_func(void* arg) { void* fd; wStream* s; void* buffer; DWORD BytesReturned = 0; testPeerContext* context = (testPeerContext*) arg; if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &BytesReturned) == TRUE) { fd = *((void**) buffer); WTSFreeMemory(buffer); context->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd); } s = Stream_New(NULL, 4096); WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, NULL); while (1) { WaitForSingleObject(context->event, INFINITE); if (WaitForSingleObject(context->stopEvent, 0) == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { if (BytesReturned == 0) break; Stream_EnsureRemainingCapacity(s, BytesReturned); if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { /* should not happen */ break; } } Stream_SetPosition(s, BytesReturned); printf("got %lu bytes\n", BytesReturned); } Stream_Free(s, TRUE); return 0; }
static int rdpsnd_server_start(RdpsndServerContext* context) { void *buffer = NULL; DWORD bytesReturned; RdpsndServerPrivate *priv = context->priv; priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); if (!priv->ChannelHandle) return -1; if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) { WLog_ERR(TAG, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n", __FUNCTION__, bytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; } CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); priv->rdpsnd_pdu = Stream_New(NULL, 4096); if (!priv->rdpsnd_pdu) goto out_close; if (priv->ownThread) { context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!context->priv->StopEvent) goto out_pdu; context->priv->Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); if (!context->priv->Thread) goto out_stopEvent; } return 0; out_stopEvent: CloseHandle(context->priv->StopEvent); context->priv->StopEvent = NULL; out_pdu: Stream_Free(context->priv->rdpsnd_pdu, TRUE); context->priv->rdpsnd_pdu = NULL; out_close: WTSVirtualChannelClose(context->priv->ChannelHandle); context->priv->ChannelHandle = NULL; return -1; }
static void* tf_debug_channel_thread_func(void* arg) { void* fd; STREAM* s; void* buffer; uint32 bytes_returned = 0; testPeerContext* context = (testPeerContext*) arg; freerdp_thread* thread = context->debug_channel_thread; if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true) { fd = *((void**)buffer); WTSFreeMemory(buffer); thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd); } s = stream_new(4096); WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL); while (1) { freerdp_thread_wait(thread); if (freerdp_thread_is_stopped(thread)) break; stream_set_pos(s, 0); if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == false) { if (bytes_returned == 0) break; stream_check_size(s, bytes_returned); if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == false) { /* should not happen */ break; } } stream_set_pos(s, bytes_returned); printf("got %d bytes\n", bytes_returned); } stream_free(s); freerdp_thread_quit(thread); return 0; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT cliprdr_server_open(CliprdrServerContext* context) { void* buffer = NULL; DWORD BytesReturned = 0; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; cliprdr->ChannelHandle = WTSVirtualChannelOpen(cliprdr->vcm, WTS_CURRENT_SESSION, "cliprdr"); if (!cliprdr->ChannelHandle) { WLog_ERR(TAG, "WTSVirtualChannelOpen for cliprdr failed!"); return ERROR_INTERNAL_ERROR; } cliprdr->ChannelEvent = NULL; if (WTSVirtualChannelQuery(cliprdr->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned)) { if (BytesReturned != sizeof(HANDLE)) { WLog_ERR(TAG, "BytesReturned has not size of HANDLE!"); return ERROR_INTERNAL_ERROR; } CopyMemory(&(cliprdr->ChannelEvent), buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } if (!cliprdr->ChannelEvent) { WLog_ERR(TAG, "WTSVirtualChannelQuery for cliprdr failed!"); return ERROR_INTERNAL_ERROR; } return CHANNEL_RC_OK; }
static void* encomsp_server_thread(void* arg) { wStream* s; DWORD nCount; void* buffer; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; ENCOMSP_ORDER_HEADER* header; EncomspServerContext* context; UINT error = CHANNEL_RC_OK; DWORD status; context = (EncomspServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %u", error); break; } status = WaitForSingleObject(context->priv->StopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForSingleObject failed with error %u", error); break; } if (status == WAIT_OBJECT_0) { break; } WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } if (Stream_GetPosition(s) >= ENCOMSP_ORDER_HEADER_SIZE) { header = (ENCOMSP_ORDER_HEADER*) Stream_Buffer(s); if (header->Length >= Stream_GetPosition(s)) { Stream_SealLength(s); Stream_SetPosition(s, 0); if ((error = encomsp_server_receive_pdu(context, s))) { WLog_ERR(TAG, "encomsp_server_receive_pdu failed with error %u!", error); break; } Stream_SetPosition(s, 0); } } } Stream_Free(s, TRUE); out: if (error && context->rdpcontext) setChannelError(context->rdpcontext, error, "encomsp_server_thread reported an error"); ExitThread((DWORD)error); return NULL; }
static void* audin_server_thread_func(void* arg) { void* fd; STREAM* s; void* buffer; BYTE MessageId; BOOL ready = FALSE; UINT32 bytes_returned = 0; audin_server* audin = (audin_server*) arg; freerdp_thread* thread = audin->audin_channel_thread; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE) { fd = *((void**)buffer); WTSFreeMemory(buffer); thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd); } /* Wait for the client to confirm that the Audio Input dynamic channel is ready */ while (1) { freerdp_thread_wait(thread); if (freerdp_thread_is_stopped(thread)) break; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &bytes_returned) == FALSE) break; ready = *((BOOL*)buffer); WTSFreeMemory(buffer); if (ready) break; } s = stream_new(4096); if (ready) { audin_server_send_version(audin, s); } while (ready) { freerdp_thread_wait(thread); if (freerdp_thread_is_stopped(thread)) break; stream_set_pos(s, 0); if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) { if (bytes_returned == 0) break; stream_check_size(s, (int) bytes_returned); if (WTSVirtualChannelRead(audin->audin_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) break; } if (bytes_returned < 1) continue; stream_read_BYTE(s, MessageId); bytes_returned--; switch (MessageId) { case MSG_SNDIN_VERSION: if (audin_server_recv_version(audin, s, bytes_returned)) audin_server_send_formats(audin, s); break; case MSG_SNDIN_FORMATS: if (audin_server_recv_formats(audin, s, bytes_returned)) audin_server_send_open(audin, s); break; case MSG_SNDIN_OPEN_REPLY: audin_server_recv_open_reply(audin, s, bytes_returned); break; case MSG_SNDIN_DATA_INCOMING: break; case MSG_SNDIN_DATA: audin_server_recv_data(audin, s, bytes_returned); break; case MSG_SNDIN_FORMATCHANGE: break; default: printf("audin_server_thread_func: unknown MessageId %d\n", MessageId); break; } } stream_free(s); WTSVirtualChannelClose(audin->audin_channel); audin->audin_channel = NULL; freerdp_thread_quit(thread); return NULL; }
static void* echo_server_thread_func(void* arg) { wStream* s; void* buffer; DWORD nCount; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; echo_server* echo = (echo_server*) arg; UINT error; DWORD status; if ((error = echo_server_open_channel(echo))) { UINT error2 = 0; WLog_ERR(TAG, "echo_server_open_channel failed with error %lu!", error); IFCALLRET(echo->context.OpenResult, error2, &echo->context, ECHO_SERVER_OPEN_RESULT_NOTSUPPORTED); if (error2) WLog_ERR(TAG, "echo server's OpenResult callback failed with error %lu", error2); goto out; } buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = echo->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Graphics Pipeline dynamic channel is ready */ while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, 100); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); break; } if (status == WAIT_OBJECT_0) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_CLOSED); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } if (WTSVirtualChannelQuery(echo->echo_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_ERROR); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) { IFCALLRET(echo->context.OpenResult, error, &echo->context, ECHO_SERVER_OPEN_RESULT_OK); if (error) WLog_ERR(TAG, "OpenResult failed with error %lu!", error); break; } } s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); WTSVirtualChannelClose(echo->echo_channel); ExitThread((DWORD)ERROR_NOT_ENOUGH_MEMORY); return NULL; } while (ready) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); break; } if (status == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); WTSVirtualChannelRead(echo->echo_channel, 0, NULL, 0, &BytesReturned); if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } if (WTSVirtualChannelRead(echo->echo_channel, 0, (PCHAR) Stream_Buffer(s), (ULONG) Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } IFCALLRET(echo->context.Response, error, &echo->context, (BYTE*) Stream_Buffer(s), BytesReturned); if (error) { WLog_ERR(TAG, "Response failed with error %lu!", error); break; } } Stream_Free(s, TRUE); WTSVirtualChannelClose(echo->echo_channel); echo->echo_channel = NULL; out: if (error && echo->context.rdpcontext) setChannelError(echo->context.rdpcontext, error, "echo_server_thread_func reported an error"); ExitThread((DWORD)error); return NULL; }
/* * Handle rpdgfx messages - server side * * @param Server side context * * @return 0 on success * ERROR_NO_DATA if no data could be read this time * otherwise a Win32 error code */ UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context) { DWORD BytesReturned; void* buffer; UINT ret = CHANNEL_RC_OK; RdpgfxServerPrivate* priv = context->priv; wStream* s = priv->input_stream; /* Check whether the dynamic channel is ready */ if (!priv->isReady) { if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) { if (GetLastError() == ERROR_NO_DATA) return ERROR_NO_DATA; WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); return ERROR_INTERNAL_ERROR; } priv->isReady = *((BOOL*) buffer); WTSFreeMemory(buffer); } /* Consume channel event only after the gfx dynamic channel is ready */ if (priv->isReady) { Stream_SetPosition(s, 0); if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned)) { if (GetLastError() == ERROR_NO_DATA) return ERROR_NO_DATA; WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); return ERROR_INTERNAL_ERROR; } if (BytesReturned < 1) return CHANNEL_RC_OK; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); return ERROR_INTERNAL_ERROR; } Stream_SetLength(s, BytesReturned); Stream_SetPosition(s, 0); while (((size_t) Stream_GetPosition(s)) < Stream_Length(s)) { if ((ret = rdpgfx_server_receive_pdu(context, s))) { WLog_ERR(TAG, "rdpgfx_server_receive_pdu " "failed with error %u!", ret); return ret; } } } return ret; }
static BOOL rdpgfx_server_open(RdpgfxServerContext* context) { RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*) context->priv; void* buffer = NULL; if (!priv->isOpened) { PULONG pSessionId = NULL; DWORD BytesReturned = 0; priv->SessionId = WTS_CURRENT_SESSION; if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*) &pSessionId, &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); return FALSE; } priv->SessionId = (DWORD) * pSessionId; WTSFreeMemory(pSessionId); priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); if (!priv->rdpgfx_channel) { WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); return FALSE; } /* Query for channel event handle */ if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) || (BytesReturned != sizeof(HANDLE))) { WLog_ERR(TAG, "WTSVirtualChannelQuery failed " "or invalid returned size(%d)", BytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; } CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); if (!(priv->zgfx = zgfx_context_new(TRUE))) { WLog_ERR(TAG, "Create zgfx context failed!"); goto out_close; } if (priv->ownThread) { if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); goto out_zgfx; } if (!(priv->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpgfx_server_thread_func, (void*) context, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto out_stopEvent; } } priv->isOpened = TRUE; priv->isReady = FALSE; return TRUE; } WLog_ERR(TAG, "RDPGFX channel is already opened!"); return FALSE; out_stopEvent: CloseHandle(priv->stopEvent); priv->stopEvent = NULL; out_zgfx: zgfx_context_free(priv->zgfx); priv->zgfx = NULL; out_close: WTSVirtualChannelClose(priv->rdpgfx_channel); priv->rdpgfx_channel = NULL; priv->channelEvent = NULL; return FALSE; }
/** * Function description * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpsnd_server_start(RdpsndServerContext* context) { void *buffer = NULL; DWORD bytesReturned; RdpsndServerPrivate *priv = context->priv; UINT error = ERROR_INTERNAL_ERROR; priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); if (!priv->ChannelHandle) { WLog_ERR(TAG, "WTSVirtualChannelOpen failed!"); return ERROR_INTERNAL_ERROR; } if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) { WLog_ERR(TAG, "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)", bytesReturned); if (buffer) WTSFreeMemory(buffer); goto out_close; } CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); priv->rdpsnd_pdu = Stream_New(NULL, 4096); if (!priv->rdpsnd_pdu) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out_close; } if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0)) { WLog_ERR(TAG, "InitializeCriticalSectionEx failed!"); goto out_pdu; } if (priv->ownThread) { context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!context->priv->StopEvent) { WLog_ERR(TAG, "CreateEvent failed!"); goto out_lock; } context->priv->Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); if (!context->priv->Thread) { WLog_ERR(TAG, "CreateThread failed!"); goto out_stopEvent; } } return CHANNEL_RC_OK; out_stopEvent: CloseHandle(context->priv->StopEvent); context->priv->StopEvent = NULL; out_lock: DeleteCriticalSection(&context->priv->lock); out_pdu: Stream_Free(context->priv->rdpsnd_pdu, TRUE); context->priv->rdpsnd_pdu = NULL; out_close: WTSVirtualChannelClose(context->priv->ChannelHandle); context->priv->ChannelHandle = NULL; return error; }
static void* audin_server_thread_func(void* arg) { wStream* s; void* buffer; DWORD nCount; BYTE MessageId; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; audin_server* audin = (audin_server*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = audin->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Audio Input dynamic channel is ready */ while (1) { if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0) break; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) break; ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) break; } s = Stream_New(NULL, 4096); if (!s) goto out; if (ready) { audin_server_send_version(audin, s); } while (ready) { if (WaitForMultipleObjects(nCount, events, FALSE, INFINITE) == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { if (BytesReturned == 0) break; Stream_EnsureRemainingCapacity(s, BytesReturned); if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { break; } } if (BytesReturned < 1) continue; Stream_Read_UINT8(s, MessageId); BytesReturned--; switch (MessageId) { case MSG_SNDIN_VERSION: if (audin_server_recv_version(audin, s, BytesReturned)) audin_server_send_formats(audin, s); break; case MSG_SNDIN_FORMATS: if (audin_server_recv_formats(audin, s, BytesReturned)) audin_server_send_open(audin, s); break; case MSG_SNDIN_OPEN_REPLY: audin_server_recv_open_reply(audin, s, BytesReturned); break; case MSG_SNDIN_DATA_INCOMING: break; case MSG_SNDIN_DATA: audin_server_recv_data(audin, s, BytesReturned); break; case MSG_SNDIN_FORMATCHANGE: break; default: fprintf(stderr, "audin_server_thread_func: unknown MessageId %d\n", MessageId); break; } } Stream_Free(s, TRUE); out: WTSVirtualChannelClose(audin->audin_channel); audin->audin_channel = NULL; return NULL; }
static void* drdynvc_server_thread(void* arg) { #if 0 wStream* s; DWORD status; DWORD nCount; void* buffer; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; DrdynvcServerContext* context; UINT error = ERROR_INTERNAL_ERROR; context = (DrdynvcServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); ExitThread((DWORD) CHANNEL_RC_NO_MEMORY); return NULL; } if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) { error = CHANNEL_RC_OK; break; } if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); break; } if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); break; } if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); break; } } Stream_Free(s, TRUE); ExitThread((DWORD) error); #endif // WTF ... this code only reads data into the stream until there is no more memory ExitThread(0); return NULL; }
static void* remdesk_server_thread(void* arg) { wStream* s; DWORD status; DWORD nCount; void* buffer; UINT32* pHeader; UINT32 PduLength; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; RemdeskServerContext* context; UINT error; context = (RemdeskServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } else { WLog_ERR(TAG, "WTSVirtualChannelQuery failed!"); error = ERROR_INTERNAL_ERROR; goto out; } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; if ((error = remdesk_send_ctl_version_info_pdu(context))) { WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %"PRIu32"!", error); goto out; } while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"", error); break; } status = WaitForSingleObject(context->priv->StopEvent, 0); if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); break; } if (status == WAIT_OBJECT_0) { break; } if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { if (BytesReturned) Stream_Seek(s, BytesReturned); } else { if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); error = CHANNEL_RC_NO_MEMORY; break; } } if (Stream_GetPosition(s) >= 8) { pHeader = (UINT32*) Stream_Buffer(s); PduLength = pHeader[0] + pHeader[1] + 8; if (PduLength >= Stream_GetPosition(s)) { Stream_SealLength(s); Stream_SetPosition(s, 0); if ((error = remdesk_server_receive_pdu(context, s))) { WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %"PRIu32"!", error); break; } Stream_SetPosition(s, 0); } } } Stream_Free(s, TRUE); out: if (error && context->rdpcontext) setChannelError(context->rdpcontext, error, "remdesk_server_thread reported an error"); ExitThread((DWORD)error); return NULL; }
static void* rdpdr_server_thread(void* arg) { wStream* s; DWORD status; DWORD nCount; void* buffer; int position; HANDLE events[8]; RDPDR_HEADER header; HANDLE ChannelEvent; DWORD BytesReturned; RdpdrServerContext* context; context = (RdpdrServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; rdpdr_server_send_announce_request(context); while (1) { BytesReturned = 0; status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) { break; } WTSVirtualChannelRead(context->priv->ChannelHandle, 0, NULL, 0, &BytesReturned); if (BytesReturned < 1) continue; Stream_EnsureRemainingCapacity(s, BytesReturned); if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { break; } if (Stream_GetPosition(s) >= RDPDR_HEADER_LENGTH) { position = Stream_GetPosition(s); Stream_SetPosition(s, 0); Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */ Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ Stream_SetPosition(s, position); Stream_SealLength(s); Stream_SetPosition(s, RDPDR_HEADER_LENGTH); rdpdr_server_receive_pdu(context, s, &header); Stream_SetPosition(s, 0); } } Stream_Free(s, TRUE); return NULL; }
static void* rdpsnd_server_thread(void* arg) { wStream* s; DWORD status; DWORD nCount; void* buffer; BYTE msgType; UINT16 BodySize; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; RdpsndServerContext* context; BOOL doRun; context = (RdpsndServerContext *)arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (!s) return NULL; if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned)) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; if (ChannelEvent) events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; if (!rdpsnd_server_send_formats(context, s)) goto out; doRun = TRUE; while (doRun) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) break; Stream_SetPosition(s, 0); if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { if (!BytesReturned) break; Stream_EnsureRemainingCapacity(s, BytesReturned); if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) break; } if (Stream_GetRemainingLength(s) < 4) break; Stream_Read_UINT8(s, msgType); Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); if (Stream_GetRemainingLength(s) < BodySize) break; switch (msgType) { case SNDC_WAVECONFIRM: doRun = rdpsnd_server_recv_waveconfirm(context, s); break; case SNDC_QUALITYMODE: doRun = rdpsnd_server_recv_quality_mode(context, s); break; case SNDC_FORMATS: doRun = rdpsnd_server_recv_formats(context, s); if (doRun) { IFCALL(context->Activated, context); } break; default: fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType); break; } } out: Stream_Free(s, TRUE); return NULL; }
HRESULT CTsTeleportShellExt::GetVirtualChannelHandle(HANDLE *phFile) { HRESULT hr = S_OK; HANDLE hWTSHandle = NULL; PVOID vcFileHandlePtr = NULL; // // Open Virtual channel // hWTSHandle = WTSVirtualChannelOpenEx( WTS_CURRENT_SESSION, TSTELE_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); if (NULL == hWTSHandle) { hr = HRESULT_FROM_WIN32(GetLastError()); } LEAVE_IF_FAILED("WTSVirtualChannelOpenEx failed"); // // Get channel file handle // DWORD len; BOOL bSucc = WTSVirtualChannelQuery( hWTSHandle, WTSVirtualFileHandle, &vcFileHandlePtr, &len); if (!bSucc) { hr = HRESULT_FROM_WIN32(GetLastError()); } LEAVE_IF_FAILED("WTSVirtualChannelQuery failed"); if (len != sizeof(HANDLE)) { hr = E_UNEXPECTED; } LEAVE_IF_FAILED("WTSVirtualChannelQuery return unexpected"); HANDLE hWTSFileHandle = *(HANDLE *)vcFileHandlePtr; // // Duplicate handle so that we can close // bSucc = DuplicateHandle( GetCurrentProcess(), hWTSFileHandle, GetCurrentProcess(), phFile, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!bSucc) { hr = HRESULT_FROM_WIN32(GetLastError()); } LEAVE_IF_FAILED("DuplicateHandle failed"); _Function_Exit: // // Cleanup // if (vcFileHandlePtr) { WTSFreeMemory(vcFileHandlePtr); } if (hWTSHandle) { WTSVirtualChannelClose(hWTSHandle); } return hr; }
static void* rdpsnd_server_thread_func(void* arg) { void* fd; STREAM* s; void* buffer; BYTE msgType; UINT16 BodySize; UINT32 bytes_returned = 0; rdpsnd_server* rdpsnd = (rdpsnd_server*) arg; freerdp_thread* thread = rdpsnd->rdpsnd_channel_thread; if (WTSVirtualChannelQuery(rdpsnd->rdpsnd_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE) { fd = *((void**)buffer); WTSFreeMemory(buffer); thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd); } s = stream_new(4096); rdpsnd_server_send_formats(rdpsnd, s); while (1) { freerdp_thread_wait(thread); if (freerdp_thread_is_stopped(thread)) break; stream_set_pos(s, 0); if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) { if (bytes_returned == 0) break; stream_check_size(s, (int) bytes_returned); if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, stream_get_head(s), stream_get_size(s), &bytes_returned) == FALSE) break; } stream_read_BYTE(s, msgType); stream_seek_BYTE(s); /* bPad */ stream_read_UINT16(s, BodySize); if (BodySize + 4 > (int) bytes_returned) continue; switch (msgType) { case SNDC_FORMATS: if (rdpsnd_server_recv_formats(rdpsnd, s)) { IFCALL(rdpsnd->context.Activated, &rdpsnd->context); } break; default: break; } } stream_free(s); freerdp_thread_quit(thread); return 0; }
static void* audin_server_thread_func(void* arg) { wStream* s; void* buffer; DWORD nCount; BYTE MessageId; HANDLE events[8]; BOOL ready = FALSE; HANDLE ChannelEvent; DWORD BytesReturned = 0; audin_server* audin = (audin_server*) arg; UINT error = CHANNEL_RC_OK; DWORD status; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } else { WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); error = ERROR_INTERNAL_ERROR; goto out; } nCount = 0; events[nCount++] = audin->stopEvent; events[nCount++] = ChannelEvent; /* Wait for the client to confirm that the Audio Input dynamic channel is ready */ while (1) { if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0) goto out; if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); goto out; } if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); error = ERROR_INTERNAL_ERROR; goto out; } ready = *((BOOL*) buffer); WTSFreeMemory(buffer); if (ready) break; } s = Stream_New(NULL, 4096); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); error = CHANNEL_RC_NO_MEMORY; goto out; } if (ready) { if ((error = audin_server_send_version(audin, s))) { WLog_ERR(TAG, "audin_server_send_version failed with error %lu!", error); goto out_capacity; } } while (ready) { if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0) break; if (status == WAIT_FAILED) { error = GetLastError(); WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu", error); goto out; } Stream_SetPosition(s, 0); if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned)) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } if (BytesReturned < 1) continue; if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) break; if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); error = ERROR_INTERNAL_ERROR; break; } Stream_Read_UINT8(s, MessageId); BytesReturned--; switch (MessageId) { case MSG_SNDIN_VERSION: if ((error = audin_server_recv_version(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_version failed with error %lu!", error); goto out_capacity; } if ((error = audin_server_send_formats(audin, s))) { WLog_ERR(TAG, "audin_server_send_formats failed with error %lu!", error); goto out_capacity; } break; case MSG_SNDIN_FORMATS: if ((error = audin_server_recv_formats(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_formats failed with error %lu!", error); goto out_capacity; } if ((error = audin_server_send_open(audin, s))) { WLog_ERR(TAG, "audin_server_send_open failed with error %lu!", error); goto out_capacity; } break; case MSG_SNDIN_OPEN_REPLY: if ((error = audin_server_recv_open_reply(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %lu!", error); goto out_capacity; } break; case MSG_SNDIN_DATA_INCOMING: break; case MSG_SNDIN_DATA: if ((error = audin_server_recv_data(audin, s, BytesReturned))) { WLog_ERR(TAG, "audin_server_recv_data failed with error %lu!", error); goto out_capacity; }; break; case MSG_SNDIN_FORMATCHANGE: break; default: WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %d", MessageId); break; } } out_capacity: Stream_Free(s, TRUE); out: WTSVirtualChannelClose(audin->audin_channel); audin->audin_channel = NULL; if (error && audin->context.rdpcontext) setChannelError(audin->context.rdpcontext, error, "audin_server_thread_func reported an error"); ExitThread((DWORD)error); return NULL; }
static void* remdesk_server_thread(void* arg) { wStream* s; DWORD status; DWORD nCount; void* buffer; UINT32* pHeader; UINT32 PduLength; HANDLE events[8]; HANDLE ChannelEvent; DWORD BytesReturned; RemdeskServerContext* context; context = (RemdeskServerContext*) arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); WTSFreeMemory(buffer); } nCount = 0; events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; remdesk_send_ctl_version_info_pdu(context); while (1) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) { break; } if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { if (BytesReturned) Stream_Seek(s, BytesReturned); } else { Stream_EnsureRemainingCapacity(s, BytesReturned); } if (Stream_GetPosition(s) >= 8) { pHeader = (UINT32*) Stream_Buffer(s); PduLength = pHeader[0] + pHeader[1] + 8; if (PduLength >= Stream_GetPosition(s)) { Stream_SealLength(s); Stream_SetPosition(s, 0); remdesk_server_receive_pdu(context, s); Stream_SetPosition(s, 0); } } } Stream_Free(s, TRUE); return NULL; }