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)
94 DWORD BytesReturned = 0;
95 PULONG pSessionId = NULL;
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 == NULL)
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)
163 WINPR_ASSERT(ainput);
168 Stream_SetPosition(s, 0);
169 if (!Stream_EnsureCapacity(s, 10))
171 WLog_WARN(TAG,
"[%s] out of memory", AINPUT_DVC_CHANNEL_NAME);
172 return ERROR_OUTOFMEMORY;
175 Stream_Write_UINT16(s, MSG_AINPUT_VERSION);
176 Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR);
177 Stream_Write_UINT32(s, AINPUT_VERSION_MINOR);
179 WINPR_ASSERT(Stream_GetPosition(s) <= UINT32_MAX);
180 if (!WTSVirtualChannelWrite(ainput->ainput_channel, Stream_BufferAs(s,
char),
181 (ULONG)Stream_GetPosition(s), &written))
183 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
184 return ERROR_INTERNAL_ERROR;
187 return CHANNEL_RC_OK;
190static UINT ainput_server_recv_mouse_event(ainput_server* ainput,
wStream* s)
192 UINT error = CHANNEL_RC_OK;
197 char buffer[128] = { 0 };
199 WINPR_ASSERT(ainput);
202 if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
203 return ERROR_NO_DATA;
205 Stream_Read_UINT64(s, time);
206 Stream_Read_UINT64(s, flags);
207 Stream_Read_INT32(s, x);
208 Stream_Read_INT32(s, y);
210 WLog_VRB(TAG,
"received: time=0x%08" PRIx64
", flags=%s, %" PRId32
"x%" PRId32, time,
211 ainput_flags_to_string(flags, buffer,
sizeof(buffer)), x, y);
212 IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y);
217static HANDLE ainput_server_get_channel_handle(ainput_server* ainput)
220 DWORD BytesReturned = 0;
221 HANDLE ChannelEvent = NULL;
223 WINPR_ASSERT(ainput);
225 if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer,
226 &BytesReturned) == TRUE)
228 if (BytesReturned ==
sizeof(HANDLE))
229 ChannelEvent = *(HANDLE*)buffer;
231 WTSFreeMemory(buffer);
237static DWORD WINAPI ainput_server_thread_func(LPVOID arg)
240 HANDLE events[2] = { 0 };
241 ainput_server* ainput = (ainput_server*)arg;
242 UINT error = CHANNEL_RC_OK;
245 WINPR_ASSERT(ainput);
248 events[nCount++] = ainput->stopEvent;
250 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
252 switch (ainput->state)
255 events[1] = ainput_server_get_channel_handle(ainput);
257 status = WaitForMultipleObjects(nCount, events, FALSE, 100);
261 case WAIT_OBJECT_0 + 1:
263 error = ainput_server_context_poll_int(&ainput->context);
267 WLog_WARN(TAG,
"[%s] Wait for open failed", AINPUT_DVC_CHANNEL_NAME);
268 error = ERROR_INTERNAL_ERROR;
272 case AINPUT_VERSION_SENT:
273 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
277 case WAIT_OBJECT_0 + 1:
279 error = ainput_server_context_poll_int(&ainput->context);
284 WLog_WARN(TAG,
"[%s] Wait for version failed", AINPUT_DVC_CHANNEL_NAME);
285 error = ERROR_INTERNAL_ERROR;
290 error = ainput_server_context_poll_int(&ainput->context);
295 (void)WTSVirtualChannelClose(ainput->ainput_channel);
296 ainput->ainput_channel = NULL;
298 if (error && ainput->context.rdpcontext)
299 setChannelError(ainput->context.rdpcontext, error,
300 "ainput_server_thread_func reported an error");
311static UINT ainput_server_open(ainput_server_context* context)
313 ainput_server* ainput = (ainput_server*)context;
315 WINPR_ASSERT(ainput);
317 if (!ainput->externalThread && (ainput->thread == NULL))
319 ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
320 if (!ainput->stopEvent)
322 WLog_ERR(TAG,
"CreateEvent failed!");
323 return ERROR_INTERNAL_ERROR;
326 ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL);
329 WLog_ERR(TAG,
"CreateEvent failed!");
330 (void)CloseHandle(ainput->stopEvent);
331 ainput->stopEvent = NULL;
332 return ERROR_INTERNAL_ERROR;
335 ainput->isOpened = TRUE;
337 return CHANNEL_RC_OK;
345static UINT ainput_server_close(ainput_server_context* context)
347 UINT error = CHANNEL_RC_OK;
348 ainput_server* ainput = (ainput_server*)context;
350 WINPR_ASSERT(ainput);
352 if (!ainput->externalThread && ainput->thread)
354 (void)SetEvent(ainput->stopEvent);
356 if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED)
358 error = GetLastError();
359 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
363 (void)CloseHandle(ainput->thread);
364 (void)CloseHandle(ainput->stopEvent);
365 ainput->thread = NULL;
366 ainput->stopEvent = NULL;
368 if (ainput->externalThread)
370 if (ainput->state != AINPUT_INITIAL)
372 (void)WTSVirtualChannelClose(ainput->ainput_channel);
373 ainput->ainput_channel = NULL;
374 ainput->state = AINPUT_INITIAL;
377 ainput->isOpened = FALSE;
382static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread)
384 UINT error = CHANNEL_RC_OK;
385 ainput_server* ainput = (ainput_server*)context;
387 WINPR_ASSERT(ainput);
389 if (ainput->isOpened)
391 WLog_WARN(TAG,
"Application error: AINPUT channel already initialized, calling in this "
392 "state is not possible!");
393 return ERROR_INVALID_STATE;
395 ainput->externalThread = externalThread;
399ainput_server_context* ainput_server_context_new(HANDLE vcm)
401 ainput_server* ainput = (ainput_server*)calloc(1,
sizeof(ainput_server));
406 ainput->context.vcm = vcm;
407 ainput->context.Open = ainput_server_open;
408 ainput->context.IsOpen = ainput_server_is_open;
409 ainput->context.Close = ainput_server_close;
410 ainput->context.Initialize = ainput_server_initialize;
411 ainput->context.Poll = ainput_server_context_poll;
412 ainput->context.ChannelHandle = ainput_server_context_handle;
414 ainput->buffer = Stream_New(NULL, 4096);
417 return &ainput->context;
419 WINPR_PRAGMA_DIAG_PUSH
420 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
421 ainput_server_context_free(&ainput->context);
422 WINPR_PRAGMA_DIAG_POP
426void ainput_server_context_free(ainput_server_context* context)
428 ainput_server* ainput = (ainput_server*)context;
431 ainput_server_close(context);
432 Stream_Free(ainput->buffer, TRUE);
437static UINT ainput_process_message(ainput_server* ainput)
439 UINT error = ERROR_INTERNAL_ERROR;
440 ULONG BytesReturned = 0;
441 ULONG ActualBytesReturned = 0;
443 WINPR_ASSERT(ainput);
444 WINPR_ASSERT(ainput->ainput_channel);
449 Stream_SetPosition(s, 0);
450 const BOOL rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned);
454 if (BytesReturned < 2)
456 error = CHANNEL_RC_OK;
460 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
462 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
463 error = CHANNEL_RC_NO_MEMORY;
467 if (WTSVirtualChannelRead(ainput->ainput_channel, 0, Stream_BufferAs(s,
char),
468 (ULONG)Stream_Capacity(s), &ActualBytesReturned) == FALSE)
470 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
474 if (BytesReturned != ActualBytesReturned)
476 WLog_ERR(TAG,
"WTSVirtualChannelRead size mismatch %" PRIu32
", expected %" PRIu32,
477 ActualBytesReturned, BytesReturned);
481 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);