21 #include <freerdp/config.h>
27 #include <winpr/crt.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")
48 } eAInputChannelState;
52 ainput_server_context context;
67 eAInputChannelState state;
72 static UINT ainput_server_context_poll(ainput_server_context* context);
73 static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle);
74 static UINT ainput_server_context_poll_int(ainput_server_context* context);
76 static BOOL ainput_server_is_open(ainput_server_context* context)
78 ainput_server* ainput = (ainput_server*)context;
81 return ainput->isOpened;
89 static 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;
158 static 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;
190 static 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);
217 static 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 CopyMemory(&ChannelEvent, buffer,
sizeof(HANDLE));
231 WTSFreeMemory(buffer);
237 static 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");
311 static 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;
345 static 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;
382 static 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;
399 ainput_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
426 void 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);
437 static UINT ainput_process_message(ainput_server* ainput)
440 UINT error = ERROR_INTERNAL_ERROR;
441 ULONG BytesReturned = 0;
442 ULONG ActualBytesReturned = 0;
443 UINT16 MessageId = 0;
446 WINPR_ASSERT(ainput);
447 WINPR_ASSERT(ainput->ainput_channel);
452 Stream_SetPosition(s, 0);
453 rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned);
457 if (BytesReturned < 2)
459 error = CHANNEL_RC_OK;
463 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
465 WLog_ERR(TAG,
"Stream_EnsureRemainingCapacity failed!");
466 error = CHANNEL_RC_NO_MEMORY;
470 if (WTSVirtualChannelRead(ainput->ainput_channel, 0, Stream_BufferAs(s,
char),
471 (ULONG)Stream_Capacity(s), &ActualBytesReturned) == FALSE)
473 WLog_ERR(TAG,
"WTSVirtualChannelRead failed!");
477 if (BytesReturned != ActualBytesReturned)
479 WLog_ERR(TAG,
"WTSVirtualChannelRead size mismatch %" PRId32
", expected %" PRId32,
480 ActualBytesReturned, BytesReturned);
484 Stream_SetLength(s, ActualBytesReturned);
485 Stream_Read_UINT16(s, MessageId);
489 case MSG_AINPUT_MOUSE:
490 error = ainput_server_recv_mouse_event(ainput, s);
494 WLog_ERR(TAG,
"audin_server_thread_func: unknown MessageId %" PRIu8
"", MessageId);
500 WLog_ERR(TAG,
"Response failed with error %" PRIu32
"!", error);
505 BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle)
507 ainput_server* ainput = (ainput_server*)context;
508 WINPR_ASSERT(ainput);
509 WINPR_ASSERT(handle);
511 if (!ainput->externalThread)
513 WLog_WARN(TAG,
"[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
516 if (ainput->state == AINPUT_INITIAL)
518 WLog_WARN(TAG,
"[%s] state fail!", AINPUT_DVC_CHANNEL_NAME);
521 *handle = ainput_server_get_channel_handle(ainput);
525 UINT ainput_server_context_poll_int(ainput_server_context* context)
527 ainput_server* ainput = (ainput_server*)context;
528 UINT error = ERROR_INTERNAL_ERROR;
530 WINPR_ASSERT(ainput);
532 switch (ainput->state)
535 error = ainput_server_open_channel(ainput);
537 WLog_ERR(TAG,
"ainput_server_open_channel failed with error %" PRIu32
"!", error);
539 ainput->state = AINPUT_OPENED;
548 DWORD BytesReturned = 0;
552 if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer.pv,
553 &BytesReturned) != TRUE)
555 WLog_ERR(TAG,
"WTSVirtualChannelReady failed,");
561 error = ainput_server_send_version(ainput);
563 WLog_ERR(TAG,
"audin_server_send_version failed with error %" PRIu32
"!",
566 ainput->state = AINPUT_VERSION_SENT;
569 error = CHANNEL_RC_OK;
571 WTSFreeMemory(buffer.pv);
574 case AINPUT_VERSION_SENT:
575 error = ainput_process_message(ainput);
579 WLog_ERR(TAG,
"AINPUT chanel is in invalid state %d", ainput->state);
586 UINT ainput_server_context_poll(ainput_server_context* context)
588 ainput_server* ainput = (ainput_server*)context;
590 WINPR_ASSERT(ainput);
591 if (!ainput->externalThread)
593 WLog_WARN(TAG,
"[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME);
594 return ERROR_INTERNAL_ERROR;
596 return ainput_server_context_poll_int(context);