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), WINPR_CXX_COMPAT_CAST(UINT32, 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.