FreeRDP
Loading...
Searching...
No Matches
server/rdpei_main.c
1
23#include <freerdp/config.h>
24
25#include <winpr/cast.h>
26#include <winpr/crt.h>
27#include <winpr/print.h>
28#include <winpr/stream.h>
29
30#include "rdpei_main.h"
31#include "../rdpei_common.h"
32#include <freerdp/channels/rdpei.h>
33#include <freerdp/server/rdpei.h>
34
35typedef enum
36{
37 RDPEI_INITIAL,
38 RDPEI_OPENED,
39} eRdpEiChannelState;
40
41enum RdpEiState
42{
43 STATE_INITIAL,
44 STATE_WAITING_CLIENT_READY,
45 STATE_WAITING_FRAME,
46 STATE_SUSPENDED,
47};
48
49struct s_rdpei_server_private
50{
51 HANDLE channelHandle;
52 HANDLE eventHandle;
53
54 HANDLE stopEvent;
55 HANDLE thread;
56
57 /* Channel state */
58 eRdpEiChannelState channelState;
59
60 UINT32 expectedBytes;
61 BOOL waitingHeaders;
62 wStream* inputStream;
63 wStream* outputStream;
64
65 UINT16 currentMsgType;
66
67 RDPINPUT_TOUCH_EVENT touchEvent;
68 RDPINPUT_PEN_EVENT penEvent;
69
70 enum RdpEiState automataState;
71};
72
73static UINT rdpei_server_open_channel(RdpeiServerContext* context)
74{
75 DWORD error = ERROR_SUCCESS;
76 DWORD bytesReturned = 0;
77 PULONG pSessionId = nullptr;
78 BOOL status = TRUE;
79
80 WINPR_ASSERT(context);
81
82 RdpeiServerPrivate* priv = context->priv;
83 WINPR_ASSERT(priv);
84
85 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
86 (LPSTR*)&pSessionId, &bytesReturned) == FALSE)
87 {
88 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
89 return ERROR_INTERNAL_ERROR;
90 }
91
92 DWORD sessionId = (DWORD)*pSessionId;
93 WTSFreeMemory(pSessionId);
94
95 priv->channelHandle =
96 WTSVirtualChannelOpenEx(sessionId, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
97 if (!priv->channelHandle)
98 {
99 error = GetLastError();
100 WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", error);
101 return error;
102 }
103
104 const UINT32 channelId = WTSChannelGetIdByHandle(priv->channelHandle);
105
106 IFCALLRET(context->onChannelIdAssigned, status, context, channelId);
107 if (!status)
108 {
109 WLog_ERR(TAG, "context->onChannelIdAssigned failed!");
110 return ERROR_INTERNAL_ERROR;
111 }
112
113 return error;
114}
115
116static UINT rdpei_server_context_poll_int(RdpeiServerContext* context)
117{
118 RdpeiServerPrivate* priv = nullptr;
119 UINT error = ERROR_INTERNAL_ERROR;
120
121 WINPR_ASSERT(context);
122 priv = context->priv;
123 WINPR_ASSERT(priv);
124
125 switch (priv->channelState)
126 {
127 case RDPEI_INITIAL:
128 error = rdpei_server_open_channel(context);
129 if (error)
130 WLog_ERR(TAG, "rdpei_server_open_channel failed with error %" PRIu32 "!", error);
131 else
132 priv->channelState = RDPEI_OPENED;
133 break;
134 case RDPEI_OPENED:
135 error = rdpei_server_handle_messages(context);
136 break;
137 default:
138 break;
139 }
140
141 return error;
142}
143
144static HANDLE rdpei_server_get_channel_handle(RdpeiServerContext* context)
145{
146 RdpeiServerPrivate* priv = nullptr;
147 void* buffer = nullptr;
148 DWORD bytesReturned = 0;
149 HANDLE channelEvent = nullptr;
150
151 WINPR_ASSERT(context);
152 priv = context->priv;
153 WINPR_ASSERT(priv);
154
155 if (WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer,
156 &bytesReturned) == TRUE)
157 {
158 if (bytesReturned == sizeof(HANDLE))
159 channelEvent = *(HANDLE*)buffer;
160
161 WTSFreeMemory(buffer);
162 }
163
164 return channelEvent;
165}
166
167static DWORD WINAPI rdpei_server_thread_func(LPVOID arg)
168{
169 RdpeiServerContext* context = (RdpeiServerContext*)arg;
170 RdpeiServerPrivate* priv = nullptr;
171 HANDLE events[2] = WINPR_C_ARRAY_INIT;
172 DWORD nCount = 0;
173 UINT error = CHANNEL_RC_OK;
174 DWORD status = 0;
175
176 WINPR_ASSERT(context);
177 priv = context->priv;
178 WINPR_ASSERT(priv);
179
180 events[nCount++] = priv->stopEvent;
181
182 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
183 {
184 switch (priv->channelState)
185 {
186 case RDPEI_INITIAL:
187 error = rdpei_server_context_poll_int(context);
188 if (error == CHANNEL_RC_OK)
189 {
190 events[1] = rdpei_server_get_channel_handle(context);
191 nCount = 2;
192 }
193 break;
194 case RDPEI_OPENED:
195 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
196 switch (status)
197 {
198 case WAIT_OBJECT_0:
199 break;
200 case WAIT_OBJECT_0 + 1:
201 case WAIT_TIMEOUT:
202 error = rdpei_server_context_poll_int(context);
203 break;
204
205 case WAIT_FAILED:
206 default:
207 error = ERROR_INTERNAL_ERROR;
208 break;
209 }
210 break;
211 default:
212 break;
213 }
214 }
215
216 (void)WTSVirtualChannelClose(priv->channelHandle);
217 priv->channelHandle = nullptr;
218
219 ExitThread(error);
220 return error;
221}
222
223static UINT rdpei_server_open(RdpeiServerContext* context)
224{
225 RdpeiServerPrivate* priv = nullptr;
226
227 priv = context->priv;
228 WINPR_ASSERT(priv);
229
230 if (!priv->thread)
231 {
232 priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
233 if (!priv->stopEvent)
234 {
235 WLog_ERR(TAG, "CreateEvent failed!");
236 return ERROR_INTERNAL_ERROR;
237 }
238
239 priv->thread = CreateThread(nullptr, 0, rdpei_server_thread_func, context, 0, nullptr);
240 if (!priv->thread)
241 {
242 WLog_ERR(TAG, "CreateThread failed!");
243 (void)CloseHandle(priv->stopEvent);
244 priv->stopEvent = nullptr;
245 return ERROR_INTERNAL_ERROR;
246 }
247 }
248
249 return CHANNEL_RC_OK;
250}
251
252static UINT rdpei_server_close(RdpeiServerContext* context)
253{
254 RdpeiServerPrivate* priv = nullptr;
255 UINT error = CHANNEL_RC_OK;
256
257 priv = context->priv;
258 WINPR_ASSERT(priv);
259
260 if (priv->thread)
261 {
262 (void)SetEvent(priv->stopEvent);
263
264 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
265 {
266 error = GetLastError();
267 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
268 return error;
269 }
270
271 (void)CloseHandle(priv->thread);
272 (void)CloseHandle(priv->stopEvent);
273 priv->thread = nullptr;
274 priv->stopEvent = nullptr;
275 }
276
277 return error;
278}
279
280RdpeiServerContext* rdpei_server_context_new(HANDLE vcm)
281{
282 RdpeiServerContext* ret = calloc(1, sizeof(*ret));
283
284 if (!ret)
285 return nullptr;
286
287 ret->Open = rdpei_server_open;
288 ret->Close = rdpei_server_close;
289
290 ret->priv = calloc(1, sizeof(*ret->priv));
291 if (!ret->priv)
292 goto fail;
293
294 ret->priv->inputStream = Stream_New(nullptr, 256);
295 if (!ret->priv->inputStream)
296 goto fail;
297
298 ret->priv->outputStream = Stream_New(nullptr, 200);
299 if (!ret->priv->outputStream)
300 goto fail;
301
302 ret->vcm = vcm;
303 rdpei_server_context_reset(ret);
304 return ret;
305
306fail:
307 WINPR_PRAGMA_DIAG_PUSH
308 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
309 rdpei_server_context_free(ret);
310 WINPR_PRAGMA_DIAG_POP
311 return nullptr;
312}
313
319UINT rdpei_server_init(RdpeiServerContext* context)
320{
321 RdpeiServerPrivate* priv = context->priv;
322 UINT error = rdpei_server_open_channel(context);
323 if (error)
324 return error;
325
326 priv->eventHandle = rdpei_server_get_channel_handle(context);
327 if (!priv->eventHandle)
328 {
329 WLog_ERR(TAG, "Failed to get channel handle!");
330 goto out_close;
331 }
332
333 return CHANNEL_RC_OK;
334
335out_close:
336 (void)WTSVirtualChannelClose(priv->channelHandle);
337 return CHANNEL_RC_INITIALIZATION_ERROR;
338}
339
340void rdpei_server_context_reset(RdpeiServerContext* context)
341{
342 RdpeiServerPrivate* priv = context->priv;
343
344 priv->channelHandle = INVALID_HANDLE_VALUE;
345 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
346 priv->waitingHeaders = TRUE;
347 priv->automataState = STATE_INITIAL;
348 Stream_ResetPosition(priv->inputStream);
349}
350
351void rdpei_server_context_free(RdpeiServerContext* context)
352{
353 if (!context)
354 return;
355 RdpeiServerPrivate* priv = context->priv;
356 if (priv)
357 {
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);
362 }
363 free(priv);
364 free(context);
365}
366
367HANDLE rdpei_server_get_event_handle(RdpeiServerContext* context)
368{
369 return context->priv->eventHandle;
370}
371
377static UINT read_cs_ready_message(RdpeiServerContext* context, wStream* s)
378{
379 UINT error = CHANNEL_RC_OK;
380 if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
381 return ERROR_INVALID_DATA;
382
383 Stream_Read_UINT32(s, context->protocolFlags);
384 Stream_Read_UINT32(s, context->clientVersion);
385 Stream_Read_UINT16(s, context->maxTouchPoints);
386
387 switch (context->clientVersion)
388 {
389 case RDPINPUT_PROTOCOL_V10:
390 case RDPINPUT_PROTOCOL_V101:
391 case RDPINPUT_PROTOCOL_V200:
392 case RDPINPUT_PROTOCOL_V300:
393 break;
394 default:
395 WLog_ERR(TAG, "unhandled RPDEI protocol version 0x%" PRIx32 "", context->clientVersion);
396 break;
397 }
398
399 IFCALLRET(context->onClientReady, error, context);
400 if (error)
401 WLog_ERR(TAG, "context->onClientReady failed with error %" PRIu32 "", error);
402
403 return error;
404}
405
411static UINT read_touch_contact_data(RdpeiServerContext* context, wStream* s,
412 RDPINPUT_CONTACT_DATA* contactData)
413{
414 WINPR_UNUSED(context);
415 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
416 return ERROR_INVALID_DATA;
417
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))
423 {
424 WLog_ERR(TAG, "rdpei_read_ failed!");
425 return ERROR_INTERNAL_ERROR;
426 }
427
428 if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
429 {
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))
434 {
435 WLog_ERR(TAG, "rdpei_read_ failed!");
436 return ERROR_INTERNAL_ERROR;
437 }
438 }
439
440 if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
441 !rdpei_read_4byte_unsigned(s, &contactData->orientation))
442 {
443 WLog_ERR(TAG, "rdpei_read_ failed!");
444 return ERROR_INTERNAL_ERROR;
445 }
446
447 if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
448 !rdpei_read_4byte_unsigned(s, &contactData->pressure))
449 {
450 WLog_ERR(TAG, "rdpei_read_ failed!");
451 return ERROR_INTERNAL_ERROR;
452 }
453
454 return CHANNEL_RC_OK;
455}
456
457static UINT read_pen_contact(RdpeiServerContext* context, wStream* s,
458 RDPINPUT_PEN_CONTACT* contactData)
459{
460 WINPR_UNUSED(context);
461 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
462 return ERROR_INVALID_DATA;
463
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))
469 {
470 WLog_ERR(TAG, "rdpei_read_ failed!");
471 return ERROR_INTERNAL_ERROR;
472 }
473
474 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT)
475 {
476 if (!rdpei_read_4byte_unsigned(s, &contactData->penFlags))
477 return ERROR_INVALID_DATA;
478 }
479 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT)
480 {
481 if (!rdpei_read_4byte_unsigned(s, &contactData->pressure))
482 return ERROR_INVALID_DATA;
483 }
484 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_ROTATION_PRESENT)
485 {
486 if (!rdpei_read_2byte_unsigned(s, &contactData->rotation))
487 return ERROR_INVALID_DATA;
488 }
489 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTX_PRESENT)
490 {
491 if (!rdpei_read_2byte_signed(s, &contactData->tiltX))
492 return ERROR_INVALID_DATA;
493 }
494 if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTY_PRESENT)
495 {
496 if (!rdpei_read_2byte_signed(s, &contactData->tiltY))
497 return ERROR_INVALID_DATA;
498 }
499
500 return CHANNEL_RC_OK;
501}
502
508static UINT read_touch_frame(RdpeiServerContext* context, wStream* s, RDPINPUT_TOUCH_FRAME* frame)
509{
510 RDPINPUT_CONTACT_DATA* contact = nullptr;
511 UINT error = 0;
512
513 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
514 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
515 {
516 WLog_ERR(TAG, "rdpei_read_ failed!");
517 return ERROR_INTERNAL_ERROR;
518 }
519
520 frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_CONTACT_DATA));
521 if (!frame->contacts)
522 {
523 WLog_ERR(TAG, "calloc failed!");
524 return CHANNEL_RC_NO_MEMORY;
525 }
526
527 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
528 {
529 if ((error = read_touch_contact_data(context, s, contact)))
530 {
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);
534 return error;
535 }
536 }
537 return CHANNEL_RC_OK;
538}
539
540static UINT read_pen_frame(RdpeiServerContext* context, wStream* s, RDPINPUT_PEN_FRAME* frame)
541{
542 RDPINPUT_PEN_CONTACT* contact = nullptr;
543 UINT error = 0;
544
545 if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
546 !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
547 {
548 WLog_ERR(TAG, "rdpei_read_ failed!");
549 return ERROR_INTERNAL_ERROR;
550 }
551
552 frame->contacts = contact = calloc(frame->contactCount, sizeof(RDPINPUT_PEN_CONTACT));
553 if (!frame->contacts)
554 {
555 WLog_ERR(TAG, "calloc failed!");
556 return CHANNEL_RC_NO_MEMORY;
557 }
558
559 for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
560 {
561 if ((error = read_pen_contact(context, s, contact)))
562 {
563 WLog_ERR(TAG, "read_touch_contact_data failed with error %" PRIu32 "!", error);
564 frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
565
566 pen_frame_reset(frame);
567 return error;
568 }
569 }
570 return CHANNEL_RC_OK;
571}
572
578static UINT read_touch_event(RdpeiServerContext* context, wStream* s)
579{
580 UINT16 frameCount = 0;
581
582 WINPR_ASSERT(context);
583 WINPR_ASSERT(context->priv);
584
585 RDPINPUT_TOUCH_EVENT* event = &context->priv->touchEvent;
586 WINPR_ASSERT(event);
587
588 RDPINPUT_TOUCH_FRAME* frame = nullptr;
589 UINT error = CHANNEL_RC_OK;
590
591 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
592 !rdpei_read_2byte_unsigned(s, &frameCount))
593 {
594 WLog_ERR(TAG, "rdpei_read_ failed!");
595 return ERROR_INTERNAL_ERROR;
596 }
597
598 event->frameCount = frameCount;
599 event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_TOUCH_FRAME));
600 if (!event->frames)
601 {
602 WLog_ERR(TAG, "calloc failed!");
603 return CHANNEL_RC_NO_MEMORY;
604 }
605
606 for (UINT32 i = 0; i < frameCount; i++, frame++)
607 {
608 if ((error = read_touch_frame(context, s, frame)))
609 {
610 WLog_ERR(TAG, "read_touch_contact_data failed with error %" PRIu32 "!", error);
611 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
612
613 goto out_cleanup;
614 }
615 }
616
617 IFCALLRET(context->onTouchEvent, error, context, event);
618 if (error)
619 WLog_ERR(TAG, "context->onTouchEvent failed with error %" PRIu32 "", error);
620
621out_cleanup:
622 touch_event_reset(event);
623 return error;
624}
625
626static UINT read_pen_event(RdpeiServerContext* context, wStream* s)
627{
628 UINT16 frameCount = 0;
629 RDPINPUT_PEN_EVENT* event = &context->priv->penEvent;
630 RDPINPUT_PEN_FRAME* frame = nullptr;
631 UINT error = CHANNEL_RC_OK;
632
633 if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
634 !rdpei_read_2byte_unsigned(s, &frameCount))
635 {
636 WLog_ERR(TAG, "rdpei_read_ failed!");
637 return ERROR_INTERNAL_ERROR;
638 }
639
640 event->frameCount = frameCount;
641 event->frames = frame = calloc(event->frameCount, sizeof(RDPINPUT_PEN_FRAME));
642 if (!event->frames)
643 {
644 WLog_ERR(TAG, "calloc failed!");
645 return CHANNEL_RC_NO_MEMORY;
646 }
647
648 for (UINT32 i = 0; i < frameCount; i++, frame++)
649 {
650 if ((error = read_pen_frame(context, s, frame)))
651 {
652 WLog_ERR(TAG, "read_pen_frame failed with error %" PRIu32 "!", error);
653 event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
654
655 goto out_cleanup;
656 }
657 }
658
659 IFCALLRET(context->onPenEvent, error, context, event);
660 if (error)
661 WLog_ERR(TAG, "context->onPenEvent failed with error %" PRIu32 "", error);
662
663out_cleanup:
664 pen_event_reset(event);
665 return error;
666}
667
673static UINT read_dismiss_hovering_contact(RdpeiServerContext* context, wStream* s)
674{
675 BYTE contactId = 0;
676 UINT error = CHANNEL_RC_OK;
677
678 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
679 return ERROR_INVALID_DATA;
680
681 Stream_Read_UINT8(s, contactId);
682
683 IFCALLRET(context->onTouchReleased, error, context, contactId);
684 if (error)
685 WLog_ERR(TAG, "context->onTouchReleased failed with error %" PRIu32 "", error);
686
687 return error;
688}
689
695UINT rdpei_server_handle_messages(RdpeiServerContext* context)
696{
697 DWORD bytesReturned = 0;
698
699 WINPR_ASSERT(context);
700
701 RdpeiServerPrivate* priv = context->priv;
702 WINPR_ASSERT(priv);
703
704 wStream* s = priv->inputStream;
705 UINT error = CHANNEL_RC_OK;
706
707 if (!WTSVirtualChannelRead(priv->channelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
708 &bytesReturned))
709 {
710 if (GetLastError() == ERROR_NO_DATA)
711 return ERROR_READ_FAULT;
712
713 WLog_DBG(TAG, "channel connection closed");
714 return CHANNEL_RC_OK;
715 }
716 priv->expectedBytes -= bytesReturned;
717 Stream_Seek(s, bytesReturned);
718
719 if (priv->expectedBytes)
720 return CHANNEL_RC_OK;
721
722 Stream_SealLength(s);
723 Stream_ResetPosition(s);
724
725 if (priv->waitingHeaders)
726 {
727 /* header case */
728 priv->currentMsgType = Stream_Get_UINT16(s);
729 const UINT32 pduLen = Stream_Get_UINT32(s);
730
731 if (pduLen < RDPINPUT_HEADER_LENGTH)
732 {
733 WLog_ERR(TAG, "invalid pduLength %" PRIu32 "", pduLen);
734 return ERROR_INVALID_DATA;
735 }
736
737 if (pduLen > RDPINPUT_MAX_PDU_LENGTH)
738 {
739 WLog_ERR(TAG, "invalid pduLength %" PRIu32 " > RDPINPUT_MAX_PDU_LENGTH(%llu)", pduLen,
740 RDPINPUT_MAX_PDU_LENGTH);
741 return ERROR_INVALID_DATA;
742 }
743
744 priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
745 priv->waitingHeaders = FALSE;
746 Stream_ResetPosition(s);
747 if (priv->expectedBytes)
748 {
749 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
750 {
751 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
752 return CHANNEL_RC_NO_MEMORY;
753 }
754 return CHANNEL_RC_OK;
755 }
756 }
757
758 /* when here we have the header + the body */
759 switch (priv->currentMsgType)
760 {
761 case EVENTID_CS_READY:
762 if (priv->automataState != STATE_WAITING_CLIENT_READY)
763 {
764 WLog_ERR(TAG, "not expecting a CS_READY packet in this state(%u)",
765 priv->automataState);
766 return ERROR_INVALID_STATE;
767 }
768
769 if ((error = read_cs_ready_message(context, s)))
770 {
771 WLog_ERR(TAG, "read_cs_ready_message failed with error %" PRIu32 "", error);
772 return error;
773 }
774 break;
775
776 case EVENTID_TOUCH:
777 if ((error = read_touch_event(context, s)))
778 {
779 WLog_ERR(TAG, "read_touch_event failed with error %" PRIu32 "", error);
780 return error;
781 }
782 break;
783 case EVENTID_DISMISS_HOVERING_CONTACT:
784 if ((error = read_dismiss_hovering_contact(context, s)))
785 {
786 WLog_ERR(TAG, "read_dismiss_hovering_contact failed with error %" PRIu32 "", error);
787 return error;
788 }
789 break;
790 case EVENTID_PEN:
791 if ((error = read_pen_event(context, s)))
792 {
793 WLog_ERR(TAG, "read_pen_event failed with error %" PRIu32 "", error);
794 return error;
795 }
796 break;
797 default:
798 WLog_ERR(TAG, "unexpected message type 0x%" PRIx16 "", priv->currentMsgType);
799 }
800
801 Stream_ResetPosition(s);
802 priv->waitingHeaders = TRUE;
803 priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
804 return error;
805}
806
812UINT rdpei_server_send_sc_ready(RdpeiServerContext* context, UINT32 version, UINT32 features)
813{
814 ULONG written = 0;
815 RdpeiServerPrivate* priv = context->priv;
816 UINT32 pduLen = 4;
817
818 if (priv->automataState != STATE_INITIAL)
819 {
820 WLog_ERR(TAG, "called from unexpected state %u", priv->automataState);
821 return ERROR_INVALID_STATE;
822 }
823
824 Stream_ResetPosition(priv->outputStream);
825
826 if (version >= RDPINPUT_PROTOCOL_V300)
827 pduLen += 4;
828
829 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
830 {
831 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
832 return CHANNEL_RC_NO_MEMORY;
833 }
834
835 Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
836 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
837 Stream_Write_UINT32(priv->outputStream, version);
838 if (version >= RDPINPUT_PROTOCOL_V300)
839 Stream_Write_UINT32(priv->outputStream, features);
840
841 const size_t pos = Stream_GetPosition(priv->outputStream);
842
843 WINPR_ASSERT(pos <= UINT32_MAX);
844 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, char),
845 (ULONG)pos, &written))
846 {
847 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
848 return ERROR_INTERNAL_ERROR;
849 }
850
851 priv->automataState = STATE_WAITING_CLIENT_READY;
852 return CHANNEL_RC_OK;
853}
854
860UINT rdpei_server_suspend(RdpeiServerContext* context)
861{
862 ULONG written = 0;
863 RdpeiServerPrivate* priv = context->priv;
864
865 switch (priv->automataState)
866 {
867 case STATE_SUSPENDED:
868 WLog_ERR(TAG, "already suspended");
869 return CHANNEL_RC_OK;
870 case STATE_WAITING_FRAME:
871 break;
872 default:
873 WLog_ERR(TAG, "called from unexpected state %u", priv->automataState);
874 return ERROR_INVALID_STATE;
875 }
876
877 Stream_ResetPosition(priv->outputStream);
878 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
879 {
880 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
881 return CHANNEL_RC_NO_MEMORY;
882 }
883
884 Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
885 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
886
887 const size_t pos = Stream_GetPosition(priv->outputStream);
888
889 WINPR_ASSERT(pos <= UINT32_MAX);
890 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, char),
891 (ULONG)pos, &written))
892 {
893 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
894 return ERROR_INTERNAL_ERROR;
895 }
896
897 priv->automataState = STATE_SUSPENDED;
898 return CHANNEL_RC_OK;
899}
900
906UINT rdpei_server_resume(RdpeiServerContext* context)
907{
908 ULONG written = 0;
909 RdpeiServerPrivate* priv = context->priv;
910
911 switch (priv->automataState)
912 {
913 case STATE_WAITING_FRAME:
914 WLog_ERR(TAG, "not suspended");
915 return CHANNEL_RC_OK;
916 case STATE_SUSPENDED:
917 break;
918 default:
919 WLog_ERR(TAG, "called from unexpected state %u", priv->automataState);
920 return ERROR_INVALID_STATE;
921 }
922
923 Stream_ResetPosition(priv->outputStream);
924 if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
925 {
926 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
927 return CHANNEL_RC_NO_MEMORY;
928 }
929
930 Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
931 Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
932
933 const size_t pos = Stream_GetPosition(priv->outputStream);
934
935 WINPR_ASSERT(pos <= UINT32_MAX);
936 if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, char),
937 (ULONG)pos, &written))
938 {
939 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
940 return ERROR_INTERNAL_ERROR;
941 }
942
943 priv->automataState = STATE_WAITING_FRAME;
944 return CHANNEL_RC_OK;
945}
a touch event with some frames
a touch event with some frames
a frame containing contact points