23#include <freerdp/config.h>
39#include <linux/ppdev.h>
40#include <linux/parport.h>
44#include <winpr/assert.h>
45#include <winpr/synch.h>
46#include <winpr/thread.h>
47#include <winpr/stream.h>
48#include <winpr/collections.h>
49#include <winpr/interlocked.h>
51#include <freerdp/types.h>
52#include <freerdp/freerdp.h>
53#include <freerdp/constants.h>
54#include <freerdp/channels/rdpdr.h>
55#include <freerdp/channels/log.h>
56#include <freerdp/utils/rdpdr_utils.h>
58#define TAG CHANNELS_TAG("drive.client")
70 rdpContext* rdpcontext;
79static UINT parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
82 UINT32 PathLength = 0;
84 WINPR_ASSERT(parallel);
87 if (!Stream_SafeSeek(irp->input, 28))
88 return ERROR_INVALID_DATA;
91 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 4))
92 return ERROR_INVALID_DATA;
93 Stream_Read_UINT32(irp->input, PathLength);
94 if (PathLength <
sizeof(WCHAR))
95 return ERROR_INVALID_DATA;
96 const WCHAR* ptr = Stream_ConstPointer(irp->input);
97 if (!Stream_SafeSeek(irp->input, PathLength))
98 return ERROR_INVALID_DATA;
99 path = ConvertWCharNToUtf8Alloc(ptr, PathLength /
sizeof(WCHAR), NULL);
101 return CHANNEL_RC_NO_MEMORY;
103 parallel->id = irp->devman->id_sequence++;
104 parallel->file = open(parallel->path, O_RDWR);
106 if (parallel->file < 0)
108 irp->IoStatus = STATUS_ACCESS_DENIED;
114 if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
119 Stream_Write_UINT32(irp->output, parallel->id);
120 Stream_Write_UINT8(irp->output, 0);
122 WINPR_ASSERT(irp->Complete);
123 return irp->Complete(irp);
131static UINT parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
133 WINPR_ASSERT(parallel);
136 (void)close(parallel->file);
138 Stream_Zero(irp->output, 5);
139 WINPR_ASSERT(irp->Complete);
140 return irp->Complete(irp);
148static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
155 WINPR_ASSERT(parallel);
158 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
159 return ERROR_INVALID_DATA;
160 Stream_Read_UINT32(irp->input, Length);
161 Stream_Read_UINT64(irp->input, Offset);
164 buffer = (BYTE*)calloc(Length,
sizeof(BYTE));
168 WLog_Print(parallel->log, WLOG_ERROR,
"malloc failed!");
169 return CHANNEL_RC_NO_MEMORY;
172 status = read(parallel->file, buffer, Length);
174 if ((status < 0) || (status > UINT32_MAX))
176 irp->IoStatus = STATUS_UNSUCCESSFUL;
183 Length = (UINT32)status;
186 Stream_Write_UINT32(irp->output, Length);
190 if (!Stream_EnsureRemainingCapacity(irp->output, Length))
192 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
194 return CHANNEL_RC_NO_MEMORY;
197 Stream_Write(irp->output, buffer, Length);
201 WINPR_ASSERT(irp->Complete);
202 return irp->Complete(irp);
210static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
216 WINPR_ASSERT(parallel);
219 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
220 return ERROR_INVALID_DATA;
222 Stream_Read_UINT32(irp->input, Length);
223 Stream_Read_UINT64(irp->input, Offset);
226 if (!Stream_SafeSeek(irp->input, 20))
227 return ERROR_INVALID_DATA;
228 const void* ptr = Stream_ConstPointer(irp->input);
229 if (!Stream_SafeSeek(irp->input, Length))
230 return ERROR_INVALID_DATA;
235 const ssize_t status = write(parallel->file, ptr, len);
237 if ((status < 0) || (status > len))
239 irp->IoStatus = STATUS_UNSUCCESSFUL;
244 Stream_Seek(irp->input, WINPR_ASSERTING_INT_CAST(
size_t, status));
248 Stream_Write_UINT32(irp->output, Length);
249 Stream_Write_UINT8(irp->output, 0);
250 WINPR_ASSERT(irp->Complete);
251 return irp->Complete(irp);
259static UINT parallel_process_irp_device_control(WINPR_ATTR_UNUSED PARALLEL_DEVICE* parallel,
262 WINPR_ASSERT(parallel);
265 Stream_Write_UINT32(irp->output, 0);
266 WINPR_ASSERT(irp->Complete);
267 return irp->Complete(irp);
275static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
277 UINT error = ERROR_INTERNAL_ERROR;
279 WINPR_ASSERT(parallel);
282 switch (irp->MajorFunction)
285 error = parallel_process_irp_create(parallel, irp);
289 error = parallel_process_irp_close(parallel, irp);
293 error = parallel_process_irp_read(parallel, irp);
297 error = parallel_process_irp_write(parallel, irp);
300 case IRP_MJ_DEVICE_CONTROL:
301 error = parallel_process_irp_device_control(parallel, irp);
305 irp->IoStatus = STATUS_NOT_SUPPORTED;
306 WINPR_ASSERT(irp->Complete);
307 error = irp->Complete(irp);
311 DWORD level = WLOG_TRACE;
315 WLog_Print(parallel->log, level,
316 "[%s|0x%08" PRIx32
"] completed with %s [0x%08" PRIx32
"] (IoStatus %s [0x%08" PRIx32
318 rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
319 error, NtStatus2Tag(irp->IoStatus), irp->IoStatus);
324static DWORD WINAPI parallel_thread_func(LPVOID arg)
326 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg;
327 UINT error = CHANNEL_RC_OK;
329 WINPR_ASSERT(parallel);
332 if (!MessageQueue_Wait(parallel->queue))
334 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Wait failed!");
335 error = ERROR_INTERNAL_ERROR;
339 wMessage message = { 0 };
340 if (!MessageQueue_Peek(parallel->queue, &message, TRUE))
342 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Peek failed!");
343 error = ERROR_INTERNAL_ERROR;
347 if (message.id == WMQ_QUIT)
350 IRP* irp = (IRP*)message.wParam;
352 error = parallel_process_irp(parallel, irp);
355 WLog_Print(parallel->log, WLOG_ERROR,
356 "parallel_process_irp failed with error %" PRIu32
"!", error);
361 if (error && parallel->rdpcontext)
362 setChannelError(parallel->rdpcontext, error,
"parallel_thread_func reported an error");
373static UINT parallel_irp_request(DEVICE* device, IRP* irp)
375 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
377 WINPR_ASSERT(parallel);
379 if (!MessageQueue_Post(parallel->queue, NULL, 0, (
void*)irp, NULL))
381 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Post failed!");
382 return ERROR_INTERNAL_ERROR;
385 return CHANNEL_RC_OK;
393static UINT parallel_free_int(PARALLEL_DEVICE* parallel)
397 if (!MessageQueue_PostQuit(parallel->queue, 0) ||
398 (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
400 const UINT error = GetLastError();
401 WLog_Print(parallel->log, WLOG_ERROR,
402 "WaitForSingleObject failed with error %" PRIu32
"!", error);
405 (void)CloseHandle(parallel->thread);
406 Stream_Free(parallel->device.data, TRUE);
407 MessageQueue_Free(parallel->queue);
410 return CHANNEL_RC_OK;
413static UINT parallel_free(DEVICE* device)
416 return parallel_free_int((PARALLEL_DEVICE*)device);
417 return CHANNEL_RC_OK;
420static void parallel_message_free(
void* obj)
428 IRP* irp = (IRP*)msg->wParam;
431 WINPR_ASSERT(irp->Discard);
443 PARALLEL_DEVICE* parallel = NULL;
446 WINPR_ASSERT(pEntryPoints);
449 WINPR_ASSERT(device);
451 wLog* log = WLog_Get(TAG);
454 char* name = device->device.Name;
455 char* path = device->Path;
457 if (!name || (name[0] ==
'*') || !path)
460 WLog_Print(log, WLOG_WARN,
"Autodetection not implemented, no ports will be redirected");
461 return CHANNEL_RC_INITIALIZATION_ERROR;
464 if (name[0] && path[0])
466 parallel = (PARALLEL_DEVICE*)calloc(1,
sizeof(PARALLEL_DEVICE));
470 WLog_Print(log, WLOG_ERROR,
"calloc failed!");
471 return CHANNEL_RC_NO_MEMORY;
475 parallel->device.type = RDPDR_DTYP_PARALLEL;
476 parallel->device.name = name;
477 parallel->device.IRPRequest = parallel_irp_request;
478 parallel->device.Free = parallel_free;
479 parallel->rdpcontext = pEntryPoints->rdpcontext;
480 const size_t length = strlen(name);
481 parallel->device.data = Stream_New(NULL, length + 1);
483 if (!parallel->device.data)
485 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_New failed!");
486 error = CHANNEL_RC_NO_MEMORY;
490 for (
size_t i = 0; i <= length; i++)
491 Stream_Write_INT8(parallel->device.data, name[i] < 0 ?
'_' : name[i]);
493 parallel->path = path;
494 parallel->queue = MessageQueue_New(NULL);
496 if (!parallel->queue)
498 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_New failed!");
499 error = CHANNEL_RC_NO_MEMORY;
503 wObject* obj = MessageQueue_Object(parallel->queue);
505 obj->fnObjectFree = parallel_message_free;
507 error = pEntryPoints->RegisterDevice(pEntryPoints->devman, ¶llel->device);
510 WLog_Print(parallel->log, WLOG_ERROR,
"RegisterDevice failed with error %" PRIu32
"!",
515 parallel->thread = CreateThread(NULL, 0, parallel_thread_func, parallel, 0, NULL);
516 if (!parallel->thread)
518 WLog_Print(parallel->log, WLOG_ERROR,
"CreateThread failed!");
519 error = ERROR_INTERNAL_ERROR;
524 return CHANNEL_RC_OK;
526 parallel_free_int(parallel);
This struct contains function pointer to initialize/free objects.