23#include <freerdp/config.h>
25#include <winpr/cast.h>
27#include <winpr/print.h>
28#include <winpr/stream.h>
30#include "rdpei_main.h"
31#include "../rdpei_common.h"
32#include <freerdp/channels/rdpei.h>
33#include <freerdp/server/rdpei.h>
44 STATE_WAITING_CLIENT_READY,
49struct s_rdpei_server_private
58 eRdpEiChannelState channelState;
65 UINT16 currentMsgType;
70 enum RdpEiState automataState;
73static UINT rdpei_server_open_channel(RdpeiServerContext* context)
75 DWORD error = ERROR_SUCCESS;
76 DWORD bytesReturned = 0;
77 PULONG pSessionId = NULL;
80 WINPR_ASSERT(context);
82 RdpeiServerPrivate* priv = context->priv;
85 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
86 (LPSTR*)&pSessionId, &bytesReturned) == FALSE)
88 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
89 return ERROR_INTERNAL_ERROR;
92 DWORD sessionId = (DWORD)*pSessionId;
93 WTSFreeMemory(pSessionId);
96 WTSVirtualChannelOpenEx(sessionId, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
97 if (!priv->channelHandle)
99 error = GetLastError();
100 WLog_ERR(TAG,
"WTSVirtualChannelOpenEx failed with error %" PRIu32
"!", error);
104 const UINT32 channelId = WTSChannelGetIdByHandle(priv->channelHandle);
106 IFCALLRET(context->onChannelIdAssigned, status, context, channelId);
109 WLog_ERR(TAG,
"context->onChannelIdAssigned failed!");
110 return ERROR_INTERNAL_ERROR;
116static UINT rdpei_server_context_poll_int(RdpeiServerContext* context)
118 RdpeiServerPrivate* priv = NULL;
119 UINT error = ERROR_INTERNAL_ERROR;
121 WINPR_ASSERT(context);
122 priv = context->priv;
125 switch (priv->channelState)
128 error = rdpei_server_open_channel(context);
130 WLog_ERR(TAG,
"rdpei_server_open_channel failed with error %" PRIu32
"!", error);
132 priv->channelState = RDPEI_OPENED;
135 error = rdpei_server_handle_messages(context);
144static HANDLE rdpei_server_get_channel_handle(RdpeiServerContext* context)
146 RdpeiServerPrivate* priv = NULL;
148 DWORD bytesReturned = 0;
149 HANDLE channelEvent = NULL;
151 WINPR_ASSERT(context);
152 priv = context->priv;
155 if (WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer,
156 &bytesReturned) == TRUE)
158 if (bytesReturned ==
sizeof(HANDLE))
159 channelEvent = *(HANDLE*)buffer;
161 WTSFreeMemory(buffer);
167static DWORD WINAPI rdpei_server_thread_func(LPVOID arg)
169 RdpeiServerContext* context = (RdpeiServerContext*)arg;
170 RdpeiServerPrivate* priv = NULL;
171 HANDLE events[2] = { 0 };
173 UINT error = CHANNEL_RC_OK;
176 WINPR_ASSERT(context);
177 priv = context->priv;
180 events[nCount++] = priv->stopEvent;
182 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
184 switch (priv->channelState)
187 error = rdpei_server_context_poll_int(context);
188 if (error == CHANNEL_RC_OK)
190 events[1] = rdpei_server_get_channel_handle(context);
195 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
200 case WAIT_OBJECT_0 + 1:
202 error = rdpei_server_context_poll_int(context);
207 error = ERROR_INTERNAL_ERROR;
216 (void)WTSVirtualChannelClose(priv->channelHandle);
217 priv->channelHandle = NULL;
223static UINT rdpei_server_open(RdpeiServerContext* context)
225 RdpeiServerPrivate* priv = NULL;
227 priv = context->priv;
232 priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
233 if (!priv->stopEvent)
235 WLog_ERR(TAG,
"CreateEvent failed!");
236 return ERROR_INTERNAL_ERROR;
239 priv->thread = CreateThread(NULL, 0, rdpei_server_thread_func, context, 0, NULL);
242 WLog_ERR(TAG,
"CreateThread failed!");
243 (void)CloseHandle(priv->stopEvent);
244 priv->stopEvent = NULL;
245 return ERROR_INTERNAL_ERROR;
249 return CHANNEL_RC_OK;
252static UINT rdpei_server_close(RdpeiServerContext* context)
254 RdpeiServerPrivate* priv = NULL;
255 UINT error = CHANNEL_RC_OK;
257 priv = context->priv;
262 (void)SetEvent(priv->stopEvent);
264 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
266 error = GetLastError();
267 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
271 (void)CloseHandle(priv->thread);
272 (void)CloseHandle(priv->stopEvent);
274 priv->stopEvent = NULL;
280RdpeiServerContext* rdpei_server_context_new(HANDLE vcm)
282 RdpeiServerContext* ret = calloc(1,
sizeof(*ret));
287 ret->Open = rdpei_server_open;
288 ret->Close = rdpei_server_close;
290 ret->priv = calloc(1,
sizeof(*ret->priv));
294 ret->priv->inputStream = Stream_New(NULL, 256);
295 if (!ret->priv->inputStream)
298 ret->priv->outputStream = Stream_New(NULL, 200);
299 if (!ret->priv->outputStream)
303 rdpei_server_context_reset(ret);
307 WINPR_PRAGMA_DIAG_PUSH
308 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
309 rdpei_server_context_free(ret);
310 WINPR_PRAGMA_DIAG_POP
319UINT rdpei_server_init(RdpeiServerContext* context)
321 RdpeiServerPrivate* priv = context->priv;
322 UINT error = rdpei_server_open_channel(context);
326 priv->eventHandle = rdpei_server_get_channel_handle(context);
327 if (!priv->eventHandle)
329 WLog_ERR(TAG,
"Failed to get channel handle!");
333 return CHANNEL_RC_OK;
336 (void)WTSVirtualChannelClose(priv->channelHandle);
337 return CHANNEL_RC_INITIALIZATION_ERROR;
340void rdpei_server_context_reset(RdpeiServerContext* context)
342 RdpeiServerPrivate* priv = context->priv;
344 priv->channelHandle = INVALID_HANDLE_VALUE;
345 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
346 priv->waitingHeaders = TRUE;
347 priv->automataState = STATE_INITIAL;
348 Stream_SetPosition(priv->inputStream, 0);
351void rdpei_server_context_free(RdpeiServerContext* context)
355 RdpeiServerPrivate* priv = context->priv;
358 if (priv->channelHandle && priv->channelHandle != INVALID_HANDLE_VALUE)
359 (void)WTSVirtualChannelClose(priv->channelHandle);
360 Stream_Free(priv->inputStream, TRUE);
361 Stream_Free(priv->outputStream, TRUE);
367HANDLE rdpei_server_get_event_handle(RdpeiServerContext* context)
369 return context->priv->eventHandle;
377static UINT read_cs_ready_message(RdpeiServerContext* context,
wStream* s)
379 UINT error = CHANNEL_RC_OK;
380 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
381 return ERROR_INVALID_DATA;
383 Stream_Read_UINT32(s, context->protocolFlags);
384 Stream_Read_UINT32(s, context->clientVersion);
385 Stream_Read_UINT16(s, context->maxTouchPoints);
387 switch (context->clientVersion)
389 case RDPINPUT_PROTOCOL_V10:
390 case RDPINPUT_PROTOCOL_V101:
391 case RDPINPUT_PROTOCOL_V200:
392 case RDPINPUT_PROTOCOL_V300:
395 WLog_ERR(TAG,
"unhandled RPDEI protocol version 0x%" PRIx32
"", context->clientVersion);
399 IFCALLRET(context->onClientReady, error, context);
401 WLog_ERR(TAG,
"context->onClientReady failed with error %" PRIu32
"", error);
411static UINT read_touch_contact_data(RdpeiServerContext* context,
wStream* s,
414 WINPR_UNUSED(context);
415 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
416 return ERROR_INVALID_DATA;
418 Stream_Read_UINT8(s, contactData->contactId);
419 if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
420 !rdpei_read_4byte_signed(s, &contactData->x) ||
421 !rdpei_read_4byte_signed(s, &contactData->y) ||
422 !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
424 WLog_ERR(TAG,
"rdpei_read_ failed!");
425 return ERROR_INTERNAL_ERROR;
428 if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
430 if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) ||
431 !rdpei_read_2byte_signed(s, &contactData->contactRectTop) ||
432 !rdpei_read_2byte_signed(s, &contactData->contactRectRight) ||
433 !rdpei_read_2byte_signed(s, &contactData->contactRectBottom))
435 WLog_ERR(TAG,
"rdpei_read_ failed!");
436 return ERROR_INTERNAL_ERROR;
440 if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
441 !rdpei_read_4byte_unsigned(s, &contactData->orientation))
443 WLog_ERR(TAG,
"rdpei_read_ failed!");
444 return ERROR_INTERNAL_ERROR;
447 if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
448 !rdpei_read_4byte_unsigned(s, &contactData->pressure))
450 WLog_ERR(TAG,
"rdpei_read_ failed!");
451 return ERROR_INTERNAL_ERROR;
454 return CHANNEL_RC_OK;
457static UINT read_pen_contact(RdpeiServerContext* context,
wStream* s,
460 WINPR_UNUSED(context);
461 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
462 return ERROR_INVALID_DATA;
464 Stream_Read_UINT8(s, contactData->deviceId);
465 if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
466 !rdpei_read_4byte_signed(s, &contactData->x) ||
467 !rdpei_read_4byte_signed(s, &contactData->y) ||
468 !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
470 WLog_ERR(TAG,
"rdpei_read_ failed!");
471 return ERROR_INTERNAL_ERROR;
474 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT)
476 if (!rdpei_read_4byte_unsigned(s, &contactData->penFlags))
477 return ERROR_INVALID_DATA;
479 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT)
481 if (!rdpei_read_4byte_unsigned(s, &contactData->pressure))
482 return ERROR_INVALID_DATA;
484 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_ROTATION_PRESENT)
486 if (!rdpei_read_2byte_unsigned(s, &contactData->rotation))
487 return ERROR_INVALID_DATA;
489 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTX_PRESENT)
491 if (!rdpei_read_2byte_signed(s, &contactData->tiltX))
492 return ERROR_INVALID_DATA;
494 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTY_PRESENT)
496 if (!rdpei_read_2byte_signed(s, &contactData->tiltY))
497 return ERROR_INVALID_DATA;
500 return CHANNEL_RC_OK;
513 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
514 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
516 WLog_ERR(TAG,
"rdpei_read_ failed!");
517 return ERROR_INTERNAL_ERROR;
521 if (!frame->contacts)
523 WLog_ERR(TAG,
"calloc failed!");
524 return CHANNEL_RC_NO_MEMORY;
527 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
529 if ((error = read_touch_contact_data(context, s, contact)))
531 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
532 frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
533 touch_frame_reset(frame);
537 return CHANNEL_RC_OK;
545 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
546 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
548 WLog_ERR(TAG,
"rdpei_read_ failed!");
549 return ERROR_INTERNAL_ERROR;
553 if (!frame->contacts)
555 WLog_ERR(TAG,
"calloc failed!");
556 return CHANNEL_RC_NO_MEMORY;
559 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
561 if ((error = read_pen_contact(context, s, contact)))
563 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
564 frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
566 pen_frame_reset(frame);
570 return CHANNEL_RC_OK;
578static UINT read_touch_event(RdpeiServerContext* context,
wStream* s)
580 UINT16 frameCount = 0;
583 UINT error = CHANNEL_RC_OK;
585 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
586 !rdpei_read_2byte_unsigned(s, &frameCount))
588 WLog_ERR(TAG,
"rdpei_read_ failed!");
589 return ERROR_INTERNAL_ERROR;
592 event->frameCount = frameCount;
596 WLog_ERR(TAG,
"calloc failed!");
597 return CHANNEL_RC_NO_MEMORY;
600 for (UINT32 i = 0; i < frameCount; i++, frame++)
602 if ((error = read_touch_frame(context, s, frame)))
604 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
605 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
611 IFCALLRET(context->onTouchEvent, error, context, event);
613 WLog_ERR(TAG,
"context->onTouchEvent failed with error %" PRIu32
"", error);
616 touch_event_reset(event);
620static UINT read_pen_event(RdpeiServerContext* context,
wStream* s)
622 UINT16 frameCount = 0;
625 UINT error = CHANNEL_RC_OK;
627 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
628 !rdpei_read_2byte_unsigned(s, &frameCount))
630 WLog_ERR(TAG,
"rdpei_read_ failed!");
631 return ERROR_INTERNAL_ERROR;
634 event->frameCount = frameCount;
638 WLog_ERR(TAG,
"calloc failed!");
639 return CHANNEL_RC_NO_MEMORY;
642 for (UINT32 i = 0; i < frameCount; i++, frame++)
644 if ((error = read_pen_frame(context, s, frame)))
646 WLog_ERR(TAG,
"read_pen_frame failed with error %" PRIu32
"!", error);
647 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
653 IFCALLRET(context->onPenEvent, error, context, event);
655 WLog_ERR(TAG,
"context->onPenEvent failed with error %" PRIu32
"", error);
658 pen_event_reset(event);
667static UINT read_dismiss_hovering_contact(RdpeiServerContext* context,
wStream* s)
670 UINT error = CHANNEL_RC_OK;
672 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
673 return ERROR_INVALID_DATA;
675 Stream_Read_UINT8(s, contactId);
677 IFCALLRET(context->onTouchReleased, error, context, contactId);
679 WLog_ERR(TAG,
"context->onTouchReleased failed with error %" PRIu32
"", error);
689UINT rdpei_server_handle_messages(RdpeiServerContext* context)
691 DWORD bytesReturned = 0;
692 RdpeiServerPrivate* priv = context->priv;
693 wStream* s = priv->inputStream;
694 UINT error = CHANNEL_RC_OK;
696 if (!WTSVirtualChannelRead(priv->channelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
699 if (GetLastError() == ERROR_NO_DATA)
700 return ERROR_READ_FAULT;
702 WLog_DBG(TAG,
"channel connection closed");
703 return CHANNEL_RC_OK;
705 priv->expectedBytes -= bytesReturned;
706 Stream_Seek(s, bytesReturned);
708 if (priv->expectedBytes)
709 return CHANNEL_RC_OK;
711 Stream_SealLength(s);
712 Stream_SetPosition(s, 0);
714 if (priv->waitingHeaders)
719 Stream_Read_UINT16(s, priv->currentMsgType);
720 Stream_Read_UINT32(s, pduLen);
722 if (pduLen < RDPINPUT_HEADER_LENGTH)
724 WLog_ERR(TAG,
"invalid pduLength %" PRIu32
"", pduLen);
725 return ERROR_INVALID_DATA;
727 priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
728 priv->waitingHeaders = FALSE;
729 Stream_SetPosition(s, 0);
730 if (priv->expectedBytes)
732 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
734 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
735 return CHANNEL_RC_NO_MEMORY;
737 return CHANNEL_RC_OK;
742 switch (priv->currentMsgType)
744 case EVENTID_CS_READY:
745 if (priv->automataState != STATE_WAITING_CLIENT_READY)
747 WLog_ERR(TAG,
"not expecting a CS_READY packet in this state(%d)",
748 priv->automataState);
749 return ERROR_INVALID_STATE;
752 if ((error = read_cs_ready_message(context, s)))
754 WLog_ERR(TAG,
"read_cs_ready_message failed with error %" PRIu32
"", error);
760 if ((error = read_touch_event(context, s)))
762 WLog_ERR(TAG,
"read_touch_event failed with error %" PRIu32
"", error);
766 case EVENTID_DISMISS_HOVERING_CONTACT:
767 if ((error = read_dismiss_hovering_contact(context, s)))
769 WLog_ERR(TAG,
"read_dismiss_hovering_contact failed with error %" PRIu32
"", error);
774 if ((error = read_pen_event(context, s)))
776 WLog_ERR(TAG,
"read_pen_event failed with error %" PRIu32
"", error);
781 WLog_ERR(TAG,
"unexpected message type 0x%" PRIx16
"", priv->currentMsgType);
784 Stream_SetPosition(s, 0);
785 priv->waitingHeaders = TRUE;
786 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
795UINT rdpei_server_send_sc_ready(RdpeiServerContext* context, UINT32 version, UINT32 features)
798 RdpeiServerPrivate* priv = context->priv;
801 if (priv->automataState != STATE_INITIAL)
803 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
804 return ERROR_INVALID_STATE;
807 Stream_SetPosition(priv->outputStream, 0);
809 if (version >= RDPINPUT_PROTOCOL_V300)
812 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
814 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
815 return CHANNEL_RC_NO_MEMORY;
818 Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
819 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
820 Stream_Write_UINT32(priv->outputStream, version);
821 if (version >= RDPINPUT_PROTOCOL_V300)
822 Stream_Write_UINT32(priv->outputStream, features);
824 const size_t pos = Stream_GetPosition(priv->outputStream);
826 WINPR_ASSERT(pos <= UINT32_MAX);
827 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
828 (ULONG)pos, &written))
830 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
831 return ERROR_INTERNAL_ERROR;
834 priv->automataState = STATE_WAITING_CLIENT_READY;
835 return CHANNEL_RC_OK;
843UINT rdpei_server_suspend(RdpeiServerContext* context)
846 RdpeiServerPrivate* priv = context->priv;
848 switch (priv->automataState)
850 case STATE_SUSPENDED:
851 WLog_ERR(TAG,
"already suspended");
852 return CHANNEL_RC_OK;
853 case STATE_WAITING_FRAME:
856 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
857 return ERROR_INVALID_STATE;
860 Stream_SetPosition(priv->outputStream, 0);
861 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
863 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
864 return CHANNEL_RC_NO_MEMORY;
867 Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
868 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
870 const size_t pos = Stream_GetPosition(priv->outputStream);
872 WINPR_ASSERT(pos <= UINT32_MAX);
873 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
874 (ULONG)pos, &written))
876 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
877 return ERROR_INTERNAL_ERROR;
880 priv->automataState = STATE_SUSPENDED;
881 return CHANNEL_RC_OK;
889UINT rdpei_server_resume(RdpeiServerContext* context)
892 RdpeiServerPrivate* priv = context->priv;
894 switch (priv->automataState)
896 case STATE_WAITING_FRAME:
897 WLog_ERR(TAG,
"not suspended");
898 return CHANNEL_RC_OK;
899 case STATE_SUSPENDED:
902 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
903 return ERROR_INVALID_STATE;
906 Stream_SetPosition(priv->outputStream, 0);
907 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
909 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
910 return CHANNEL_RC_NO_MEMORY;
913 Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
914 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
916 const size_t pos = Stream_GetPosition(priv->outputStream);
918 WINPR_ASSERT(pos <= UINT32_MAX);
919 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
920 (ULONG)pos, &written))
922 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
923 return ERROR_INTERNAL_ERROR;
926 priv->automataState = STATE_WAITING_FRAME;
927 return CHANNEL_RC_OK;