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->inputStream)
 
  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)
 
  353  RdpeiServerPrivate* priv = NULL;
 
  357  priv = context->priv;
 
  360    if (priv->channelHandle && priv->channelHandle != INVALID_HANDLE_VALUE)
 
  361      (void)WTSVirtualChannelClose(priv->channelHandle);
 
  362    Stream_Free(priv->inputStream, TRUE);
 
  368HANDLE rdpei_server_get_event_handle(RdpeiServerContext* context)
 
  370  return context->priv->eventHandle;
 
  378static UINT read_cs_ready_message(RdpeiServerContext* context, 
wStream* s)
 
  380  UINT error = CHANNEL_RC_OK;
 
  381  if (!Stream_CheckAndLogRequiredLength(TAG, s, 10))
 
  382    return ERROR_INVALID_DATA;
 
  384  Stream_Read_UINT32(s, context->protocolFlags);
 
  385  Stream_Read_UINT32(s, context->clientVersion);
 
  386  Stream_Read_UINT16(s, context->maxTouchPoints);
 
  388  switch (context->clientVersion)
 
  390    case RDPINPUT_PROTOCOL_V10:
 
  391    case RDPINPUT_PROTOCOL_V101:
 
  392    case RDPINPUT_PROTOCOL_V200:
 
  393    case RDPINPUT_PROTOCOL_V300:
 
  396      WLog_ERR(TAG, 
"unhandled RPDEI protocol version 0x%" PRIx32 
"", context->clientVersion);
 
  400  IFCALLRET(context->onClientReady, error, context);
 
  402    WLog_ERR(TAG, 
"context->onClientReady failed with error %" PRIu32 
"", error);
 
  412static UINT read_touch_contact_data(RdpeiServerContext* context, 
wStream* s,
 
  415  WINPR_UNUSED(context);
 
  416  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  417    return ERROR_INVALID_DATA;
 
  419  Stream_Read_UINT8(s, contactData->contactId);
 
  420  if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
 
  421      !rdpei_read_4byte_signed(s, &contactData->x) ||
 
  422      !rdpei_read_4byte_signed(s, &contactData->y) ||
 
  423      !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
 
  425    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  426    return ERROR_INTERNAL_ERROR;
 
  429  if (contactData->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
 
  431    if (!rdpei_read_2byte_signed(s, &contactData->contactRectLeft) ||
 
  432        !rdpei_read_2byte_signed(s, &contactData->contactRectTop) ||
 
  433        !rdpei_read_2byte_signed(s, &contactData->contactRectRight) ||
 
  434        !rdpei_read_2byte_signed(s, &contactData->contactRectBottom))
 
  436      WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  437      return ERROR_INTERNAL_ERROR;
 
  441  if ((contactData->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT) &&
 
  442      !rdpei_read_4byte_unsigned(s, &contactData->orientation))
 
  444    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  445    return ERROR_INTERNAL_ERROR;
 
  448  if ((contactData->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT) &&
 
  449      !rdpei_read_4byte_unsigned(s, &contactData->pressure))
 
  451    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  452    return ERROR_INTERNAL_ERROR;
 
  455  return CHANNEL_RC_OK;
 
  458static UINT read_pen_contact(RdpeiServerContext* context, 
wStream* s,
 
  461  WINPR_UNUSED(context);
 
  462  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  463    return ERROR_INVALID_DATA;
 
  465  Stream_Read_UINT8(s, contactData->deviceId);
 
  466  if (!rdpei_read_2byte_unsigned(s, &contactData->fieldsPresent) ||
 
  467      !rdpei_read_4byte_signed(s, &contactData->x) ||
 
  468      !rdpei_read_4byte_signed(s, &contactData->y) ||
 
  469      !rdpei_read_4byte_unsigned(s, &contactData->contactFlags))
 
  471    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  472    return ERROR_INTERNAL_ERROR;
 
  475  if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT)
 
  477    if (!rdpei_read_4byte_unsigned(s, &contactData->penFlags))
 
  478      return ERROR_INVALID_DATA;
 
  480  if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT)
 
  482    if (!rdpei_read_4byte_unsigned(s, &contactData->pressure))
 
  483      return ERROR_INVALID_DATA;
 
  485  if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_ROTATION_PRESENT)
 
  487    if (!rdpei_read_2byte_unsigned(s, &contactData->rotation))
 
  488      return ERROR_INVALID_DATA;
 
  490  if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTX_PRESENT)
 
  492    if (!rdpei_read_2byte_signed(s, &contactData->tiltX))
 
  493      return ERROR_INVALID_DATA;
 
  495  if (contactData->fieldsPresent & RDPINPUT_PEN_CONTACT_TILTY_PRESENT)
 
  497    if (!rdpei_read_2byte_signed(s, &contactData->tiltY))
 
  498      return ERROR_INVALID_DATA;
 
  501  return CHANNEL_RC_OK;
 
  514  if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
 
  515      !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
 
  517    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  518    return ERROR_INTERNAL_ERROR;
 
  522  if (!frame->contacts)
 
  524    WLog_ERR(TAG, 
"calloc failed!");
 
  525    return CHANNEL_RC_NO_MEMORY;
 
  528  for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
 
  530    if ((error = read_touch_contact_data(context, s, contact)))
 
  532      WLog_ERR(TAG, 
"read_touch_contact_data failed with error %" PRIu32 
"!", error);
 
  533      frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
 
  534      touch_frame_reset(frame);
 
  538  return CHANNEL_RC_OK;
 
  546  if (!rdpei_read_2byte_unsigned(s, &frame->contactCount) ||
 
  547      !rdpei_read_8byte_unsigned(s, &frame->frameOffset))
 
  549    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  550    return ERROR_INTERNAL_ERROR;
 
  554  if (!frame->contacts)
 
  556    WLog_ERR(TAG, 
"calloc failed!");
 
  557    return CHANNEL_RC_NO_MEMORY;
 
  560  for (UINT32 i = 0; i < frame->contactCount; i++, contact++)
 
  562    if ((error = read_pen_contact(context, s, contact)))
 
  564      WLog_ERR(TAG, 
"read_touch_contact_data failed with error %" PRIu32 
"!", error);
 
  565      frame->contactCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
 
  567      pen_frame_reset(frame);
 
  571  return CHANNEL_RC_OK;
 
  579static UINT read_touch_event(RdpeiServerContext* context, 
wStream* s)
 
  581  UINT16 frameCount = 0;
 
  584  UINT error = CHANNEL_RC_OK;
 
  586  if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
 
  587      !rdpei_read_2byte_unsigned(s, &frameCount))
 
  589    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  590    return ERROR_INTERNAL_ERROR;
 
  593  event->frameCount = frameCount;
 
  597    WLog_ERR(TAG, 
"calloc failed!");
 
  598    return CHANNEL_RC_NO_MEMORY;
 
  601  for (UINT32 i = 0; i < frameCount; i++, frame++)
 
  603    if ((error = read_touch_frame(context, s, frame)))
 
  605      WLog_ERR(TAG, 
"read_touch_contact_data failed with error %" PRIu32 
"!", error);
 
  606      event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
 
  612  IFCALLRET(context->onTouchEvent, error, context, event);
 
  614    WLog_ERR(TAG, 
"context->onTouchEvent failed with error %" PRIu32 
"", error);
 
  617  touch_event_reset(event);
 
  621static UINT read_pen_event(RdpeiServerContext* context, 
wStream* s)
 
  623  UINT16 frameCount = 0;
 
  626  UINT error = CHANNEL_RC_OK;
 
  628  if (!rdpei_read_4byte_unsigned(s, &event->encodeTime) ||
 
  629      !rdpei_read_2byte_unsigned(s, &frameCount))
 
  631    WLog_ERR(TAG, 
"rdpei_read_ failed!");
 
  632    return ERROR_INTERNAL_ERROR;
 
  635  event->frameCount = frameCount;
 
  639    WLog_ERR(TAG, 
"calloc failed!");
 
  640    return CHANNEL_RC_NO_MEMORY;
 
  643  for (UINT32 i = 0; i < frameCount; i++, frame++)
 
  645    if ((error = read_pen_frame(context, s, frame)))
 
  647      WLog_ERR(TAG, 
"read_pen_frame failed with error %" PRIu32 
"!", error);
 
  648      event->frameCount = WINPR_ASSERTING_INT_CAST(UINT16, i);
 
  654  IFCALLRET(context->onPenEvent, error, context, event);
 
  656    WLog_ERR(TAG, 
"context->onPenEvent failed with error %" PRIu32 
"", error);
 
  659  pen_event_reset(event);
 
  668static UINT read_dismiss_hovering_contact(RdpeiServerContext* context, 
wStream* s)
 
  671  UINT error = CHANNEL_RC_OK;
 
  673  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
 
  674    return ERROR_INVALID_DATA;
 
  676  Stream_Read_UINT8(s, contactId);
 
  678  IFCALLRET(context->onTouchReleased, error, context, contactId);
 
  680    WLog_ERR(TAG, 
"context->onTouchReleased failed with error %" PRIu32 
"", error);
 
  690UINT rdpei_server_handle_messages(RdpeiServerContext* context)
 
  692  DWORD bytesReturned = 0;
 
  693  RdpeiServerPrivate* priv = context->priv;
 
  694  wStream* s = priv->inputStream;
 
  695  UINT error = CHANNEL_RC_OK;
 
  697  if (!WTSVirtualChannelRead(priv->channelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
 
  700    if (GetLastError() == ERROR_NO_DATA)
 
  701      return ERROR_READ_FAULT;
 
  703    WLog_DBG(TAG, 
"channel connection closed");
 
  704    return CHANNEL_RC_OK;
 
  706  priv->expectedBytes -= bytesReturned;
 
  707  Stream_Seek(s, bytesReturned);
 
  709  if (priv->expectedBytes)
 
  710    return CHANNEL_RC_OK;
 
  712  Stream_SealLength(s);
 
  713  Stream_SetPosition(s, 0);
 
  715  if (priv->waitingHeaders)
 
  720    Stream_Read_UINT16(s, priv->currentMsgType);
 
  721    Stream_Read_UINT32(s, pduLen);
 
  723    if (pduLen < RDPINPUT_HEADER_LENGTH)
 
  725      WLog_ERR(TAG, 
"invalid pduLength %" PRIu32 
"", pduLen);
 
  726      return ERROR_INVALID_DATA;
 
  728    priv->expectedBytes = pduLen - RDPINPUT_HEADER_LENGTH;
 
  729    priv->waitingHeaders = FALSE;
 
  730    Stream_SetPosition(s, 0);
 
  731    if (priv->expectedBytes)
 
  733      if (!Stream_EnsureCapacity(s, priv->expectedBytes))
 
  735        WLog_ERR(TAG, 
"Stream_EnsureCapacity failed!");
 
  736        return CHANNEL_RC_NO_MEMORY;
 
  738      return CHANNEL_RC_OK;
 
  743  switch (priv->currentMsgType)
 
  745    case EVENTID_CS_READY:
 
  746      if (priv->automataState != STATE_WAITING_CLIENT_READY)
 
  748        WLog_ERR(TAG, 
"not expecting a CS_READY packet in this state(%d)",
 
  749                 priv->automataState);
 
  750        return ERROR_INVALID_STATE;
 
  753      if ((error = read_cs_ready_message(context, s)))
 
  755        WLog_ERR(TAG, 
"read_cs_ready_message failed with error %" PRIu32 
"", error);
 
  761      if ((error = read_touch_event(context, s)))
 
  763        WLog_ERR(TAG, 
"read_touch_event failed with error %" PRIu32 
"", error);
 
  767    case EVENTID_DISMISS_HOVERING_CONTACT:
 
  768      if ((error = read_dismiss_hovering_contact(context, s)))
 
  770        WLog_ERR(TAG, 
"read_dismiss_hovering_contact failed with error %" PRIu32 
"", error);
 
  775      if ((error = read_pen_event(context, s)))
 
  777        WLog_ERR(TAG, 
"read_pen_event failed with error %" PRIu32 
"", error);
 
  782      WLog_ERR(TAG, 
"unexpected message type 0x%" PRIx16 
"", priv->currentMsgType);
 
  785  Stream_SetPosition(s, 0);
 
  786  priv->waitingHeaders = TRUE;
 
  787  priv->expectedBytes = RDPINPUT_HEADER_LENGTH;
 
  796UINT rdpei_server_send_sc_ready(RdpeiServerContext* context, UINT32 version, UINT32 features)
 
  799  RdpeiServerPrivate* priv = context->priv;
 
  802  if (priv->automataState != STATE_INITIAL)
 
  804    WLog_ERR(TAG, 
"called from unexpected state %d", priv->automataState);
 
  805    return ERROR_INVALID_STATE;
 
  808  Stream_SetPosition(priv->outputStream, 0);
 
  810  if (version >= RDPINPUT_PROTOCOL_V300)
 
  813  if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
 
  815    WLog_ERR(TAG, 
"Stream_EnsureCapacity failed!");
 
  816    return CHANNEL_RC_NO_MEMORY;
 
  819  Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
 
  820  Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
 
  821  Stream_Write_UINT32(priv->outputStream, version);
 
  822  if (version >= RDPINPUT_PROTOCOL_V300)
 
  823    Stream_Write_UINT32(priv->outputStream, features);
 
  825  const size_t pos = Stream_GetPosition(priv->outputStream);
 
  827  WINPR_ASSERT(pos <= UINT32_MAX);
 
  828  if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, 
char),
 
  829                              (ULONG)pos, &written))
 
  831    WLog_ERR(TAG, 
"WTSVirtualChannelWrite failed!");
 
  832    return ERROR_INTERNAL_ERROR;
 
  835  priv->automataState = STATE_WAITING_CLIENT_READY;
 
  836  return CHANNEL_RC_OK;
 
  844UINT rdpei_server_suspend(RdpeiServerContext* context)
 
  847  RdpeiServerPrivate* priv = context->priv;
 
  849  switch (priv->automataState)
 
  851    case STATE_SUSPENDED:
 
  852      WLog_ERR(TAG, 
"already suspended");
 
  853      return CHANNEL_RC_OK;
 
  854    case STATE_WAITING_FRAME:
 
  857      WLog_ERR(TAG, 
"called from unexpected state %d", priv->automataState);
 
  858      return ERROR_INVALID_STATE;
 
  861  Stream_SetPosition(priv->outputStream, 0);
 
  862  if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
 
  864    WLog_ERR(TAG, 
"Stream_EnsureCapacity failed!");
 
  865    return CHANNEL_RC_NO_MEMORY;
 
  868  Stream_Write_UINT16(priv->outputStream, EVENTID_SUSPEND_TOUCH);
 
  869  Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
 
  871  const size_t pos = Stream_GetPosition(priv->outputStream);
 
  873  WINPR_ASSERT(pos <= UINT32_MAX);
 
  874  if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, 
