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),
nullptr);
101 return CHANNEL_RC_NO_MEMORY;
103 if (parallel->file >= 0)
105 WLog_ERR(TAG,
"Duplicate create request for %s. Aborting.", path);
107 return ERROR_INVALID_DATA;
109 parallel->id = irp->devman->id_sequence++;
110 parallel->file = open(parallel->path, O_RDWR);
112 if (parallel->file < 0)
114 irp->IoStatus = STATUS_ACCESS_DENIED;
120 if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
125 Stream_Write_UINT32(irp->output, parallel->id);
126 Stream_Write_UINT8(irp->output, 0);
128 return CHANNEL_RC_OK;
136static UINT parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
138 WINPR_ASSERT(parallel);
141 (void)close(parallel->file);
144 Stream_Zero(irp->output, 5);
145 return CHANNEL_RC_OK;
153static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
158 BYTE* buffer =
nullptr;
160 WINPR_ASSERT(parallel);
163 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
164 return ERROR_INVALID_DATA;
165 Stream_Read_UINT32(irp->input, Length);
166 Stream_Read_UINT64(irp->input, Offset);
170 if (parallel->file < 0)
172 WLog_ERR(TAG,
"Device not open, aborting");
173 return ERROR_DEVICE_NOT_AVAILABLE;
176 buffer = (BYTE*)calloc(Length,
sizeof(BYTE));
180 WLog_Print(parallel->log, WLOG_ERROR,
"malloc failed!");
181 return CHANNEL_RC_NO_MEMORY;
184 status = read(parallel->file, buffer, Length);
186 if ((status < 0) || (status > UINT32_MAX))
188 irp->IoStatus = STATUS_UNSUCCESSFUL;
195 Length = (UINT32)status;
198 Stream_Write_UINT32(irp->output, Length);
202 if (!Stream_EnsureRemainingCapacity(irp->output, Length))
204 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
206 return CHANNEL_RC_NO_MEMORY;
209 Stream_Write(irp->output, buffer, Length);
213 return CHANNEL_RC_OK;
221static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
227 WINPR_ASSERT(parallel);
230 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
231 return ERROR_INVALID_DATA;
233 Stream_Read_UINT32(irp->input, Length);
234 Stream_Read_UINT64(irp->input, Offset);
237 if (!Stream_SafeSeek(irp->input, 20))
238 return ERROR_INVALID_DATA;
239 const void* ptr = Stream_ConstPointer(irp->input);
240 if (!Stream_SafeSeek(irp->input, Length))
241 return ERROR_INVALID_DATA;
244 if (parallel->file < 0)
246 WLog_ERR(TAG,
"Device not open, aborting");
247 return ERROR_DEVICE_NOT_AVAILABLE;
251 const ssize_t status = write(parallel->file, ptr, len);
253 if ((status < 0) || (status > len))
255 irp->IoStatus = STATUS_UNSUCCESSFUL;
260 Stream_Seek(irp->input, WINPR_ASSERTING_INT_CAST(
size_t, status));
264 Stream_Write_UINT32(irp->output, Length);
265 Stream_Write_UINT8(irp->output, 0);
266 return CHANNEL_RC_OK;
274static UINT parallel_process_irp_device_control(WINPR_ATTR_UNUSED PARALLEL_DEVICE* parallel,
277 WINPR_ASSERT(parallel);
280 Stream_Write_UINT32(irp->output, 0);
281 return CHANNEL_RC_OK;
290static UINT parallel_eval(UINT error, IRP* irp)
293 if (error == CHANNEL_RC_OK)
295 WINPR_ASSERT(irp->Complete);
296 return irp->Complete(irp);
299 WLog_ERR(TAG,
"IRP %s failed with %" PRIu32, rdpdr_irp_string(irp->MajorFunction), error);
300 WINPR_ASSERT(irp->Discard);
305static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
307 UINT error = ERROR_INTERNAL_ERROR;
309 WINPR_ASSERT(parallel);
312 switch (irp->MajorFunction)
315 error = parallel_process_irp_create(parallel, irp);
319 error = parallel_process_irp_close(parallel, irp);
323 error = parallel_process_irp_read(parallel, irp);
327 error = parallel_process_irp_write(parallel, irp);
330 case IRP_MJ_DEVICE_CONTROL:
331 error = parallel_process_irp_device_control(parallel, irp);
335 irp->IoStatus = STATUS_NOT_SUPPORTED;
336 error = CHANNEL_RC_OK;
340 error = parallel_eval(error, irp);
342 DWORD level = WLOG_TRACE;
346 WLog_Print(parallel->log, level,
347 "[%s|0x%08" PRIx32
"] completed with %s [0x%08" PRIx32
"] (IoStatus %s [0x%08" PRIx32
349 rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
350 error, NtStatus2Tag(irp->IoStatus), WINPR_CXX_COMPAT_CAST(UINT32, irp->IoStatus));
355static DWORD WINAPI parallel_thread_func(LPVOID arg)
357 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg;
358 UINT error = CHANNEL_RC_OK;
360 WINPR_ASSERT(parallel);
363 if (!MessageQueue_Wait(parallel->queue))
365 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Wait failed!");
366 error = ERROR_INTERNAL_ERROR;
370 wMessage message = WINPR_C_ARRAY_INIT;
371 if (!MessageQueue_Peek(parallel->queue, &message, TRUE))
373 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Peek failed!");
374 error = ERROR_INTERNAL_ERROR;
378 if (message.id == WMQ_QUIT)
381 IRP* irp = (IRP*)message.wParam;
383 error = parallel_process_irp(parallel, irp);
386 WLog_Print(parallel->log, WLOG_ERROR,
387 "parallel_process_irp failed with error %" PRIu32
"!", error);
392 if (error && parallel->rdpcontext)
393 setChannelError(parallel->rdpcontext, error,
"parallel_thread_func reported an error");
404static UINT parallel_irp_request(DEVICE* device, IRP* irp)
406 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
408 WINPR_ASSERT(parallel);
410 if (!MessageQueue_Post(parallel->queue,
nullptr, 0, (
void*)irp,
nullptr))
412 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Post failed!");
414 return ERROR_INTERNAL_ERROR;
417 return CHANNEL_RC_OK;
425static UINT parallel_free_int(PARALLEL_DEVICE* parallel)
429 if (!MessageQueue_PostQuit(parallel->queue, 0) ||
430 (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
432 const UINT error = GetLastError();
433 WLog_Print(parallel->log, WLOG_ERROR,
434 "WaitForSingleObject failed with error %" PRIu32
"!", error);
437 (void)CloseHandle(parallel->thread);
438 Stream_Free(parallel->device.data, TRUE);
439 MessageQueue_Free(parallel->queue);
442 return CHANNEL_RC_OK;
445static UINT parallel_free(DEVICE* device)
448 return parallel_free_int((PARALLEL_DEVICE*)device);
449 return CHANNEL_RC_OK;
452static void parallel_message_free(
void* obj)
460 IRP* irp = (IRP*)msg->wParam;
463 WINPR_ASSERT(irp->Discard);
475 PARALLEL_DEVICE* parallel =
nullptr;
478 WINPR_ASSERT(pEntryPoints);
481 WINPR_ASSERT(device);
483 wLog* log = WLog_Get(TAG);
486 char* name = device->device.Name;
487 char* path = device->Path;
489 if (!name || (name[0] ==
'*') || !path)
492 WLog_Print(log, WLOG_WARN,
"Autodetection not implemented, no ports will be redirected");
493 return CHANNEL_RC_INITIALIZATION_ERROR;
496 if (name[0] && path[0])
498 parallel = (PARALLEL_DEVICE*)calloc(1,
sizeof(PARALLEL_DEVICE));
502 WLog_Print(log, WLOG_ERROR,
"calloc failed!");
503 return CHANNEL_RC_NO_MEMORY;
508 parallel->device.type = RDPDR_DTYP_PARALLEL;
509 parallel->device.name = name;
510 parallel->device.IRPRequest = parallel_irp_request;
511 parallel->device.Free = parallel_free;
512 parallel->rdpcontext = pEntryPoints->rdpcontext;
513 const size_t length = strlen(name);
514 parallel->device.data = Stream_New(
nullptr, length + 1);
516 if (!parallel->device.data)
518 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_New failed!");
519 error = CHANNEL_RC_NO_MEMORY;
523 for (
size_t i = 0; i <= length; i++)
524 Stream_Write_INT8(parallel->device.data, name[i] < 0 ?
'_' : name[i]);
526 parallel->path = path;
527 parallel->queue = MessageQueue_New(
nullptr);
529 if (!parallel->queue)
531 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_New failed!");
532 error = CHANNEL_RC_NO_MEMORY;
536 wObject* obj = MessageQueue_Object(parallel->queue);
540 error = pEntryPoints->RegisterDevice(pEntryPoints->devman, ¶llel->device);
543 WLog_Print(parallel->log, WLOG_ERROR,
"RegisterDevice failed with error %" PRIu32
"!",
548 parallel->thread = CreateThread(
nullptr, 0, parallel_thread_func, parallel, 0,
nullptr);
549 if (!parallel->thread)
551 WLog_Print(parallel->log, WLOG_ERROR,
"CreateThread failed!");
552 error = ERROR_INTERNAL_ERROR;
557 return CHANNEL_RC_OK;
559 parallel_free_int(parallel);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree