21#include <winpr/assert.h> 
   23#include <winpr/file.h> 
   24#include <winpr/pipe.h> 
   25#include <winpr/thread.h> 
   27#include <freerdp/freerdp.h> 
   28#include <freerdp/svc.h> 
   29#include <freerdp/channels/rdp2tcp.h> 
   31#include <freerdp/log.h> 
   32#define TAG CLIENT_TAG(RDP2TCP_DVC_CHANNEL_NAME) 
   36  HANDLE hStdOutputRead;
 
   37  HANDLE hStdInputWrite;
 
   44  char buffer[16 * 1024];
 
   48static int init_external_addin(Plugin* plugin)
 
   58  saAttr.bInheritHandle = TRUE;
 
   59  saAttr.lpSecurityDescriptor = NULL;
 
   61  siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 
   62  siStartInfo.dwFlags = STARTF_USESTDHANDLES;
 
   65  if (!CreatePipe(&plugin->hStdOutputRead, &siStartInfo.hStdOutput, &saAttr, 0))
 
   67    WLog_ERR(TAG, 
"stdout CreatePipe");
 
   71  if (!SetHandleInformation(plugin->hStdOutputRead, HANDLE_FLAG_INHERIT, 0))
 
   73    WLog_ERR(TAG, 
"stdout SetHandleInformation");
 
   77  if (!CreatePipe(&siStartInfo.hStdInput, &plugin->hStdInputWrite, &saAttr, 0))
 
   79    WLog_ERR(TAG, 
"stdin CreatePipe");
 
   83  if (!SetHandleInformation(plugin->hStdInputWrite, HANDLE_FLAG_INHERIT, 0))
 
   85    WLog_ERR(TAG, 
"stdin SetHandleInformation");
 
   91  if (!args || (args->argc < 2))
 
   93    WLog_ERR(TAG, 
"missing command line options");
 
   97  plugin->commandline = _strdup(args->argv[1]);
 
   98  if (!CreateProcessA(NULL,
 
  110    WLog_ERR(TAG, 
"fork for addin");
 
  114  plugin->hProcess = procInfo.hProcess;
 
  118  (void)CloseHandle(procInfo.hThread);
 
  119  (void)CloseHandle(siStartInfo.hStdOutput);
 
  120  (void)CloseHandle(siStartInfo.hStdInput);
 
  124static DWORD WINAPI copyThread(
void* data)
 
  126  DWORD status = WAIT_OBJECT_0;
 
  127  Plugin* plugin = (Plugin*)data;
 
  128  size_t const bufsize = 16ULL * 1024ULL;
 
  130  WINPR_ASSERT(plugin);
 
  132  while (status == WAIT_OBJECT_0)
 
  134    (void)ResetEvent(plugin->writeComplete);
 
  137    char* buffer = calloc(bufsize, 
sizeof(
char));
 
  141      (void)fprintf(stderr, 
"rdp2tcp copyThread: malloc failed\n");
 
  147    if (!ReadFile(plugin->hStdOutputRead, buffer, bufsize, &dwRead, NULL))
 
  153    if (plugin->channelEntryPoints.pVirtualChannelWriteEx(
 
  154            plugin->initHandle, plugin->openHandle, buffer, dwRead, buffer) != CHANNEL_RC_OK)
 
  157      (void)fprintf(stderr, 
"rdp2tcp copyThread failed %i\n", (
int)dwRead);
 
  161    HANDLE handles[] = { plugin->writeComplete,
 
  162                       freerdp_abort_event(plugin->channelEntryPoints.context) };
 
  163    status = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, INFINITE);
 
  171static void closeChannel(Plugin* plugin)
 
  173  WINPR_ASSERT(plugin);
 
  174  WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelCloseEx);
 
  175  plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle);
 
  178static void dataReceived(Plugin* plugin, 
void* pData, UINT32 dataLength, UINT32 totalLength,
 
  183  WINPR_ASSERT(plugin);
 
  185  if (dataFlags & CHANNEL_FLAG_SUSPEND)
 
  188  if (dataFlags & CHANNEL_FLAG_RESUME)
 
  191  if (dataFlags & CHANNEL_FLAG_FIRST)
 
  193    if (!WriteFile(plugin->hStdInputWrite, &totalLength, 
sizeof(totalLength), &dwWritten, NULL))
 
  194      closeChannel(plugin);
 
  197  if (!WriteFile(plugin->hStdInputWrite, pData, dataLength, &dwWritten, NULL))
 
  198    closeChannel(plugin);
 
  201static void VCAPITYPE VirtualChannelOpenEventEx(LPVOID lpUserParam,
 
  202                                                WINPR_ATTR_UNUSED DWORD openHandle, UINT event,
 
  203                                                LPVOID pData, UINT32 dataLength, UINT32 totalLength,
 
  206  Plugin* plugin = (Plugin*)lpUserParam;
 
  208  WINPR_ASSERT(plugin);
 
  211    case CHANNEL_EVENT_DATA_RECEIVED:
 
  212      dataReceived(plugin, pData, dataLength, totalLength, dataFlags);
 
  215    case CHANNEL_EVENT_WRITE_CANCELLED:
 
  218    case CHANNEL_EVENT_WRITE_COMPLETE:
 
  219      (void)SetEvent(plugin->writeComplete);
 
  227static void channel_terminated(Plugin* plugin)
 
  232  if (plugin->copyThread)
 
  233    (void)CloseHandle(plugin->copyThread);
 
  234  if (plugin->writeComplete)
 
  235    (void)CloseHandle(plugin->writeComplete);
 
  237  (void)CloseHandle(plugin->hStdInputWrite);
 
  238  (void)CloseHandle(plugin->hStdOutputRead);
 
  239  TerminateProcess(plugin->hProcess, 0);
 
  240  (void)CloseHandle(plugin->hProcess);
 
  241  free(plugin->commandline);
 
  245static void channel_initialized(Plugin* plugin)
 
  247  WINPR_ASSERT(plugin);
 
  248  WINPR_ASSERT(!plugin->writeComplete);
 
  249  plugin->writeComplete = CreateEvent(NULL, TRUE, FALSE, NULL);
 
  251  WINPR_ASSERT(!plugin->copyThread);
 
  252  plugin->copyThread = CreateThread(NULL, 0, copyThread, plugin, 0, NULL);
 
  255static VOID VCAPITYPE VirtualChannelInitEventEx(LPVOID lpUserParam, LPVOID pInitHandle, UINT event,
 
  256                                                WINPR_ATTR_UNUSED LPVOID pData,
 
  257                                                WINPR_ATTR_UNUSED UINT dataLength)
 
  259  Plugin* plugin = (Plugin*)lpUserParam;
 
  261  WINPR_ASSERT(plugin);
 
  265    case CHANNEL_EVENT_INITIALIZED:
 
  266      channel_initialized(plugin);
 
  269    case CHANNEL_EVENT_CONNECTED:
 
  270      WINPR_ASSERT(plugin);
 
  271      WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelOpenEx);
 
  272      if (plugin->channelEntryPoints.pVirtualChannelOpenEx(
 
  273              pInitHandle, &plugin->openHandle, RDP2TCP_DVC_CHANNEL_NAME,
 
  274              VirtualChannelOpenEventEx) != CHANNEL_RC_OK)
 
  279    case CHANNEL_EVENT_DISCONNECTED:
 
  280      closeChannel(plugin);
 
  283    case CHANNEL_EVENT_TERMINATED:
 
  284      channel_terminated(plugin);
 
  291#define VirtualChannelEntryEx rdp2tcp_VirtualChannelEntryEx 
  292FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
 
  297  WINPR_ASSERT(pEntryPointsEx);
 
  299               pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER);
 
  301  Plugin* plugin = (Plugin*)calloc(1, 
sizeof(Plugin));
 
  306  plugin->initHandle = pInitHandle;
 
  307  plugin->channelEntryPoints = *pEntryPointsEx;
 
  309  if (init_external_addin(plugin) < 0)
 
  311    channel_terminated(plugin);
 
  316  strncpy(channelDef.name, RDP2TCP_DVC_CHANNEL_NAME, 
sizeof(channelDef.name));
 
  318      CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
 
  320  if (pEntryPointsEx->pVirtualChannelInitEx(plugin, NULL, pInitHandle, &channelDef, 1,
 
  321                                            VIRTUAL_CHANNEL_VERSION_WIN2000,
 
  322                                            VirtualChannelInitEventEx) != CHANNEL_RC_OK)
 
  324    channel_terminated(plugin);