char),
 
  875                              (ULONG)pos, &written))
 
  877    WLog_ERR(TAG, 
"WTSVirtualChannelWrite failed!");
 
  878    return ERROR_INTERNAL_ERROR;
 
  881  priv->automataState = STATE_SUSPENDED;
 
  882  return CHANNEL_RC_OK;
 
  890UINT rdpei_server_resume(RdpeiServerContext* context)
 
  893  RdpeiServerPrivate* priv = context->priv;
 
  895  switch (priv->automataState)
 
  897    case STATE_WAITING_FRAME:
 
  898      WLog_ERR(TAG, 
"not suspended");
 
  899      return CHANNEL_RC_OK;
 
  900    case STATE_SUSPENDED:
 
  903      WLog_ERR(TAG, 
"called from unexpected state %d", priv->automataState);
 
  904      return ERROR_INVALID_STATE;
 
  907  Stream_SetPosition(priv->outputStream, 0);
 
  908  if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH))
 
  910    WLog_ERR(TAG, 
"Stream_EnsureCapacity failed!");
 
  911    return CHANNEL_RC_NO_MEMORY;
 
  914  Stream_Write_UINT16(priv->outputStream, EVENTID_RESUME_TOUCH);
 
  915  Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH);
 
  917  const size_t pos = Stream_GetPosition(priv->outputStream);
 
  919  WINPR_ASSERT(pos <= UINT32_MAX);
 
  920  if (!WTSVirtualChannelWrite(priv->channelHandle, Stream_BufferAs(priv->outputStream, 
char),
 
  921                              (ULONG)pos, &written))
 
  923    WLog_ERR(TAG, 
"WTSVirtualChannelWrite failed!");
 
  924    return ERROR_INTERNAL_ERROR;
 
  927  priv->automataState = STATE_WAITING_FRAME;
 
  928  return CHANNEL_RC_OK;