23 #include <freerdp/config.h>
35 #include <sys/ioctl.h>
39 #include <linux/ppdev.h>
40 #include <linux/parport.h>
43 #include <winpr/crt.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;
79 static 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 irp->Complete(irp);
130 static 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 irp->Complete(irp);
146 static 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 irp->Complete(irp);
207 static 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, status);
245 Stream_Write_UINT32(irp->output, Length);
246 Stream_Write_UINT8(irp->output, 0);
247 return irp->Complete(irp);
255 static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
257 WINPR_ASSERT(parallel);
260 Stream_Write_UINT32(irp->output, 0);
261 return irp->Complete(irp);
269 static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
271 UINT error = ERROR_INTERNAL_ERROR;
273 WINPR_ASSERT(parallel);
276 switch (irp->MajorFunction)
279 error = parallel_process_irp_create(parallel, irp);
283 error = parallel_process_irp_close(parallel, irp);
287 error = parallel_process_irp_read(parallel, irp);
291 error = parallel_process_irp_write(parallel, irp);
294 case IRP_MJ_DEVICE_CONTROL:
295 error = parallel_process_irp_device_control(parallel, irp);
299 irp->IoStatus = STATUS_NOT_SUPPORTED;
300 error = irp->Complete(irp);
304 DWORD level = WLOG_TRACE;
308 WLog_Print(parallel->log, level,
309 "[%s|0x%08" PRIx32
"] completed with %s [0x%08" PRIx32
"] (IoStatus %s [0x%08" PRIx32
311 rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
312 error, NtStatus2Tag(irp->IoStatus), irp->IoStatus);
317 static DWORD WINAPI parallel_thread_func(LPVOID arg)
319 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)arg;
320 UINT error = CHANNEL_RC_OK;
322 WINPR_ASSERT(parallel);
325 if (!MessageQueue_Wait(parallel->queue))
327 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Wait failed!");
328 error = ERROR_INTERNAL_ERROR;
332 wMessage message = { 0 };
333 if (!MessageQueue_Peek(parallel->queue, &message, TRUE))
335 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Peek failed!");
336 error = ERROR_INTERNAL_ERROR;
340 if (message.id == WMQ_QUIT)
343 IRP* irp = (IRP*)message.wParam;
345 error = parallel_process_irp(parallel, irp);
348 WLog_Print(parallel->log, WLOG_ERROR,
349 "parallel_process_irp failed with error %" PRIu32
"!", error);
354 if (error && parallel->rdpcontext)
355 setChannelError(parallel->rdpcontext, error,
"parallel_thread_func reported an error");
366 static UINT parallel_irp_request(DEVICE* device, IRP* irp)
368 PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
370 WINPR_ASSERT(parallel);
372 if (!MessageQueue_Post(parallel->queue, NULL, 0, (
void*)irp, NULL))
374 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_Post failed!");
375 return ERROR_INTERNAL_ERROR;
378 return CHANNEL_RC_OK;
386 static UINT parallel_free_int(PARALLEL_DEVICE* parallel)
390 if (!MessageQueue_PostQuit(parallel->queue, 0) ||
391 (WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
393 const UINT error = GetLastError();
394 WLog_Print(parallel->log, WLOG_ERROR,
395 "WaitForSingleObject failed with error %" PRIu32
"!", error);
398 (void)CloseHandle(parallel->thread);
399 Stream_Free(parallel->device.data, TRUE);
400 MessageQueue_Free(parallel->queue);
403 return CHANNEL_RC_OK;
406 static UINT parallel_free(DEVICE* device)
409 return parallel_free_int((PARALLEL_DEVICE*)device);
410 return CHANNEL_RC_OK;
413 static void parallel_message_free(
void* obj)
421 IRP* irp = (IRP*)msg->wParam;
424 WINPR_ASSERT(irp->Discard);
436 PARALLEL_DEVICE* parallel = NULL;
439 WINPR_ASSERT(pEntryPoints);
442 WINPR_ASSERT(device);
444 wLog* log = WLog_Get(TAG);
447 char* name = device->device.Name;
448 char* path = device->Path;
450 if (!name || (name[0] ==
'*') || !path)
453 WLog_Print(log, WLOG_WARN,
"Autodetection not implemented, no ports will be redirected");
454 return CHANNEL_RC_INITIALIZATION_ERROR;
457 if (name[0] && path[0])
459 parallel = (PARALLEL_DEVICE*)calloc(1,
sizeof(PARALLEL_DEVICE));
463 WLog_Print(log, WLOG_ERROR,
"calloc failed!");
464 return CHANNEL_RC_NO_MEMORY;
468 parallel->device.type = RDPDR_DTYP_PARALLEL;
469 parallel->device.name = name;
470 parallel->device.IRPRequest = parallel_irp_request;
471 parallel->device.Free = parallel_free;
472 parallel->rdpcontext = pEntryPoints->rdpcontext;
473 const size_t length = strlen(name);
474 parallel->device.data = Stream_New(NULL, length + 1);
476 if (!parallel->device.data)
478 WLog_Print(parallel->log, WLOG_ERROR,
"Stream_New failed!");
479 error = CHANNEL_RC_NO_MEMORY;
483 for (
size_t i = 0; i <= length; i++)
484 Stream_Write_UINT8(parallel->device.data, name[i] < 0 ?
'_' : name[i]);
486 parallel->path = path;
487 parallel->queue = MessageQueue_New(NULL);
489 if (!parallel->queue)
491 WLog_Print(parallel->log, WLOG_ERROR,
"MessageQueue_New failed!");
492 error = CHANNEL_RC_NO_MEMORY;
496 wObject* obj = MessageQueue_Object(parallel->queue);
498 obj->fnObjectFree = parallel_message_free;
500 error = pEntryPoints->RegisterDevice(pEntryPoints->devman, ¶llel->device);
503 WLog_Print(parallel->log, WLOG_ERROR,
"RegisterDevice failed with error %" PRIu32
"!",
508 parallel->thread = CreateThread(NULL, 0, parallel_thread_func, parallel, 0, NULL);
509 if (!parallel->thread)
511 WLog_Print(parallel->log, WLOG_ERROR,
"CreateThread failed!");
512 error = ERROR_INTERNAL_ERROR;
517 return CHANNEL_RC_OK;
519 parallel_free_int(parallel);
This struct contains function pointer to initialize/free objects.