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 return CHANNEL_RC_OK;
130static UINT parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
132 WINPR_ASSERT(parallel);
135 (void)close(parallel->file);
137 Stream_Zero(irp->output, 5);
138 return CHANNEL_RC_OK;
146static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
153 WINPR_ASSERT(parallel);
156 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
157 return ERROR_INVALID_DATA;
158 Stream_Read_UINT32(irp->input, Length);
159 Stream_Read_UINT64(irp->input, Offset);
162 buffer = (BYTE*)calloc(Length,
sizeof(BYTE));
166 WLog_Print(parallel->log, WLOG_ERROR,
"malloc failed!");
167 return CHANNEL_RC_NO_MEMORY;
170 status = read(parallel->file, buffer, Length);
172 if ((status < 0) || (status > UINT32_MAX))
174 irp->IoStatus = STATUS_UNSUCCESSFUL;
181 Length = (UINT32)status;
184 Stream_Write_UINT32(irp->output, Length);
188 if (!Stream_EnsureRemainingCapacity(irp->output, Length))
190 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_EnsureRemainingCapacity failed!");
192 return CHANNEL_RC_NO_MEMORY;
195 Stream_Write(irp->output, buffer, Length);
199 return CHANNEL_RC_OK;
207static UINT parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
213 WINPR_ASSERT(parallel);
216 if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 12))
217 return ERROR_INVALID_DATA;
219 Stream_Read_UINT32(irp->input, Length);
220 Stream_Read_UINT64(irp->input, Offset);
223 if (!Stream_SafeSeek(irp->input, 20))
224 return ERROR_INVALID_DATA;
225 const void* ptr = Stream_ConstPointer(irp->input);
226 if (!Stream_SafeSeek(irp->input, Length))
227 return ERROR_INVALID_DATA;
232 const ssize_t status = write(parallel->file, ptr, len);
234 if ((status < 0) || (status > len))
236 irp->IoStatus = STATUS_UNSUCCESSFUL;
241 Stream_Seek(irp->input, WINPR_ASSERTING_INT_CAST(
size_t, status));
245 Stream_Write_UINT32(irp->output, Length);
246 Stream_Write_UINT8(irp->output, 0);
247 return CHANNEL_RC_OK;
255static UINT parallel_process_irp_device_control(WINPR_ATTR_UNUSED PARALLEL_DEVICE* parallel,
258 WINPR_ASSERT(parallel);
261 Stream_Write_UINT32(irp->output, 0);
262 return CHANNEL_RC_OK;
271static UINT parallel_eval(UINT error, IRP* irp)
274 if (error == CHANNEL_RC_OK)
276 WINPR_ASSERT(irp->Complete);
277 return irp->Complete(irp);
280 WLog_ERR(TAG,
"IRP %s failed with %" PRIu32, rdpdr_irp_string(irp->MajorFunction), error);
281 WINPR_ASSERT(irp->Discard);
286static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
288 UINT error = ERROR_INTERNAL_ERROR;
290 WINPR_ASSERT(parallel);
293 switch (irp->MajorFunction)
296 error = parallel_process_irp_create(parallel, irp);
300 error = parallel_process_irp_close(parallel, irp);
304 error = parallel_process_irp_read(parallel, irp);
308 error = parallel_process_irp_write(parallel, irp);
311 case IRP_MJ_DEVICE_CONTROL:
312 error = parallel_process_irp_device_control(parallel, irp);
316 irp->IoStatus = STATUS_NOT_SUPPORTED;
317 error = CHANNEL_RC_OK;
321 error = parallel_eval(error, irp);
323 DWORD level = WLOG_TRACE;
327 WLog_Print(parallel->log, level,
328 "[%s|0x%08" PRIx32
"] completed with %s [0x%08" PRIx32
"] (IoStatus %s [0x%08" PRIx32
330 rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
331 error, NtStatus2Tag(irp->IoStatus), WINPR_CXX_COMPAT_CAST(UINT32, irp->IoStatus));
336static DWORD WINAPI parallel_thread_func(LPVOID arg)
338 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg;
339 UINT error = CHANNEL_RC_OK;
341 WINPR_ASSERT(parallel);
344 if (!MessageQueue_Wait(parallel->queue))
346 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Wait failed!");
347 error = ERROR_INTERNAL_ERROR;
351 wMessage message = { 0 };
352 if (!MessageQueue_Peek(parallel->queue, &message, TRUE))
354 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Peek failed!");
355 error = ERROR_INTERNAL_ERROR;
359 if (message.id == WMQ_QUIT)
362 IRP* irp = (IRP*)message.wParam;
364 error = parallel_process_irp(parallel, irp);
367 WLog_Print(parallel->log, WLOG_ERROR,
368 "parallel_process_irp failed with error %" PRIu32
"!", error);
373 if (error && parallel->rdpcontext)
374 setChannelError(parallel->rdpcontext, error,
"parallel_thread_func reported an error");
385static UINT parallel_irp_request(DEVICE* device, IRP* irp)
387 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
389 WINPR_ASSERT(parallel);
391 if (!MessageQueue_Post(parallel->queue, NULL, 0, (
void*)irp, NULL))
393 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Post failed!");
395 return ERROR_INTERNAL_ERROR;
398 return CHANNEL_RC_OK;
406static UINT parallel_free_int(PARALLEL_DEVICE* parallel)
410 if (!MessageQueue_PostQuit(parallel->queue, 0) ||
411 (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
413 const UINT error = GetLastError();
414 WLog_Print(parallel->log, WLOG_ERROR,
415 "WaitForSingleObject failed with error %" PRIu32
"!", error);
418 (void)CloseHandle(parallel->thread);
419 Stream_Free(parallel->device.data, TRUE);
420 MessageQueue_Free(parallel->queue);
423 return CHANNEL_RC_OK;
426static UINT parallel_free(DEVICE* device)
429 return parallel_free_int((PARALLEL_DEVICE*)device);
430 return CHANNEL_RC_OK;
433static void parallel_message_free(
void* obj)
441 IRP* irp = (IRP*)msg->wParam;
444 WINPR_ASSERT(irp->Discard);
456 PARALLEL_DEVICE* parallel = NULL;
459 WINPR_ASSERT(pEntryPoints);
462 WINPR_ASSERT(device);
464 wLog* log = WLog_Get(TAG);
467 char* name = device->device.Name;
468 char* path = device->Path;
470 if (!name || (name[0] ==
'*') || !path)
473 WLog_Print(log, WLOG_WARN,
"Autodetection not implemented, no ports will be redirected");
474 return CHANNEL_RC_INITIALIZATION_ERROR;
477 if (name[0] && path[0])
479 parallel = (PARALLEL_DEVICE*)calloc(1,
sizeof(PARALLEL_DEVICE));
483 WLog_Print(log, WLOG_ERROR,
"calloc failed!");
484 return CHANNEL_RC_NO_MEMORY;
488 parallel->device.type = RDPDR_DTYP_PARALLEL;
489 parallel->device.name = name;
490 parallel->device.IRPRequest = parallel_irp_request;
491 parallel->device.Free = parallel_free;
492 parallel->rdpcontext = pEntryPoints->rdpcontext;
493 const size_t length = strlen(name);
494 parallel->device.data = Stream_New(NULL, length + 1);
496 if (!parallel->device.data)
498 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_New failed!");
499 error = CHANNEL_RC_NO_MEMORY;
503 for (
size_t i = 0; i <= length; i++)
504 Stream_Write_INT8(parallel->device.data, name[i] < 0 ?
'_' : name[i]);
506 parallel->path = path;
507 parallel->queue = MessageQueue_New(NULL);
509 if (!parallel->queue)
511 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_New failed!");
512 error = CHANNEL_RC_NO_MEMORY;
516 wObject* obj = MessageQueue_Object(parallel->queue);
520 error = pEntryPoints->RegisterDevice(pEntryPoints->devman, ¶llel->device);
523 WLog_Print(parallel->log, WLOG_ERROR,
"RegisterDevice failed with error %" PRIu32
"!",
528 parallel->thread = CreateThread(NULL, 0, parallel_thread_func, parallel, 0, NULL);
529 if (!parallel->thread)
531 WLog_Print(parallel->log, WLOG_ERROR,
"CreateThread failed!");
532 error = ERROR_INTERNAL_ERROR;
537 return CHANNEL_RC_OK;
539 parallel_free_int(parallel);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree