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];
48 static int init_external_addin(Plugin* plugin)
57 saAttr.bInheritHandle = TRUE;
58 saAttr.lpSecurityDescriptor = NULL;
60 siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
61 siStartInfo.dwFlags = STARTF_USESTDHANDLES;
64 if (!CreatePipe(&plugin->hStdOutputRead, &siStartInfo.hStdOutput, &saAttr, 0))
66 WLog_ERR(TAG,
"stdout CreatePipe");
70 if (!SetHandleInformation(plugin->hStdOutputRead, HANDLE_FLAG_INHERIT, 0))
72 WLog_ERR(TAG,
"stdout SetHandleInformation");
76 if (!CreatePipe(&siStartInfo.hStdInput, &plugin->hStdInputWrite, &saAttr, 0))
78 WLog_ERR(TAG,
"stdin CreatePipe");
82 if (!SetHandleInformation(plugin->hStdInputWrite, HANDLE_FLAG_INHERIT, 0))
84 WLog_ERR(TAG,
"stdin SetHandleInformation");
89 plugin->commandline = _strdup(plugin->channelEntryPoints.pExtendedData);
90 if (!CreateProcessA(NULL,
102 WLog_ERR(TAG,
"fork for addin");
106 plugin->hProcess = procInfo.hProcess;
107 (void)CloseHandle(procInfo.hThread);
108 (void)CloseHandle(siStartInfo.hStdOutput);
109 (void)CloseHandle(siStartInfo.hStdInput);
113 static DWORD WINAPI copyThread(
void* data)
115 DWORD status = WAIT_OBJECT_0;
116 Plugin* plugin = (Plugin*)data;
117 size_t const bufsize = 16ULL * 1024ULL;
119 WINPR_ASSERT(plugin);
121 while (status == WAIT_OBJECT_0)
124 HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
126 char* buffer = calloc(bufsize,
sizeof(
char));
130 (void)fprintf(stderr,
"rdp2tcp copyThread: malloc failed\n");
136 if (!ReadFile(plugin->hStdOutputRead, buffer, bufsize, &dwRead, NULL))
142 if (plugin->channelEntryPoints.pVirtualChannelWriteEx(
143 plugin->initHandle, plugin->openHandle, buffer, dwRead, buffer) != CHANNEL_RC_OK)
146 (void)fprintf(stderr,
"rdp2tcp copyThread failed %i\n", (
int)dwRead);
150 handles[0] = plugin->writeComplete;
151 handles[1] = freerdp_abort_event(plugin->channelEntryPoints.context);
152 status = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
153 if (status == WAIT_OBJECT_0)
154 (void)ResetEvent(plugin->writeComplete);
162 static void closeChannel(Plugin* plugin)
164 WINPR_ASSERT(plugin);
165 WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelCloseEx);
166 plugin->channelEntryPoints.pVirtualChannelCloseEx(plugin->initHandle, plugin->openHandle);
169 static void dataReceived(Plugin* plugin,
void* pData, UINT32 dataLength, UINT32 totalLength,
174 WINPR_ASSERT(plugin);
176 if (dataFlags & CHANNEL_FLAG_SUSPEND)
179 if (dataFlags & CHANNEL_FLAG_RESUME)
182 if (dataFlags & CHANNEL_FLAG_FIRST)
184 if (!WriteFile(plugin->hStdInputWrite, &totalLength,
sizeof(totalLength), &dwWritten, NULL))
185 closeChannel(plugin);
188 if (!WriteFile(plugin->hStdInputWrite, pData, dataLength, &dwWritten, NULL))
189 closeChannel(plugin);
192 static void VCAPITYPE VirtualChannelOpenEventEx(LPVOID lpUserParam, DWORD openHandle, UINT event,
193 LPVOID pData, UINT32 dataLength, UINT32 totalLength,
196 Plugin* plugin = (Plugin*)lpUserParam;
198 WINPR_ASSERT(plugin);
201 case CHANNEL_EVENT_DATA_RECEIVED:
202 dataReceived(plugin, pData, dataLength, totalLength, dataFlags);
205 case CHANNEL_EVENT_WRITE_CANCELLED:
208 case CHANNEL_EVENT_WRITE_COMPLETE:
209 (void)SetEvent(plugin->writeComplete);
217 static void channel_terminated(Plugin* plugin)
222 if (plugin->copyThread)
223 (void)TerminateThread(plugin->copyThread, 0);
224 if (plugin->writeComplete)
225 (void)CloseHandle(plugin->writeComplete);
227 (void)CloseHandle(plugin->hStdInputWrite);
228 (void)CloseHandle(plugin->hStdOutputRead);
229 TerminateProcess(plugin->hProcess, 0);
230 (void)CloseHandle(plugin->hProcess);
231 free(plugin->commandline);
235 static void channel_initialized(Plugin* plugin)
237 WINPR_ASSERT(plugin);
238 plugin->writeComplete = CreateEvent(NULL, TRUE, FALSE, NULL);
239 plugin->copyThread = CreateThread(NULL, 0, copyThread, plugin, 0, NULL);
242 static VOID VCAPITYPE VirtualChannelInitEventEx(LPVOID lpUserParam, LPVOID pInitHandle, UINT event,
243 LPVOID pData, UINT dataLength)
245 Plugin* plugin = (Plugin*)lpUserParam;
247 WINPR_ASSERT(plugin);
251 case CHANNEL_EVENT_INITIALIZED:
252 channel_initialized(plugin);
255 case CHANNEL_EVENT_CONNECTED:
256 WINPR_ASSERT(plugin);
257 WINPR_ASSERT(plugin->channelEntryPoints.pVirtualChannelOpenEx);
258 if (plugin->channelEntryPoints.pVirtualChannelOpenEx(
259 pInitHandle, &plugin->openHandle, RDP2TCP_DVC_CHANNEL_NAME,
260 VirtualChannelOpenEventEx) != CHANNEL_RC_OK)
265 case CHANNEL_EVENT_DISCONNECTED:
268 case CHANNEL_EVENT_TERMINATED:
269 channel_terminated(plugin);
276 #define VirtualChannelEntryEx rdp2tcp_VirtualChannelEntryEx
277 FREERDP_ENTRY_POINT(BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
282 WINPR_ASSERT(pEntryPointsEx);
284 pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER);
286 Plugin* plugin = (Plugin*)calloc(1,
sizeof(Plugin));
291 plugin->initHandle = pInitHandle;
292 plugin->channelEntryPoints = *pEntryPointsEx;
294 if (init_external_addin(plugin) < 0)
301 strncpy(channelDef.name, RDP2TCP_DVC_CHANNEL_NAME,
sizeof(channelDef.name));
303 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP;
305 if (pEntryPointsEx->pVirtualChannelInitEx(plugin, NULL, pInitHandle, &channelDef, 1,
306 VIRTUAL_CHANNEL_VERSION_WIN2000,
307 VirtualChannelInitEventEx) != CHANNEL_RC_OK)