23 #include <freerdp/config.h>
25 #include <winpr/cast.h>
26 #include <winpr/crt.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>
38 STATE_WAITING_CLIENT_READY,
43 struct s_rdpei_server_private
53 UINT16 currentMsgType;
58 enum RdpEiState automataState;
61 RdpeiServerContext* rdpei_server_context_new(HANDLE vcm)
63 RdpeiServerContext* ret = calloc(1,
sizeof(*ret));
64 RdpeiServerPrivate* priv = NULL;
69 ret->priv = priv = calloc(1,
sizeof(*ret->priv));
73 priv->inputStream = Stream_New(NULL, 256);
74 if (!priv->inputStream)
77 priv->outputStream = Stream_New(NULL, 200);
78 if (!priv->inputStream)
82 rdpei_server_context_reset(ret);
86 WINPR_PRAGMA_DIAG_PUSH
87 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
88 rdpei_server_context_free(ret);
98 UINT rdpei_server_init(RdpeiServerContext* context)
101 DWORD bytesReturned = 0;
102 RdpeiServerPrivate* priv = context->priv;
103 UINT32 channelId = 0;
106 priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME,
107 WTS_CHANNEL_OPTION_DYNAMIC);
108 if (!priv->channelHandle)
110 WLog_ERR(TAG,
"WTSVirtualChannelOpenEx failed!");
111 return CHANNEL_RC_INITIALIZATION_ERROR;
114 channelId = WTSChannelGetIdByHandle(priv->channelHandle);
116 IFCALLRET(context->onChannelIdAssigned, status, context, channelId);
119 WLog_ERR(TAG,
"context->onChannelIdAssigned failed!");
123 if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer,
125 (bytesReturned !=
sizeof(HANDLE)))
128 "WTSVirtualChannelQuery failed or invalid invalid returned size(%" PRIu32
")!",
131 WTSFreeMemory(buffer);
134 priv->eventHandle = *(HANDLE*)buffer;
135 WTSFreeMemory(buffer);
137 return CHANNEL_RC_OK;
140 (void)WTSVirtualChannelClose(priv->channelHandle);
141 return CHANNEL_RC_INITIALIZATION_ERROR;
144 void rdpei_server_context_reset(RdpeiServerContext* context)
146 RdpeiServerPrivate* priv = context->priv;
148 priv->channelHandle = INVALID_HANDLE_VALUE;
149 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
150 priv->waitingHeaders = TRUE;
151 priv->automataState = STATE_INITIAL;
152 Stream_SetPosition(priv->inputStream, 0);
155 void rdpei_server_context_free(RdpeiServerContext* context)
157 RdpeiServerPrivate* priv = NULL;
161 priv = context->priv;
164 if (priv->channelHandle != INVALID_HANDLE_VALUE)
165 (void)WTSVirtualChannelClose(priv->channelHandle);
166 Stream_Free(priv->inputStream, TRUE);
172 HANDLE rdpei_server_get_event_handle(RdpeiServerContext* context)
174 return context->priv->eventHandle;
182 static UINT read_cs_ready_message(RdpeiServerContext* context,
wStream* s)
184 UINT error = CHANNEL_RC_OK;
185 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
186 return ERROR_INVALID_DATA;
188 Stream_Read_UINT32(s, context->protocolFlags);
189 Stream_Read_UINT32(s, context->clientVersion);
190 Stream_Read_UINT16(s, context->maxTouchPoints);
192 switch (context->clientVersion)
194 case RDPINPUT_PROTOCOL_V10:
195 case RDPINPUT_PROTOCOL_V101:
196 case RDPINPUT_PROTOCOL_V200:
197 case RDPINPUT_PROTOCOL_V300:
200 WLog_ERR(TAG,
"unhandled RPDEI protocol version 0x%" PRIx32
"", context->clientVersion);
204 IFCALLRET(context->onClientReady, error, context);
206 WLog_ERR(TAG,
"context->onClientReady failed with error %" PRIu32
"", error);
216 static UINT read_touch_contact_data(RdpeiServerContext* context,
wStream* s,
219 WINPR_UNUSED(context);
220 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
221 return ERROR_INVALID_DATA;
223 Stream_Read_UINT8(s, contactData->contactId);
224 if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
225 !rdpei_read_4byte_signed(s, &contactData->x) ||
226 !rdpei_read_4byte_signed(s, &contactData->y) ||
227 !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
229 WLog_ERR(TAG,
"rdpei_read_ failed!");
230 return ERROR_INTERNAL_ERROR;
233 if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
235 if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) ||
236 !rdpei_read_2byte_signed(s, &contactData->contactRectTop) ||
237 !rdpei_read_2byte_signed(s, &contactData->contactRectRight) ||
238 !rdpei_read_2byte_signed(s, &contactData->contactRectBottom))
240 WLog_ERR(TAG,
"rdpei_read_ failed!");
241 return ERROR_INTERNAL_ERROR;
245 if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
246 !rdpei_read_4byte_unsigned(s, &contactData->orientation))
248 WLog_ERR(TAG,
"rdpei_read_ failed!");
249 return ERROR_INTERNAL_ERROR;
252 if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
253 !rdpei_read_4byte_unsigned(s, &contactData->pressure))
255 WLog_ERR(TAG,
"rdpei_read_ failed!");
256 return ERROR_INTERNAL_ERROR;
259 return CHANNEL_RC_OK;
262 static UINT read_pen_contact(RdpeiServerContext* context,
wStream* s,
265 WINPR_UNUSED(context);
266 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
267 return ERROR_INVALID_DATA;
269 Stream_Read_UINT8(s, contactData->deviceId);
270 if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
271 !rdpei_read_4byte_signed(s, &contactData->x) ||
272 !rdpei_read_4byte_signed(s, &contactData->y) ||
273 !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
275 WLog_ERR(TAG,
"rdpei_read_ failed!");
276 return ERROR_INTERNAL_ERROR;
279 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT)
281 if (!rdpei_read_4byte_unsigned(s, &contactData->penFlags))
282 return ERROR_INVALID_DATA;
284 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT)
286 if (!rdpei_read_4byte_unsigned(s, &contactData->pressure))
287 return ERROR_INVALID_DATA;
289 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_ROTATION_PRESENT)
291 if (!rdpei_read_2byte_unsigned(s, &contactData->rotation))
292 return ERROR_INVALID_DATA;
294 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTX_PRESENT)
296 if (!rdpei_read_2byte_signed(s, &contactData->tiltX))
297 return ERROR_INVALID_DATA;
299 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTY_PRESENT)
301 if (!rdpei_read_2byte_signed(s, &contactData->tiltY))
302 return ERROR_INVALID_DATA;
305 return CHANNEL_RC_OK;
318 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
319 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
321 WLog_ERR(TAG,
"rdpei_read_ failed!");
322 return ERROR_INTERNAL_ERROR;
326 if (!frame->contacts)
328 WLog_ERR(TAG,
"calloc failed!");
329 return CHANNEL_RC_NO_MEMORY;
332 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
334 if ((error = read_touch_contact_data(context, s, contact)))
336 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
337 frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
338 touch_frame_reset(frame);
342 return CHANNEL_RC_OK;
350 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
351 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
353 WLog_ERR(TAG,
"rdpei_read_ failed!");
354 return ERROR_INTERNAL_ERROR;
358 if (!frame->contacts)
360 WLog_ERR(TAG,
"calloc failed!");
361 return CHANNEL_RC_NO_MEMORY;
364 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
366 if ((error = read_pen_contact(context, s, contact)))
368 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
369 frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
371 pen_frame_reset(frame);
375 return CHANNEL_RC_OK;
383 static UINT read_touch_event(RdpeiServerContext* context,
wStream* s)
385 UINT16 frameCount = 0;
388 UINT error = CHANNEL_RC_OK;
390 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
391 !rdpei_read_2byte_unsigned(s, &frameCount))
393 WLog_ERR(TAG,
"rdpei_read_ failed!");
394 return ERROR_INTERNAL_ERROR;
397 event->frameCount = frameCount;
401 WLog_ERR(TAG,
"calloc failed!");
402 return CHANNEL_RC_NO_MEMORY;
405 for (UINT32 i = 0; i < frameCount; i++, frame++)
407 if ((error = read_touch_frame(context, s, frame)))
409 WLog_ERR(TAG,
"read_touch_contact_data failed with error %" PRIu32
"!", error);
410 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
416 IFCALLRET(context->onTouchEvent, error, context, event);
418 WLog_ERR(TAG,
"context->onTouchEvent failed with error %" PRIu32
"", error);
421 touch_event_reset(event);
425 static UINT read_pen_event(RdpeiServerContext* context,
wStream* s)
427 UINT16 frameCount = 0;
430 UINT error = CHANNEL_RC_OK;
432 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
433 !rdpei_read_2byte_unsigned(s, &frameCount))
435 WLog_ERR(TAG,
"rdpei_read_ failed!");
436 return ERROR_INTERNAL_ERROR;
439 event->frameCount = frameCount;
443 WLog_ERR(TAG,
"calloc failed!");
444 return CHANNEL_RC_NO_MEMORY;
447 for (UINT32 i = 0; i < frameCount; i++, frame++)
449 if ((error = read_pen_frame(context, s, frame)))
451 WLog_ERR(TAG,
"read_pen_frame failed with error %" PRIu32
"!", error);
452 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
458 IFCALLRET(context->onPenEvent, error, context, event);
460 WLog_ERR(TAG,
"context->onPenEvent failed with error %" PRIu32
"", error);
463 pen_event_reset(event);
472 static UINT read_dismiss_hovering_contact(RdpeiServerContext* context,
wStream* s)
475 UINT error = CHANNEL_RC_OK;
477 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
478 return ERROR_INVALID_DATA;
480 Stream_Read_UINT8(s, contactId);
482 IFCALLRET(context->onTouchReleased, error, context, contactId);
484 WLog_ERR(TAG,
"context->onTouchReleased failed with error %" PRIu32
"", error);
494 UINT rdpei_server_handle_messages(RdpeiServerContext* context)
496 DWORD bytesReturned = 0;
497 RdpeiServerPrivate* priv = context->priv;
498 wStream* s = priv->inputStream;
499 UINT error = CHANNEL_RC_OK;
501 if (!WTSVirtualChannelRead(priv->channelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
504 if (GetLastError() == ERROR_NO_DATA)
505 return ERROR_READ_FAULT;
507 WLog_DBG(TAG,
"channel connection closed");
508 return CHANNEL_RC_OK;
510 priv->expectedBytes -= bytesReturned;
511 Stream_Seek(s, bytesReturned);
513 if (priv->expectedBytes)
514 return CHANNEL_RC_OK;
516 Stream_SealLength(s);
517 Stream_SetPosition(s, 0);
519 if (priv->waitingHeaders)
524 Stream_Read_UINT16(s, priv->currentMsgType);
525 Stream_Read_UINT16(s, pduLen);
527 if (pduLen < RDPINPUT_HEADER_LENGTH)
529 WLog_ERR(TAG,
"invalid pduLength %" PRIu32
"", pduLen);
530 return ERROR_INVALID_DATA;
532 priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
533 priv->waitingHeaders = FALSE;
534 Stream_SetPosition(s, 0);
535 if (priv->expectedBytes)
537 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
539 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
540 return CHANNEL_RC_NO_MEMORY;
542 return CHANNEL_RC_OK;
547 switch (priv->currentMsgType)
549 case EVENTID_CS_READY:
550 if (priv->automataState != STATE_WAITING_CLIENT_READY)
552 WLog_ERR(TAG,
"not expecting a CS_READY packet in this state(%d)",
553 priv->automataState);
554 return ERROR_INVALID_STATE;
557 if ((error = read_cs_ready_message(context, s)))
559 WLog_ERR(TAG,
"read_cs_ready_message failed with error %" PRIu32
"", error);
565 if ((error = read_touch_event(context, s)))
567 WLog_ERR(TAG,
"read_touch_event failed with error %" PRIu32
"", error);
571 case EVENTID_DISMISS_HOVERING_CONTACT:
572 if ((error = read_dismiss_hovering_contact(context, s)))
574 WLog_ERR(TAG,
"read_dismiss_hovering_contact failed with error %" PRIu32
"", error);
579 if ((error = read_pen_event(context, s)))
581 WLog_ERR(TAG,
"read_pen_event failed with error %" PRIu32
"", error);
586 WLog_ERR(TAG,
"unexpected message type 0x%" PRIx16
"", priv->currentMsgType);
589 Stream_SetPosition(s, 0);
590 priv->waitingHeaders = TRUE;
591 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
600 UINT rdpei_server_send_sc_ready(RdpeiServerContext* context, UINT32 version, UINT32 features)
603 RdpeiServerPrivate* priv = context->priv;
606 if (priv->automataState != STATE_INITIAL)
608 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
609 return ERROR_INVALID_STATE;
612 Stream_SetPosition(priv->outputStream, 0);
614 if (version >= RDPINPUT_PROTOCOL_V300)
617 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
619 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
620 return CHANNEL_RC_NO_MEMORY;
623 Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
624 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
625 Stream_Write_UINT32(priv->outputStream, version);
626 if (version >= RDPINPUT_PROTOCOL_V300)
627 Stream_Write_UINT32(priv->outputStream, features);
629 const size_t pos = Stream_GetPosition(priv->outputStream);
631 WINPR_ASSERT(pos <= UINT32_MAX);
632 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
633 (ULONG)pos, &written))
635 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
636 return ERROR_INTERNAL_ERROR;
639 priv->automataState = STATE_WAITING_CLIENT_READY;
640 return CHANNEL_RC_OK;
648 UINT rdpei_server_suspend(RdpeiServerContext* context)
651 RdpeiServerPrivate* priv = context->priv;
653 switch (priv->automataState)
655 case STATE_SUSPENDED:
656 WLog_ERR(TAG,
"already suspended");
657 return CHANNEL_RC_OK;
658 case STATE_WAITING_FRAME:
661 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
662 return ERROR_INVALID_STATE;
665 Stream_SetPosition(priv->outputStream, 0);
666 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
668 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
669 return CHANNEL_RC_NO_MEMORY;
672 Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
673 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
675 const size_t pos = Stream_GetPosition(priv->outputStream);
677 WINPR_ASSERT(pos <= UINT32_MAX);
678 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
679 (ULONG)pos, &written))
681 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
682 return ERROR_INTERNAL_ERROR;
685 priv->automataState = STATE_SUSPENDED;
686 return CHANNEL_RC_OK;
694 UINT rdpei_server_resume(RdpeiServerContext* context)
697 RdpeiServerPrivate* priv = context->priv;
699 switch (priv->automataState)
701 case STATE_WAITING_FRAME:
702 WLog_ERR(TAG,
"not suspended");
703 return CHANNEL_RC_OK;
704 case STATE_SUSPENDED:
707 WLog_ERR(TAG,
"called from unexpected state %d", priv->automataState);
708 return ERROR_INVALID_STATE;
711 Stream_SetPosition(priv->outputStream, 0);
712 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
714 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
715 return CHANNEL_RC_NO_MEMORY;
718 Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
719 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
721 const size_t pos = Stream_GetPosition(priv->outputStream);
723 WINPR_ASSERT(pos <= UINT32_MAX);
724 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream,
char),
725 (ULONG)pos, &written))
727 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
728 return ERROR_INTERNAL_ERROR;
731 priv->automataState = STATE_WAITING_FRAME;
732 return CHANNEL_RC_OK;