21#include <freerdp/config.h>
28#include <winpr/assert.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
32#include <winpr/sysinfo.h>
34#include <freerdp/freerdp.h>
35#include <freerdp/channels/ainput.h>
36#include <freerdp/server/ainput.h>
37#include <freerdp/channels/log.h>
39#include "../common/ainput_common.h"
41#define TAG CHANNELS_TAG("ainput.server")
52 ainput_server_context context;
67 eAInputChannelState state;
72static UINT ainput_server_context_poll(ainput_server_context* context);
73static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle);
74static UINT ainput_server_context_poll_int(ainput_server_context* context);
76static BOOL ainput_server_is_open(ainput_server_context* context)
78 ainput_server* ainput = (ainput_server*)context;
81 return ainput->isOpened;
89static UINT ainput_server_open_channel(ainput_server* ainput)
92 HANDLE hEvent =
nullptr;
94 DWORD BytesReturned = 0;
95 PULONG pSessionId =
nullptr;
99 if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
100 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
102 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
103 return ERROR_INTERNAL_ERROR;
106 ainput->SessionId = (DWORD)*pSessionId;
107 WTSFreeMemory(pSessionId);
108 hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm);
109 StartTick = GetTickCount();
111 while (ainput->ainput_channel ==
nullptr)
113 if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
115 Error = GetLastError();
116 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", Error);
120 ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME,
121 WTS_CHANNEL_OPTION_DYNAMIC);
123 Error = GetLastError();
125 if (Error == ERROR_NOT_FOUND)
127 WLog_DBG(TAG,
"Channel %s not found", AINPUT_DVC_CHANNEL_NAME);
131 if (ainput->ainput_channel)
133 UINT32 channelId = 0;
136 channelId = WTSChannelGetIdByHandle(ainput->ainput_channel);
138 IFCALLRET(ainput->context.ChannelIdAssigned, status, &ainput->context, channelId);
141 WLog_ERR(TAG,
"context->ChannelIdAssigned failed!");
142 return ERROR_INTERNAL_ERROR;
148 if (GetTickCount() - StartTick > 5000)
150 WLog_WARN(TAG,
"Timeout opening channel %s", AINPUT_DVC_CHANNEL_NAME);
155 return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
158static UINT ainput_server_send_version(ainput_server* ainput)
162 WINPR_ASSERT(ainput);
167 Stream_ResetPosition(s);
168 if (!Stream_EnsureCapacity(s, 10))
170 WLog_WARN(TAG,
"[%s] out of memory", AINPUT_DVC_CHANNEL_NAME);
171 return ERROR_OUTOFMEMORY;
174 Stream_Write_UINT16(s, MSG_AINPUT_VERSION);
175 Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR);
176 Stream_Write_UINT32(s, AINPUT_VERSION_MINOR);
178 const ULONG len = WINPR_ASSERTING_INT_CAST(ULONG, Stream_GetPosition(s));
179 if (!WTSVirtualChannelWrite(ainput->ainput_channel, Stream_BufferAs(s,
char), len, &written))
181 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
182 return ERROR_INTERNAL_ERROR;
185 return CHANNEL_RC_OK;
188static UINT ainput_server_recv_mouse_event(ainput_server* ainput,
wStream* s)
190 UINT error = CHANNEL_RC_OK;
195 char buffer[128] = WINPR_C_ARRAY_INIT;
197 WINPR_ASSERT(ainput);
200 if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
201 return ERROR_NO_DATA;
203 Stream_Read_UINT64(s, time);
204 Stream_Read_UINT64(s, flags);
205 Stream_Read_INT32(s, x);
206 Stream_Read_INT32(s, y);
208 WLog_VRB(TAG,
"received: time=0x%08" PRIx64
", flags=%s, %" PRId32
"x%" PRId32, time,
209 ainput_flags_to_string(flags, buffer,
sizeof(buffer)), x, y);
210 IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y);
215static HANDLE ainput_server_get_channel_handle(ainput_server* ainput)
217 void* buffer =
nullptr;
218 DWORD BytesReturned = 0;
219 HANDLE ChannelEvent =
nullptr;
221 WINPR_ASSERT(ainput);
223 if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer,
224 &BytesReturned) == TRUE)
226 if (BytesReturned ==
sizeof(HANDLE))
227 ChannelEvent = *(HANDLE*)buffer;
229 WTSFreeMemory(buffer);
235static DWORD WINAPI ainput_server_thread_func(LPVOID arg)
238 HANDLE events[2] = WINPR_C_ARRAY_INIT;
239 ainput_server* ainput = (ainput_server*)arg;
240 UINT error = CHANNEL_RC_OK;
243 WINPR_ASSERT(ainput);
246 events[nCount++] = ainput->stopEvent;
248 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
250 switch (ainput->state)
253 events[1] = ainput_server_get_channel_handle(ainput);
255 status = WaitForMultipleObjects(nCount, events, FALSE, 100);
259 case WAIT_OBJECT_0 + 1:
261 error = ainput_server_context_poll_int(&ainput->context);
265 WLog_WARN(TAG,
"[%s] Wait for open failed", AINPUT_DVC_CHANNEL_NAME);
266 error = ERROR_INTERNAL_ERROR;
270 case AINPUT_VERSION_SENT:
271 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
275 case WAIT_OBJECT_0 + 1:
277 error = ainput_server_context_poll_int(&ainput->context);
282 WLog_WARN(TAG,
"[%s] Wait for version failed", AINPUT_DVC_CHANNEL_NAME);
283 error = ERROR_INTERNAL_ERROR;
288 error = ainput_server_context_poll_int(&ainput->context);
293 (void)WTSVirtualChannelClose(ainput->ainput_channel);
294 ainput->ainput_channel =
nullptr;
296 if (error && ainput->context.rdpcontext)
297 setChannelError(ainput->context.rdpcontext, error,
298 "ainput_server_thread_func reported an error");
309static UINT ainput_server_open(ainput_server_context* context)
311 ainput_server* ainput = (ainput_server*)context;
313 WINPR_ASSERT(ainput);
315 if (!ainput->externalThread && (ainput->thread ==
nullptr))
317 ainput->stopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
318 if (!ainput->stopEvent)
320 WLog_ERR(TAG,
"CreateEvent failed!");
321 return ERROR_INTERNAL_ERROR;
324 ainput->thread = CreateThread(
nullptr, 0, ainput_server_thread_func, ainput, 0,
nullptr);
327 WLog_ERR(TAG,
"CreateEvent failed!");
328 (void)CloseHandle(ainput->stopEvent);
329 ainput->stopEvent =
nullptr;
330 return ERROR_INTERNAL_ERROR;
333 ainput->isOpened = TRUE;
335 return CHANNEL_RC_OK;
343static UINT ainput_server_close(ainput_server_context* context)
345 UINT error = CHANNEL_RC_OK;
346 ainput_server* ainput = (ainput_server*)context;
348 WINPR_ASSERT(ainput);
350 if (!ainput->externalThread && ainput->thread)
352 (void)SetEvent(ainput->stopEvent);
354 if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED)
356 error = GetLastError();
357 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
361 (void)CloseHandle(ainput->thread);
362 (void)CloseHandle(ainput->stopEvent);
363 ainput->thread =
nullptr;
364 ainput->stopEvent =
nullptr;
366 if (ainput->externalThread)
368 if (ainput->state != AINPUT_INITIAL)
370 (void)WTSVirtualChannelClose(ainput->ainput_channel);
371 ainput->ainput_channel =
nullptr;
372 ainput->state = AINPUT_INITIAL;
375 ainput->isOpened = FALSE;
380static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread)
382 UINT error = CHANNEL_RC_OK;
383 ainput_server* ainput = (ainput_server*)context;
385 WINPR_ASSERT(ainput);
387 if (ainput->isOpened)
389 WLog_WARN(TAG,
"Application error: AINPUT channel already initialized, calling in this "
390 "state is not possible!");
391 return ERROR_INVALID_STATE;
393 ainput->externalThread = externalThread;
397ainput_server_context* ainput_server_context_new(HANDLE vcm)
399 ainput_server* ainput = (ainput_server*)calloc(1,
sizeof(ainput_server));
404 ainput->context.vcm = vcm;
405 ainput->context.Open = ainput_server_open;
406 ainput->context.IsOpen = ainput_server_is_open;
407 ainput->context.Close = ainput_server_close;
408 ainput->context.Initialize = ainput_server_initialize;
409 ainput->context.Poll = ainput_server_context_poll;
410 ainput->context.ChannelHandle = ainput_server_context_handle;
412 ainput->buffer = Stream_New(
nullptr, 4096);
415 return &ainput->context;
417 WINPR_PRAGMA_DIAG_PUSH
418 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
419 ainput_server_context_free(&ainput->context);
420 WINPR_PRAGMA_DIAG_POP
424void ainput_server_context_free(ainput_server_context* context)
426 ainput_server* ainput = (ainput_server*)context;
429 ainput_server_close(context);
430 Stream_Free(ainput->buffer, TRUE);
435static UINT ainput_process_message(ainput_server* ainput)
437 UINT error = ERROR_INTERNAL_ERROR;
438 ULONG BytesReturned = 0;
439 ULONG ActualBytesReturned = 0;
441 WINPR_ASSERT(ainput);
442 WINPR_ASSERT(ainput->ainput_channel);
447 Stream_ResetPosition(s);
448 const BOOL rc = WTSVirtualChannelRead(ainput->ainput_channel, 0,
nullptr, 0, &BytesReturned);
452 if (BytesReturned < 2)
454 error = CHANNEL_RC_OK;
458 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
460 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
461 error = CHANNEL_RC_NO_MEMORY;
465 if (WTSVirtualChannelRead(ainput->ainput_channel, 0, Stream_BufferAs(s,
char),
466 (ULONG)Stream_Capacity(s), &ActualBytesReturned) == FALSE)
468 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
472 if (BytesReturned != ActualBytesReturned)
474 WLog_ERR(TAG,
"WTSVirtualChannelRead size mismatch %" PRIu32
", expected %" PRIu32,
475 ActualBytesReturned, BytesReturned);
479 if (!Stream_SetLength(s, ActualBytesReturned))
483 const UINT16 MessageId = Stream_Get_UINT16(s);
487 case MSG_AINPUT_MOUSE:
488 error = ainput_server_recv_mouse_event(ainput, s);
492 WLog_ERR(TAG,
"audin_server_thread_func: unknown MessageId %" PRIu16
"", MessageId);
499 WLog_ERR(TAG,
"Response failed with error %" PRIu32
"!", error);
504BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle)
506 ainput_server* ainput = (ainput_server*)context;
507 WINPR_ASSERT(ainput);
508 WINPR_ASSERT(handle);
510 if (!ainput->externalThread)
512 WLog_WARN(TAG,
"[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
515 if (ainput->state == AINPUT_INITIAL)
517 WLog_WARN(TAG,
"[%s] state fail!", AINPUT_DVC_CHANNEL_NAME);
520 *handle = ainput_server_get_channel_handle(ainput);
524UINT ainput_server_context_poll_int(ainput_server_context* context)
526 ainput_server* ainput = (ainput_server*)context;
527 UINT error = ERROR_INTERNAL_ERROR;
529 WINPR_ASSERT(ainput);
531 switch (ainput->state)
534 error = ainput_server_open_channel(ainput);
536 WLog_ERR(TAG,
"ainput_server_open_channel failed with error %" PRIu32
"!", error);
538 ainput->state = AINPUT_OPENED;
547 DWORD BytesReturned = 0;
551 if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer.pv,
552 &BytesReturned) != TRUE)
554 WLog_ERR(TAG,
"WTSVirtualChannelReady failed,");
560 error = ainput_server_send_version(ainput);
562 WLog_ERR(TAG,
"audin_server_send_version failed with error %" PRIu32
"!",
565 ainput->state = AINPUT_VERSION_SENT;
568 error = CHANNEL_RC_OK;
570 WTSFreeMemory(buffer.pv);
573 case AINPUT_VERSION_SENT:
574 error = ainput_process_message(ainput);
578 WLog_ERR(TAG,
"AINPUT channel is in invalid state %u", ainput->state);
585UINT ainput_server_context_poll(ainput_server_context* context)
587 ainput_server* ainput = (ainput_server*)context;
589 WINPR_ASSERT(ainput);
590 if (!ainput->externalThread)
592 WLog_WARN(TAG,
"[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
593 return ERROR_INTERNAL_ERROR;
595 return ainput_server_context_poll_int(context);