Merge pull request #10510 from akallabeth/serial-cleanup
Serial cleanup
This commit is contained in:
commit
00eb86970d
@ -6,11 +6,19 @@ set(OPTION_SERVER_DEFAULT OFF)
|
||||
if(WIN32)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on windows")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on apple")
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on android")
|
||||
endif()
|
||||
|
||||
define_channel_options(NAME "parallel" TYPE "device"
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
#include <freerdp/utils/rdpdr_utils.h>
|
||||
|
||||
#define TAG CHANNELS_TAG("drive.client")
|
||||
|
||||
@ -67,6 +68,7 @@ typedef struct
|
||||
HANDLE thread;
|
||||
wMessageQueue* queue;
|
||||
rdpContext* rdpcontext;
|
||||
wLog* log;
|
||||
} PARALLEL_DEVICE;
|
||||
|
||||
/**
|
||||
@ -166,7 +168,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
WLog_ERR(TAG, "malloc failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "malloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -190,7 +192,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(irp->output, Length))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
|
||||
free(buffer);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
@ -271,7 +273,7 @@ static UINT parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP*
|
||||
*/
|
||||
static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
UINT error = 0;
|
||||
UINT error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(parallel);
|
||||
WINPR_ASSERT(irp);
|
||||
@ -279,57 +281,42 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
if ((error = parallel_process_irp_create(parallel, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp_create failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = parallel_process_irp_create(parallel, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_CLOSE:
|
||||
if ((error = parallel_process_irp_close(parallel, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp_close failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = parallel_process_irp_close(parallel, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
if ((error = parallel_process_irp_read(parallel, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp_read failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = parallel_process_irp_read(parallel, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
if ((error = parallel_process_irp_write(parallel, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp_write failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = parallel_process_irp_write(parallel, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
if ((error = parallel_process_irp_device_control(parallel, irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp_device_control failed with error %" PRIu32 "!",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = parallel_process_irp_device_control(parallel, irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
return irp->Complete(irp);
|
||||
error = irp->Complete(irp);
|
||||
break;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
DWORD level = WLOG_TRACE;
|
||||
if (error)
|
||||
level = WLOG_WARN;
|
||||
|
||||
WLog_Print(parallel->log, level,
|
||||
"[%s|0x%08" PRIx32 "] completed with %s [0x%08" PRIx32 "] (IoStatus %s [0x%08" PRIx32
|
||||
"])",
|
||||
rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
|
||||
error, NtStatus2Tag(irp->IoStatus), irp->IoStatus);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static DWORD WINAPI parallel_thread_func(LPVOID arg)
|
||||
@ -342,7 +329,7 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
|
||||
{
|
||||
if (!MessageQueue_Wait(parallel->queue))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Wait failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "MessageQueue_Wait failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
@ -350,7 +337,7 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
|
||||
wMessage message = { 0 };
|
||||
if (!MessageQueue_Peek(parallel->queue, &message, TRUE))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Peek failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "MessageQueue_Peek failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
@ -360,9 +347,11 @@ static DWORD WINAPI parallel_thread_func(LPVOID arg)
|
||||
|
||||
IRP* irp = (IRP*)message.wParam;
|
||||
|
||||
if ((error = parallel_process_irp(parallel, irp)))
|
||||
error = parallel_process_irp(parallel, irp);
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "parallel_process_irp failed with error %" PRIu32 "!", error);
|
||||
WLog_Print(parallel->log, WLOG_ERROR,
|
||||
"parallel_process_irp failed with error %" PRIu32 "!", error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -383,9 +372,11 @@ static UINT parallel_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
|
||||
|
||||
WINPR_ASSERT(parallel);
|
||||
|
||||
if (!MessageQueue_Post(parallel->queue, NULL, 0, (void*)irp, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "MessageQueue_Post failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -399,21 +390,24 @@ static UINT parallel_irp_request(DEVICE* device, IRP* irp)
|
||||
*/
|
||||
static UINT parallel_free(DEVICE* device)
|
||||
{
|
||||
UINT error = 0;
|
||||
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*)device;
|
||||
|
||||
if (!MessageQueue_PostQuit(parallel->queue, 0) ||
|
||||
(WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
|
||||
if (parallel)
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
if (!MessageQueue_PostQuit(parallel->queue, 0) ||
|
||||
(WaitForSingleObject(parallel->thread, INFINITE) == WAIT_FAILED))
|
||||
{
|
||||
const UINT error = GetLastError();
|
||||
WLog_Print(parallel->log, WLOG_ERROR,
|
||||
"WaitForSingleObject failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
CloseHandle(parallel->thread);
|
||||
Stream_Free(parallel->device.data, TRUE);
|
||||
MessageQueue_Free(parallel->queue);
|
||||
free(parallel);
|
||||
CloseHandle(parallel->thread);
|
||||
Stream_Free(parallel->device.data, TRUE);
|
||||
MessageQueue_Free(parallel->queue);
|
||||
free(parallel);
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
@ -439,24 +433,24 @@ static void parallel_message_free(void* obj)
|
||||
*/
|
||||
FREERDP_ENTRY_POINT(UINT parallel_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
|
||||
{
|
||||
char* name = NULL;
|
||||
char* path = NULL;
|
||||
size_t length = 0;
|
||||
RDPDR_PARALLEL* device = NULL;
|
||||
PARALLEL_DEVICE* parallel = NULL;
|
||||
UINT error = 0;
|
||||
|
||||
WINPR_ASSERT(pEntryPoints);
|
||||
|
||||
device = (RDPDR_PARALLEL*)pEntryPoints->device;
|
||||
RDPDR_PARALLEL* device = (RDPDR_PARALLEL*)pEntryPoints->device;
|
||||
WINPR_ASSERT(device);
|
||||
|
||||
name = device->device.Name;
|
||||
path = device->Path;
|
||||
wLog* log = WLog_Get(TAG);
|
||||
WINPR_ASSERT(log);
|
||||
|
||||
char* name = device->device.Name;
|
||||
char* path = device->Path;
|
||||
|
||||
if (!name || (name[0] == '*') || !path)
|
||||
{
|
||||
/* TODO: implement auto detection of parallel ports */
|
||||
WLog_Print(log, WLOG_WARN, "Autodetection not implemented, no ports will be redirected");
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
}
|
||||
|
||||
@ -466,21 +460,22 @@ FREERDP_ENTRY_POINT(UINT parallel_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINT
|
||||
|
||||
if (!parallel)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
parallel->log = log;
|
||||
parallel->device.type = RDPDR_DTYP_PARALLEL;
|
||||
parallel->device.name = name;
|
||||
parallel->device.IRPRequest = parallel_irp_request;
|
||||
parallel->device.Free = parallel_free;
|
||||
parallel->rdpcontext = pEntryPoints->rdpcontext;
|
||||
length = strlen(name);
|
||||
const size_t length = strlen(name);
|
||||
parallel->device.data = Stream_New(NULL, length + 1);
|
||||
|
||||
if (!parallel->device.data)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "Stream_New failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
@ -493,7 +488,7 @@ FREERDP_ENTRY_POINT(UINT parallel_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINT
|
||||
|
||||
if (!parallel->queue)
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_New failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "MessageQueue_New failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
@ -502,16 +497,18 @@ FREERDP_ENTRY_POINT(UINT parallel_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINT
|
||||
WINPR_ASSERT(obj);
|
||||
obj->fnObjectFree = parallel_message_free;
|
||||
|
||||
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)parallel)))
|
||||
error = pEntryPoints->RegisterDevice(pEntryPoints->devman, ¶llel->device);
|
||||
if (error)
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "RegisterDevice failed with error %" PRIu32 "!",
|
||||
error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!(parallel->thread =
|
||||
CreateThread(NULL, 0, parallel_thread_func, (void*)parallel, 0, NULL)))
|
||||
parallel->thread = CreateThread(NULL, 0, parallel_thread_func, parallel, 0, NULL);
|
||||
if (!parallel->thread)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
WLog_Print(parallel->log, WLOG_ERROR, "CreateThread failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
goto error_out;
|
||||
}
|
||||
@ -519,8 +516,7 @@ FREERDP_ENTRY_POINT(UINT parallel_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINT
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
MessageQueue_Free(parallel->queue);
|
||||
Stream_Free(parallel->device.data, TRUE);
|
||||
free(parallel);
|
||||
if (parallel)
|
||||
parallel_free(¶llel->device);
|
||||
return error;
|
||||
}
|
||||
|
@ -6,11 +6,19 @@ set(OPTION_SERVER_DEFAULT OFF)
|
||||
if(WIN32)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on windows")
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on android")
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
message("Serial redirection not supported on apple")
|
||||
endif()
|
||||
|
||||
define_channel_options(NAME "serial" TYPE "device"
|
||||
|
@ -24,4 +24,8 @@ set(${MODULE_PREFIX}_SRCS
|
||||
set(${MODULE_PREFIX}_LIBS
|
||||
winpr freerdp
|
||||
)
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
|
||||
|
||||
# Serial implementation is currently linux only. BSD* might also work but untested
|
||||
if (UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
|
||||
endif()
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
@ -43,11 +44,6 @@
|
||||
|
||||
#define TAG CHANNELS_TAG("serial.client")
|
||||
|
||||
/* TODO: all #ifdef __linux__ could be removed once only some generic
|
||||
* functions will be used. Replace CommReadFile by ReadFile,
|
||||
* CommWriteFile by WriteFile etc.. */
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
|
||||
#define MAX_IRP_THREADS 5
|
||||
|
||||
typedef struct
|
||||
@ -63,7 +59,6 @@ typedef struct
|
||||
|
||||
/* one thread per pending IRP and indexed according their CompletionId */
|
||||
wListDictionary* IrpThreads;
|
||||
UINT32 IrpThreadToBeTerminatedCount;
|
||||
CRITICAL_SECTION TerminatingIrpThreadsLock;
|
||||
rdpContext* rdpcontext;
|
||||
} SERIAL_DEVICE;
|
||||
@ -74,7 +69,8 @@ typedef struct
|
||||
IRP* irp;
|
||||
} IRP_THREAD_DATA;
|
||||
|
||||
static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
|
||||
static void close_terminated_irp_thread_handles(SERIAL_DEVICE* serial, BOOL forceClose);
|
||||
static UINT32 GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
|
||||
{
|
||||
/* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests
|
||||
*/
|
||||
@ -126,7 +122,10 @@ static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
DWORD CreateDisposition = 0;
|
||||
UINT32 PathLength = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, 32))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */
|
||||
@ -202,11 +201,16 @@ error_handle:
|
||||
|
||||
static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, 32))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
|
||||
|
||||
close_terminated_irp_thread_handles(serial, TRUE);
|
||||
|
||||
if (!CloseHandle(serial->hComm))
|
||||
{
|
||||
WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%" PRIu32 ") closed.",
|
||||
@ -217,9 +221,9 @@ static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %" PRIu32 ", FileId: %" PRIu32 ") closed.",
|
||||
serial->device.name, irp->device->id, irp->FileId);
|
||||
serial->hComm = NULL;
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
error_handle:
|
||||
serial->hComm = NULL;
|
||||
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
@ -236,7 +240,10 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
BYTE* buffer = NULL;
|
||||
DWORD nbRead = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, 32))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
@ -268,7 +275,7 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
WLog_Print(serial->log, WLOG_DEBUG,
|
||||
"read failure to %s, nbRead=%" PRIu32 ", last-error: 0x%08" PRIX32 "",
|
||||
serial->device.name, nbRead, GetLastError());
|
||||
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||
irp->IoStatus = GetLastErrorToIoStatus(serial);
|
||||
}
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes read from %s", nbRead,
|
||||
@ -280,7 +287,7 @@ error_handle:
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(irp->output, nbRead))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
|
||||
free(buffer);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
@ -298,7 +305,10 @@ static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
UINT64 Offset = 0;
|
||||
DWORD nbWritten = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, 32))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
@ -330,7 +340,7 @@ static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
WLog_Print(serial->log, WLOG_DEBUG,
|
||||
"write failure to %s, nbWritten=%" PRIu32 ", last-error: 0x%08" PRIX32 "",
|
||||
serial->device.name, nbWritten, GetLastError());
|
||||
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||
irp->IoStatus = GetLastErrorToIoStatus(serial);
|
||||
}
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes written to %s", nbWritten,
|
||||
@ -354,7 +364,10 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
BYTE* OutputBuffer = NULL;
|
||||
DWORD BytesReturned = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, 32))
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, 32))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
@ -362,7 +375,7 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, InputBufferLength))
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(serial->log, irp->input, InputBufferLength))
|
||||
return ERROR_INVALID_DATA;
|
||||
|
||||
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
|
||||
@ -401,7 +414,7 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
"CommDeviceIoControl failure: IoControlCode=[0x%" PRIX32
|
||||
"] %s, last-error: 0x%08" PRIX32 "",
|
||||
IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError());
|
||||
irp->IoStatus = _GetLastErrorToIoStatus(serial);
|
||||
irp->IoStatus = GetLastErrorToIoStatus(serial);
|
||||
}
|
||||
|
||||
error_handle:
|
||||
@ -415,7 +428,7 @@ error_handle:
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(irp->output, BytesReturned))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
|
||||
free(InputBuffer);
|
||||
free(OutputBuffer);
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
@ -445,7 +458,11 @@ error_handle:
|
||||
static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: s, MinorFunction: 0x%08" PRIX32 "\n",
|
||||
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: %s, MinorFunction: 0x%08" PRIX32 "\n",
|
||||
rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
@ -459,9 +476,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
if ((error = serial_process_irp_read(serial, irp)))
|
||||
WLog_ERR(TAG, "serial_process_irp_read failed with error %" PRIu32 "!", error);
|
||||
|
||||
error = serial_process_irp_read(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
@ -469,10 +484,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
if ((error = serial_process_irp_device_control(serial, irp)))
|
||||
WLog_ERR(TAG, "serial_process_irp_device_control failed with error %" PRIu32 "!",
|
||||
error);
|
||||
|
||||
error = serial_process_irp_device_control(serial, irp);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -480,6 +492,16 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD level = WLOG_TRACE;
|
||||
if (error)
|
||||
level = WLOG_WARN;
|
||||
|
||||
WLog_Print(serial->log, level,
|
||||
"[%s|0x%08" PRIx32 "] completed with %s [0x%08" PRIx32 "] (IoStatus %s [0x%08" PRIx32
|
||||
"])",
|
||||
rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error),
|
||||
error, NtStatus2Tag(irp->IoStatus), irp->IoStatus);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -488,15 +510,19 @@ static DWORD WINAPI irp_thread_func(LPVOID arg)
|
||||
IRP_THREAD_DATA* data = (IRP_THREAD_DATA*)arg;
|
||||
UINT error = 0;
|
||||
|
||||
WINPR_ASSERT(data);
|
||||
WINPR_ASSERT(data->serial);
|
||||
WINPR_ASSERT(data->irp);
|
||||
|
||||
/* blocks until the end of the request */
|
||||
if ((error = serial_process_irp(data->serial, data->irp)))
|
||||
{
|
||||
WLog_ERR(TAG, "serial_process_irp failed with error %" PRIu32 "", error);
|
||||
WLog_Print(data->serial->log, WLOG_ERROR,
|
||||
"serial_process_irp failed with error %" PRIu32 "", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
||||
data->serial->IrpThreadToBeTerminatedCount++;
|
||||
error = data->irp->Complete(data->irp);
|
||||
LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
||||
error_out:
|
||||
@ -512,74 +538,71 @@ error_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void close_unterminated_irp_thread(wListDictionary* list, wLog* log, ULONG_PTR id)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
HANDLE self = _GetCurrentThread();
|
||||
HANDLE cirpThread = ListDictionary_GetItemValue(list, (void*)id);
|
||||
if (self == cirpThread)
|
||||
WLog_Print(log, WLOG_DEBUG, "Skipping termination of own IRP thread");
|
||||
else
|
||||
ListDictionary_Remove(list, (void*)id);
|
||||
}
|
||||
|
||||
static void close_terminated_irp_thread(wListDictionary* list, wLog* log, ULONG_PTR id)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
|
||||
HANDLE cirpThread = ListDictionary_GetItemValue(list, (void*)id);
|
||||
/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is
|
||||
* stil alived or not */
|
||||
const DWORD waitResult = WaitForSingleObject(cirpThread, 0);
|
||||
|
||||
if (waitResult == WAIT_OBJECT_0)
|
||||
ListDictionary_Remove(list, (void*)id);
|
||||
else if (waitResult != WAIT_TIMEOUT)
|
||||
{
|
||||
/* unexpected thread state */
|
||||
WLog_Print(log, WLOG_WARN, "WaitForSingleObject, got an unexpected result=0x%" PRIX32 "\n",
|
||||
waitResult);
|
||||
}
|
||||
}
|
||||
|
||||
void close_terminated_irp_thread_handles(SERIAL_DEVICE* serial, BOOL forceClose)
|
||||
{
|
||||
WINPR_ASSERT(serial);
|
||||
|
||||
EnterCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||
|
||||
ULONG_PTR* ids = NULL;
|
||||
const size_t nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
|
||||
|
||||
for (size_t i = 0; i < nbIds; i++)
|
||||
{
|
||||
ULONG_PTR id = ids[i];
|
||||
if (forceClose)
|
||||
close_unterminated_irp_thread(serial->IrpThreads, serial->log, id);
|
||||
else
|
||||
close_terminated_irp_thread(serial->IrpThreads, serial->log, id);
|
||||
}
|
||||
|
||||
free(ids);
|
||||
|
||||
LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||
}
|
||||
|
||||
static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
IRP_THREAD_DATA* data = NULL;
|
||||
HANDLE irpThread = NULL;
|
||||
HANDLE previousIrpThread = NULL;
|
||||
uintptr_t key = 0;
|
||||
/* for a test/debug purpose, uncomment the code below to get a
|
||||
* single thread for all IRPs. NB: two IRPs could not be
|
||||
* processed at the same time, typically two concurent
|
||||
* Read/Write operations could block each other. */
|
||||
/* serial_process_irp(serial, irp); */
|
||||
/* irp->Complete(irp); */
|
||||
/* return; */
|
||||
/* NOTE: for good or bad, this implementation relies on the
|
||||
* server to avoid a flooding of requests. see also _purge().
|
||||
*/
|
||||
EnterCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||
|
||||
while (serial->IrpThreadToBeTerminatedCount > 0)
|
||||
{
|
||||
/* Cleaning up termitating and pending irp
|
||||
* threads. See also: irp_thread_func() */
|
||||
HANDLE cirpThread = NULL;
|
||||
ULONG_PTR* ids = NULL;
|
||||
const size_t nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
|
||||
WINPR_ASSERT(serial);
|
||||
WINPR_ASSERT(irp);
|
||||
|
||||
for (size_t i = 0; i < nbIds; i++)
|
||||
{
|
||||
/* Checking if ids[i] is terminating or pending */
|
||||
DWORD waitResult = 0;
|
||||
ULONG_PTR id = ids[i];
|
||||
cirpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
|
||||
/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is
|
||||
* stil alived or not */
|
||||
waitResult = WaitForSingleObject(cirpThread, 0);
|
||||
close_terminated_irp_thread_handles(serial, FALSE);
|
||||
|
||||
if (waitResult == WAIT_OBJECT_0)
|
||||
{
|
||||
/* terminating thread */
|
||||
/* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz"
|
||||
* naturally died", id); */
|
||||
CloseHandle(cirpThread);
|
||||
ListDictionary_Remove(serial->IrpThreads, (void*)id);
|
||||
serial->IrpThreadToBeTerminatedCount--;
|
||||
}
|
||||
else if (waitResult != WAIT_TIMEOUT)
|
||||
{
|
||||
/* unexpected thread state */
|
||||
WLog_Print(serial->log, WLOG_WARN,
|
||||
"WaitForSingleObject, got an unexpected result=0x%" PRIX32 "\n",
|
||||
waitResult);
|
||||
WINPR_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */
|
||||
}
|
||||
|
||||
if (serial->IrpThreadToBeTerminatedCount > 0)
|
||||
{
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " IRP thread(s) not yet terminated",
|
||||
serial->IrpThreadToBeTerminatedCount);
|
||||
Sleep(1); /* 1 ms */
|
||||
}
|
||||
|
||||
free(ids);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||
/* NB: At this point and thanks to the synchronization we're
|
||||
* sure that the incoming IRP uses well a recycled
|
||||
* CompletionId or the server sent again an IRP already posted
|
||||
@ -642,7 +665,7 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
|
||||
data->serial = serial;
|
||||
data->irp = irp;
|
||||
/* data freed by irp_thread_func */
|
||||
irpThread = CreateThread(NULL, 0, irp_thread_func, (void*)data, 0, NULL);
|
||||
irpThread = CreateThread(NULL, 0, irp_thread_func, (void*)data, CREATE_SUSPENDED, NULL);
|
||||
|
||||
if (irpThread == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@ -654,45 +677,21 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
|
||||
|
||||
if (!ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread))
|
||||
{
|
||||
WLog_ERR(TAG, "ListDictionary_Add failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "ListDictionary_Add failed!");
|
||||
goto error_handle;
|
||||
}
|
||||
|
||||
ResumeThread(irpThread);
|
||||
|
||||
return;
|
||||
error_handle:
|
||||
if (irpThread)
|
||||
CloseHandle(irpThread);
|
||||
irp->IoStatus = STATUS_NO_MEMORY;
|
||||
irp->Complete(irp);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void terminate_pending_irp_threads(SERIAL_DEVICE* serial)
|
||||
{
|
||||
WINPR_ASSERT(serial);
|
||||
|
||||
ULONG_PTR* ids = NULL;
|
||||
const size_t nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "Terminating %" PRIuz " IRP thread(s)", nbIds);
|
||||
|
||||
for (size_t i = 0; i < nbIds; i++)
|
||||
{
|
||||
HANDLE irpThread = NULL;
|
||||
ULONG_PTR id = ids[i];
|
||||
irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
|
||||
TerminateThread(irpThread, 0);
|
||||
if (WaitForSingleObject(irpThread, INFINITE) == WAIT_FAILED)
|
||||
{
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed!");
|
||||
continue;
|
||||
}
|
||||
|
||||
CloseHandle(irpThread);
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*)id);
|
||||
}
|
||||
|
||||
ListDictionary_Clear(serial->IrpThreads);
|
||||
free(ids);
|
||||
}
|
||||
|
||||
static DWORD WINAPI serial_thread_func(LPVOID arg)
|
||||
{
|
||||
IRP* irp = NULL;
|
||||
@ -700,27 +699,26 @@ static DWORD WINAPI serial_thread_func(LPVOID arg)
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
WINPR_ASSERT(serial);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!MessageQueue_Wait(serial->MainIrpQueue))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Wait failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "MessageQueue_Wait failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Peek failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "MessageQueue_Peek failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (message.id == WMQ_QUIT)
|
||||
{
|
||||
terminate_pending_irp_threads(serial);
|
||||
break;
|
||||
}
|
||||
|
||||
irp = (IRP*)message.wParam;
|
||||
|
||||
@ -728,6 +726,7 @@ static DWORD WINAPI serial_thread_func(LPVOID arg)
|
||||
create_irp_thread(serial, irp);
|
||||
}
|
||||
|
||||
ListDictionary_Clear(serial->IrpThreads);
|
||||
if (error && serial->rdpcontext)
|
||||
setChannelError(serial->rdpcontext, error, "serial_thread_func reported an error");
|
||||
|
||||
@ -744,6 +743,7 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
|
||||
WINPR_ASSERT(irp != NULL);
|
||||
WINPR_ASSERT(serial);
|
||||
|
||||
if (irp == NULL)
|
||||
return CHANNEL_RC_OK;
|
||||
@ -755,7 +755,7 @@ static UINT serial_irp_request(DEVICE* device, IRP* irp)
|
||||
|
||||
if (!MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*)irp, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "MessageQueue_Post failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -771,18 +771,24 @@ static UINT serial_free(DEVICE* device)
|
||||
{
|
||||
UINT error = 0;
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
|
||||
if (!serial)
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
|
||||
MessageQueue_PostQuit(serial->MainIrpQueue, 0);
|
||||
if (serial->MainIrpQueue)
|
||||
MessageQueue_PostQuit(serial->MainIrpQueue, 0);
|
||||
|
||||
if (WaitForSingleObject(serial->MainThread, INFINITE) == WAIT_FAILED)
|
||||
if (serial->MainThread)
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
||||
return error;
|
||||
if (WaitForSingleObject(serial->MainThread, INFINITE) == WAIT_FAILED)
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_Print(serial->log, WLOG_ERROR,
|
||||
"WaitForSingleObject failed with error %" PRIu32 "!", error);
|
||||
}
|
||||
CloseHandle(serial->MainThread);
|
||||
}
|
||||
|
||||
CloseHandle(serial->MainThread);
|
||||
|
||||
if (serial->hComm)
|
||||
CloseHandle(serial->hComm);
|
||||
|
||||
@ -795,8 +801,6 @@ static UINT serial_free(DEVICE* device)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
||||
static void serial_message_free(void* obj)
|
||||
{
|
||||
wMessage* msg = obj;
|
||||
@ -812,6 +816,23 @@ static void serial_message_free(void* obj)
|
||||
irp->Discard(irp);
|
||||
}
|
||||
|
||||
static void irp_thread_close(void* arg)
|
||||
{
|
||||
HANDLE hdl = arg;
|
||||
if (hdl)
|
||||
{
|
||||
HANDLE thz = _GetCurrentThread();
|
||||
if (thz == hdl)
|
||||
WLog_WARN(TAG, "closing self, ignoring...");
|
||||
else
|
||||
{
|
||||
TerminateThread(hdl, 0);
|
||||
WaitForSingleObject(hdl, INFINITE);
|
||||
CloseHandle(hdl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
@ -819,46 +840,36 @@ static void serial_message_free(void* obj)
|
||||
*/
|
||||
FREERDP_ENTRY_POINT(UINT serial_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
|
||||
{
|
||||
char* name = NULL;
|
||||
char* path = NULL;
|
||||
char* driver = NULL;
|
||||
RDPDR_SERIAL* device = NULL;
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
size_t len = 0;
|
||||
SERIAL_DEVICE* serial = NULL;
|
||||
#endif /* __linux__ */
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
|
||||
WINPR_ASSERT(pEntryPoints);
|
||||
|
||||
device = (RDPDR_SERIAL*)pEntryPoints->device;
|
||||
RDPDR_SERIAL* device = (RDPDR_SERIAL*)pEntryPoints->device;
|
||||
WINPR_ASSERT(device);
|
||||
|
||||
name = device->device.Name;
|
||||
path = device->Path;
|
||||
driver = device->Driver;
|
||||
wLog* log = WLog_Get(TAG);
|
||||
const char* name = device->device.Name;
|
||||
const char* path = device->Path;
|
||||
const char* driver = device->Driver;
|
||||
|
||||
if (!name || (name[0] == '*'))
|
||||
{
|
||||
/* TODO: implement auto detection of serial ports */
|
||||
WLog_Print(log, WLOG_WARN,
|
||||
"Serial port autodetection not implemented, nothing will be redirected!");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
if ((name && name[0]) && (path && path[0]))
|
||||
{
|
||||
wLog* log = NULL;
|
||||
log = WLog_Get("com.freerdp.channel.serial.client");
|
||||
WLog_Print(log, WLOG_DEBUG, "initializing");
|
||||
#ifndef __linux__ /* to be removed */
|
||||
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
|
||||
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||
#else /* __linux __ */
|
||||
WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path);
|
||||
|
||||
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
|
||||
{
|
||||
DWORD status = GetLastError();
|
||||
WLog_ERR(TAG, "DefineCommDevice failed with %08" PRIx32, status);
|
||||
WLog_Print(log, WLOG_ERROR, "DefineCommDevice failed with %08" PRIx32, status);
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -866,7 +877,7 @@ FREERDP_ENTRY_POINT(UINT serial_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS
|
||||
|
||||
if (!serial)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(log, WLOG_ERROR, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -881,7 +892,7 @@ FREERDP_ENTRY_POINT(UINT serial_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS
|
||||
|
||||
if (!serial->device.data)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "calloc failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
@ -899,10 +910,10 @@ FREERDP_ENTRY_POINT(UINT serial_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS
|
||||
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
|
||||
else
|
||||
{
|
||||
WINPR_ASSERT(FALSE);
|
||||
WLog_Print(serial->log, WLOG_DEBUG,
|
||||
"Unknown server's serial driver: %s. SerCx2 will be used", driver);
|
||||
serial->ServerSerialDriverId = SerialDriverSerialSys;
|
||||
WLog_Print(serial->log, WLOG_WARN, "Unknown server's serial driver: %s.", driver);
|
||||
WLog_Print(serial->log, WLOG_WARN,
|
||||
"Valid options are: 'Serial' (default), 'SerCx' and 'SerCx2'");
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -919,64 +930,67 @@ FREERDP_ENTRY_POINT(UINT serial_DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "Unknown flag: %s", device->Permissive);
|
||||
WINPR_ASSERT(FALSE);
|
||||
WLog_Print(serial->log, WLOG_WARN, "Unknown flag: %s", device->Permissive);
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver,
|
||||
serial->ServerSerialDriverId);
|
||||
/* TODO: implement auto detection of the server's serial driver */
|
||||
|
||||
serial->MainIrpQueue = MessageQueue_New(NULL);
|
||||
|
||||
if (!serial->MainIrpQueue)
|
||||
{
|
||||
WLog_ERR(TAG, "MessageQueue_New failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "MessageQueue_New failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
wObject* obj = MessageQueue_Object(serial->MainIrpQueue);
|
||||
WINPR_ASSERT(obj);
|
||||
obj->fnObjectFree = serial_message_free;
|
||||
{
|
||||
wObject* obj = MessageQueue_Object(serial->MainIrpQueue);
|
||||
WINPR_ASSERT(obj);
|
||||
obj->fnObjectFree = serial_message_free;
|
||||
}
|
||||
|
||||
/* IrpThreads content only modified by create_irp_thread() */
|
||||
serial->IrpThreads = ListDictionary_New(FALSE);
|
||||
|
||||
if (!serial->IrpThreads)
|
||||
{
|
||||
WLog_ERR(TAG, "ListDictionary_New failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "ListDictionary_New failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
serial->IrpThreadToBeTerminatedCount = 0;
|
||||
{
|
||||
wObject* obj = ListDictionary_ValueObject(serial->IrpThreads);
|
||||
WINPR_ASSERT(obj);
|
||||
obj->fnObjectFree = irp_thread_close;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||
|
||||
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)serial)))
|
||||
error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &serial->device);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %" PRIu32 "!", error);
|
||||
WLog_Print(serial->log, WLOG_ERROR,
|
||||
"EntryPoints->RegisterDevice failed with error %" PRIu32 "!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!(serial->MainThread =
|
||||
CreateThread(NULL, 0, serial_thread_func, (void*)serial, 0, NULL)))
|
||||
serial->MainThread = CreateThread(NULL, 0, serial_thread_func, serial, 0, NULL);
|
||||
if (!serial->MainThread)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
WLog_Print(serial->log, WLOG_ERROR, "CreateThread failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
#endif /* __linux __ */
|
||||
}
|
||||
|
||||
return error;
|
||||
error_out:
|
||||
#ifdef __linux__ /* to be removed */
|
||||
ListDictionary_Free(serial->IrpThreads);
|
||||
MessageQueue_Free(serial->MainIrpQueue);
|
||||
Stream_Free(serial->device.data, TRUE);
|
||||
free(serial);
|
||||
#endif /* __linux __ */
|
||||
if (serial)
|
||||
serial_free(&serial->device);
|
||||
return error;
|
||||
}
|
||||
|
@ -626,9 +626,13 @@ BOOL freerdp_client_print_command_line_help_ex(int argc, char** argv,
|
||||
printf("Smartcard Redirection: /smartcard:<device>\n");
|
||||
printf("Smartcard logon with Kerberos authentication: /smartcard-logon /sec:nla\n");
|
||||
|
||||
#if defined(CHANNEL_SERIAL_CLIENT)
|
||||
printf("Serial Port Redirection: /serial:<name>,<device>,[SerCx2|SerCx|Serial],[permissive]\n");
|
||||
printf("Serial Port Redirection: /serial:COM1,/dev/ttyS0\n");
|
||||
#endif
|
||||
#if defined(CHANNEL_PARALLEL_CLIENT)
|
||||
printf("Parallel Port Redirection: /parallel:<name>,<device>\n");
|
||||
#endif
|
||||
printf("Printer Redirection: /printer:<device>,<driver>,[default]\n");
|
||||
printf("TCP redirection: /rdp2tcp:/usr/bin/rdp2tcp\n");
|
||||
printf("\n");
|
||||
@ -787,6 +791,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count, cons
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#if defined(CHANNEL_SERIAL_CLIENT)
|
||||
else if (option_equals(params[0], "serial"))
|
||||
{
|
||||
RDPDR_DEVICE* serial = NULL;
|
||||
@ -812,6 +817,7 @@ BOOL freerdp_client_add_device_channel(rdpSettings* settings, size_t count, cons
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
else if (option_equals(params[0], "parallel"))
|
||||
{
|
||||
RDPDR_DEVICE* parallel = NULL;
|
||||
@ -1076,6 +1082,7 @@ static int freerdp_client_command_line_post_filter_int(void* context, COMMAND_LI
|
||||
if (status)
|
||||
return fail_at(arg, status);
|
||||
}
|
||||
#if defined(CHANNEL_SERIAL_CLIENT)
|
||||
CommandLineSwitchCase(arg, "serial")
|
||||
{
|
||||
size_t count = 0;
|
||||
@ -1086,6 +1093,8 @@ static int freerdp_client_command_line_post_filter_int(void* context, COMMAND_LI
|
||||
if (status)
|
||||
return fail_at(arg, status);
|
||||
}
|
||||
#endif
|
||||
#if defined(CHANNEL_PARALLEL_CLIENT)
|
||||
CommandLineSwitchCase(arg, "parallel")
|
||||
{
|
||||
size_t count = 0;
|
||||
@ -1096,6 +1105,7 @@ static int freerdp_client_command_line_post_filter_int(void* context, COMMAND_LI
|
||||
if (status)
|
||||
return fail_at(arg, status);
|
||||
}
|
||||
#endif
|
||||
CommandLineSwitchCase(arg, "smartcard")
|
||||
{
|
||||
size_t count = 0;
|
||||
|
@ -355,8 +355,10 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
||||
{ "old-license", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL,
|
||||
"Use the old license workflow (no CAL and hwId set to 0)" },
|
||||
{ "p", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Password" },
|
||||
#if defined(CHANNEL_PARALLEL_CLIENT)
|
||||
{ "parallel", COMMAND_LINE_VALUE_OPTIONAL, "<name>[,<path>]", NULL, NULL, -1, NULL,
|
||||
"Redirect parallel device" },
|
||||
#endif
|
||||
{ "parent-window", COMMAND_LINE_VALUE_REQUIRED, "<window-id>", NULL, NULL, -1, NULL,
|
||||
"Parent window id" },
|
||||
{ "pcb", COMMAND_LINE_VALUE_REQUIRED, "<blob>", NULL, NULL, -1, NULL, "Preconnection Blob" },
|
||||
@ -415,8 +417,10 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
||||
{ "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL,
|
||||
"[DEPRECATED, use /sec:tls] TLS protocol security" },
|
||||
#endif
|
||||
#if defined(CHANNEL_SERIAL_CLIENT)
|
||||
{ "serial", COMMAND_LINE_VALUE_OPTIONAL, "<name>[,<path>[,<driver>[,permissive]]]", NULL, NULL,
|
||||
-1, "tty", "Redirect serial device" },
|
||||
#endif
|
||||
{ "server-name", COMMAND_LINE_VALUE_REQUIRED, "<name>", NULL, NULL, -1, NULL,
|
||||
"User-specified server name to use for validation (TLS, Kerberos)" },
|
||||
{ "shell", COMMAND_LINE_VALUE_REQUIRED, "<shell>", NULL, NULL, -1, NULL, "Alternate shell" },
|
||||
|
@ -18,7 +18,7 @@
|
||||
set(MODULE_NAME "winpr-comm")
|
||||
set(MODULE_PREFIX "WINPR_COMM")
|
||||
|
||||
if(UNIX AND NOT WIN32 AND NOT APPLE)
|
||||
if(UNIX AND NOT ANDROID AND NOT APPLE)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
comm.c
|
||||
comm.h
|
||||
|
@ -22,8 +22,6 @@
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -1378,19 +1376,6 @@ BOOL CommCloseHandle(HANDLE handle)
|
||||
if (!CommIsHandled(handle))
|
||||
return FALSE;
|
||||
|
||||
if (pComm->PendingEvents & SERIAL_EV_WINPR_WAITING)
|
||||
{
|
||||
ULONG WaitMask = 0;
|
||||
DWORD BytesReturned = 0;
|
||||
|
||||
/* ensures to gracefully stop the WAIT_ON_MASK's loop */
|
||||
if (!CommDeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK, &WaitMask, sizeof(ULONG), NULL,
|
||||
0, &BytesReturned, NULL))
|
||||
{
|
||||
CommLog_Print(WLOG_WARN, "failure to WAIT_ON_MASK's loop!");
|
||||
}
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&pComm->ReadLock);
|
||||
DeleteCriticalSection(&pComm->WriteLock);
|
||||
DeleteCriticalSection(&pComm->EventsLock);
|
||||
@ -1425,5 +1410,3 @@ int eventfd_write(int fd, eventfd_t value)
|
||||
return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
@ -545,5 +543,3 @@ return_false:
|
||||
LeaveCriticalSection(&pComm->WriteLock);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
@ -20,8 +20,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#include "comm_serial_sys.h"
|
||||
@ -40,14 +39,19 @@
|
||||
* request with a STATUS_SUCCESS status code.
|
||||
*/
|
||||
|
||||
static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
|
||||
static BOOL set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
static BOOL get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
|
||||
return TRUE;
|
||||
}
|
||||
@ -64,11 +68,15 @@ static const ULONG _SERCX2_SYS_SUPPORTED_EV_MASK =
|
||||
;
|
||||
|
||||
/* use Serial.sys for basis (not SerCx.sys) */
|
||||
static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
{
|
||||
ULONG possibleMask = 0;
|
||||
SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pWaitMask);
|
||||
WINPR_ASSERT(pSerialSys);
|
||||
|
||||
possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK;
|
||||
|
||||
if (possibleMask != *pWaitMask)
|
||||
@ -87,10 +95,14 @@ static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
return pSerialSys->set_wait_mask(pComm, pWaitMask);
|
||||
}
|
||||
|
||||
static BOOL _purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
static BOOL purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
{
|
||||
SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pPurgeMask);
|
||||
WINPR_ASSERT(pSerialSys);
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */
|
||||
|
||||
if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT))
|
||||
@ -113,14 +125,14 @@ static BOOL _purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
}
|
||||
|
||||
/* specific functions only */
|
||||
static SERIAL_DRIVER _SerCx2Sys = {
|
||||
static SERIAL_DRIVER SerCx2Sys = {
|
||||
.id = SerialDriverSerCx2Sys,
|
||||
.name = _T("SerCx2.sys"),
|
||||
.set_baud_rate = NULL,
|
||||
.get_baud_rate = NULL,
|
||||
.get_properties = NULL,
|
||||
.set_serial_chars = _set_serial_chars,
|
||||
.get_serial_chars = _get_serial_chars,
|
||||
.set_serial_chars = set_serial_chars,
|
||||
.get_serial_chars = get_serial_chars,
|
||||
.set_line_control = NULL,
|
||||
.get_line_control = NULL,
|
||||
.set_handflow = NULL,
|
||||
@ -132,11 +144,11 @@ static SERIAL_DRIVER _SerCx2Sys = {
|
||||
.set_rts = NULL,
|
||||
.clear_rts = NULL,
|
||||
.get_modemstatus = NULL,
|
||||
.set_wait_mask = _set_wait_mask,
|
||||
.set_wait_mask = set_wait_mask,
|
||||
.get_wait_mask = NULL,
|
||||
.wait_on_mask = NULL,
|
||||
.set_queue_size = NULL,
|
||||
.purge = _purge,
|
||||
.purge = purge,
|
||||
.get_commstatus = NULL,
|
||||
.set_break_on = NULL,
|
||||
.set_break_off = NULL,
|
||||
@ -150,51 +162,49 @@ static SERIAL_DRIVER _SerCx2Sys = {
|
||||
|
||||
SERIAL_DRIVER* SerCx2Sys_s(void)
|
||||
{
|
||||
/* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
|
||||
/* SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
|
||||
SERIAL_DRIVER* pSerialSys = SerialSys_s();
|
||||
SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
|
||||
if (!pSerialSys || !pSerCxSys)
|
||||
return NULL;
|
||||
|
||||
_SerCx2Sys.set_baud_rate = pSerialSys->set_baud_rate;
|
||||
_SerCx2Sys.get_baud_rate = pSerialSys->get_baud_rate;
|
||||
SerCx2Sys.set_baud_rate = pSerialSys->set_baud_rate;
|
||||
SerCx2Sys.get_baud_rate = pSerialSys->get_baud_rate;
|
||||
|
||||
_SerCx2Sys.get_properties = pSerialSys->get_properties;
|
||||
SerCx2Sys.get_properties = pSerialSys->get_properties;
|
||||
|
||||
_SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
|
||||
_SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
|
||||
SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
|
||||
SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
|
||||
|
||||
/* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really
|
||||
* required by SerCx2.sys http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx
|
||||
*/
|
||||
_SerCx2Sys.set_handflow = pSerialSys->set_handflow;
|
||||
_SerCx2Sys.get_handflow = pSerialSys->get_handflow;
|
||||
SerCx2Sys.set_handflow = pSerialSys->set_handflow;
|
||||
SerCx2Sys.get_handflow = pSerialSys->get_handflow;
|
||||
|
||||
_SerCx2Sys.set_timeouts = pSerialSys->set_timeouts;
|
||||
_SerCx2Sys.get_timeouts = pSerialSys->get_timeouts;
|
||||
SerCx2Sys.set_timeouts = pSerialSys->set_timeouts;
|
||||
SerCx2Sys.get_timeouts = pSerialSys->get_timeouts;
|
||||
|
||||
_SerCx2Sys.set_dtr = pSerialSys->set_dtr;
|
||||
_SerCx2Sys.clear_dtr = pSerialSys->clear_dtr;
|
||||
SerCx2Sys.set_dtr = pSerialSys->set_dtr;
|
||||
SerCx2Sys.clear_dtr = pSerialSys->clear_dtr;
|
||||
|
||||
_SerCx2Sys.set_rts = pSerialSys->set_rts;
|
||||
_SerCx2Sys.clear_rts = pSerialSys->clear_rts;
|
||||
SerCx2Sys.set_rts = pSerialSys->set_rts;
|
||||
SerCx2Sys.clear_rts = pSerialSys->clear_rts;
|
||||
|
||||
_SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
|
||||
SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
|
||||
|
||||
_SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
|
||||
_SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
|
||||
_SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
|
||||
SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
|
||||
SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
|
||||
SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
|
||||
|
||||
_SerCx2Sys.set_queue_size = pSerialSys->set_queue_size;
|
||||
SerCx2Sys.set_queue_size = pSerialSys->set_queue_size;
|
||||
|
||||
_SerCx2Sys.get_commstatus = pSerialSys->get_commstatus;
|
||||
SerCx2Sys.get_commstatus = pSerialSys->get_commstatus;
|
||||
|
||||
_SerCx2Sys.set_break_on = pSerialSys->set_break_on;
|
||||
_SerCx2Sys.set_break_off = pSerialSys->set_break_off;
|
||||
SerCx2Sys.set_break_on = pSerialSys->set_break_on;
|
||||
SerCx2Sys.set_break_off = pSerialSys->set_break_off;
|
||||
|
||||
_SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts;
|
||||
SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts;
|
||||
|
||||
return &_SerCx2Sys;
|
||||
return &SerCx2Sys;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
@ -20,8 +20,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if defined __linux__ && !defined ANDROID
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -156,8 +154,11 @@ static const speed_t _BAUD_TABLE[][3] = {
|
||||
{ BAUD_TABLE_END, 0, 0 }
|
||||
};
|
||||
|
||||
static BOOL _get_properties(WINPR_COMM* pComm, COMMPROP* pProperties)
|
||||
static BOOL commstatus_error(WINPR_COMM* pComm, const char* ctrl);
|
||||
|
||||
static BOOL get_properties(WINPR_COMM* pComm, COMMPROP* pProperties)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680684%28v=vs.85%29.aspx
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363189%28v=vs.85%29.aspx
|
||||
*/
|
||||
@ -220,12 +221,14 @@ static BOOL _get_properties(WINPR_COMM* pComm, COMMPROP* pProperties)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_baud_rate(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate)
|
||||
static BOOL set_baud_rate(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate)
|
||||
{
|
||||
speed_t newSpeed = 0;
|
||||
struct termios futureState;
|
||||
struct termios futureState = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pBaudRate);
|
||||
|
||||
ZeroMemory(&futureState, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, &futureState) <
|
||||
0) /* NB: preserves current settings not directly handled by the Communication Functions */
|
||||
{
|
||||
@ -264,12 +267,14 @@ static BOOL _set_baud_rate(WINPR_COMM* pComm, const SERIAL_BAUD_RATE* pBaudRate)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL _get_baud_rate(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate)
|
||||
static BOOL get_baud_rate(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate)
|
||||
{
|
||||
speed_t currentSpeed = 0;
|
||||
struct termios currentState;
|
||||
struct termios currentState = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pBaudRate);
|
||||
|
||||
ZeroMemory(¤tState, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, ¤tState) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -302,25 +307,20 @@ static BOOL _get_baud_rate(WINPR_COMM* pComm, SERIAL_BAUD_RATE* pBaudRate)
|
||||
* ERROR_INVALID_PARAMETER when Xon and Xoff chars are the same;
|
||||
* ERROR_NOT_SUPPORTED
|
||||
*/
|
||||
static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
|
||||
static BOOL set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
struct termios upcomingTermios;
|
||||
struct termios upcomingTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
ZeroMemory(&upcomingTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pSerialChars->XonChar == pSerialChars->XoffChar)
|
||||
{
|
||||
/* https://msdn.microsoft.com/en-us/library/windows/hardware/ff546688?v=vs.85.aspx */
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* termios(3): (..) above symbolic subscript values are all
|
||||
* different, except that VTIME, VMIN may have the same value
|
||||
* as VEOL, VEOF, respectively. In noncanonical mode the
|
||||
@ -344,7 +344,7 @@ static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChar
|
||||
* get the prefix the prefix \377 \0
|
||||
*/
|
||||
|
||||
/* FIXME: see also: _set_handflow() */
|
||||
/* FIXME: see also: set_handflow() */
|
||||
if (pSerialChars->ErrorChar != '\0')
|
||||
{
|
||||
CommLog_Print(WLOG_WARN, "ErrorChar 0x%02" PRIX8 " ('%c') cannot be set (unsupported).\n",
|
||||
@ -353,7 +353,7 @@ static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChar
|
||||
result = FALSE; /* but keep on */
|
||||
}
|
||||
|
||||
/* FIXME: see also: _set_handflow() */
|
||||
/* FIXME: see also: set_handflow() */
|
||||
if (pSerialChars->BreakChar != '\0')
|
||||
{
|
||||
CommLog_Print(WLOG_WARN, "BreakChar 0x%02" PRIX8 " ('%c') cannot be set (unsupported).\n",
|
||||
@ -381,11 +381,13 @@ static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChar
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
static BOOL get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
{
|
||||
struct termios currentTermios;
|
||||
struct termios currentTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSerialChars);
|
||||
|
||||
ZeroMemory(¤tTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, ¤tTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -400,7 +402,7 @@ static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
|
||||
/* BreakChar unsupported */
|
||||
|
||||
/* FIXME: see also: _set_serial_chars() */
|
||||
/* FIXME: see also: set_serial_chars() */
|
||||
/* EventChar */
|
||||
|
||||
pSerialChars->XonChar = currentTermios.c_cc[VSTART];
|
||||
@ -410,10 +412,13 @@ static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_line_control(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLineControl)
|
||||
static BOOL set_line_control(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLineControl)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
struct termios upcomingTermios;
|
||||
struct termios upcomingTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pLineControl);
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx
|
||||
*
|
||||
@ -424,7 +429,6 @@ static BOOL _set_line_control(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLin
|
||||
* this issue. At least produce a warning message?
|
||||
*/
|
||||
|
||||
ZeroMemory(&upcomingTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -525,11 +529,13 @@ static BOOL _set_line_control(WINPR_COMM* pComm, const SERIAL_LINE_CONTROL* pLin
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL _get_line_control(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineControl)
|
||||
static BOOL get_line_control(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineControl)
|
||||
{
|
||||
struct termios currentTermios;
|
||||
struct termios currentTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pLineControl);
|
||||
|
||||
ZeroMemory(¤tTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, ¤tTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -571,12 +577,14 @@ static BOOL _get_line_control(WINPR_COMM* pComm, SERIAL_LINE_CONTROL* pLineContr
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
|
||||
static BOOL set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
|
||||
{
|
||||
BOOL result = TRUE;
|
||||
struct termios upcomingTermios;
|
||||
struct termios upcomingTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pHandflow);
|
||||
|
||||
ZeroMemory(&upcomingTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, &upcomingTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -771,11 +779,13 @@ static BOOL _set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL _get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
|
||||
static BOOL get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
|
||||
{
|
||||
struct termios currentTermios;
|
||||
struct termios currentTermios = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pHandflow);
|
||||
|
||||
ZeroMemory(¤tTermios, sizeof(struct termios));
|
||||
if (tcgetattr(pComm->fd, ¤tTermios) < 0)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
@ -839,8 +849,11 @@ static BOOL _get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_timeouts(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts)
|
||||
static BOOL set_timeouts(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pTimeouts);
|
||||
|
||||
/* NB: timeouts are applied on system during read/write I/O */
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx */
|
||||
@ -874,8 +887,11 @@ static BOOL _set_timeouts(WINPR_COMM* pComm, const SERIAL_TIMEOUTS* pTimeouts)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _get_timeouts(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts)
|
||||
static BOOL get_timeouts(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pTimeouts);
|
||||
|
||||
pTimeouts->ReadIntervalTimeout = pComm->timeouts.ReadIntervalTimeout;
|
||||
pTimeouts->ReadTotalTimeoutMultiplier = pComm->timeouts.ReadTotalTimeoutMultiplier;
|
||||
pTimeouts->ReadTotalTimeoutConstant = pComm->timeouts.ReadTotalTimeoutConstant;
|
||||
@ -885,8 +901,10 @@ static BOOL _get_timeouts(WINPR_COMM* pComm, SERIAL_TIMEOUTS* pTimeouts)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
static BOOL set_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
if (ioctl(pComm->fd, TIOCMBIS, &lines) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -899,8 +917,10 @@ static BOOL _set_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _clear_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
static BOOL clear_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
if (ioctl(pComm->fd, TIOCMBIC, &lines) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -913,10 +933,12 @@ static BOOL _clear_lines(WINPR_COMM* pComm, UINT32 lines)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_dtr(WINPR_COMM* pComm)
|
||||
static BOOL set_dtr(WINPR_COMM* pComm)
|
||||
{
|
||||
SERIAL_HANDFLOW handflow;
|
||||
if (!_get_handflow(pComm, &handflow))
|
||||
SERIAL_HANDFLOW handflow = { 0 };
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
if (!get_handflow(pComm, &handflow))
|
||||
return FALSE;
|
||||
|
||||
/* SERIAL_DTR_HANDSHAKE not supported as of today */
|
||||
@ -928,13 +950,15 @@ static BOOL _set_dtr(WINPR_COMM* pComm)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _set_lines(pComm, TIOCM_DTR);
|
||||
return set_lines(pComm, TIOCM_DTR);
|
||||
}
|
||||
|
||||
static BOOL _clear_dtr(WINPR_COMM* pComm)
|
||||
static BOOL clear_dtr(WINPR_COMM* pComm)
|
||||
{
|
||||
SERIAL_HANDFLOW handflow;
|
||||
if (!_get_handflow(pComm, &handflow))
|
||||
SERIAL_HANDFLOW handflow = { 0 };
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
if (!get_handflow(pComm, &handflow))
|
||||
return FALSE;
|
||||
|
||||
/* SERIAL_DTR_HANDSHAKE not supported as of today */
|
||||
@ -946,13 +970,15 @@ static BOOL _clear_dtr(WINPR_COMM* pComm)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _clear_lines(pComm, TIOCM_DTR);
|
||||
return clear_lines(pComm, TIOCM_DTR);
|
||||
}
|
||||
|
||||
static BOOL _set_rts(WINPR_COMM* pComm)
|
||||
static BOOL set_rts(WINPR_COMM* pComm)
|
||||
{
|
||||
SERIAL_HANDFLOW handflow;
|
||||
if (!_get_handflow(pComm, &handflow))
|
||||
SERIAL_HANDFLOW handflow = { 0 };
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
if (!get_handflow(pComm, &handflow))
|
||||
return FALSE;
|
||||
|
||||
if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
|
||||
@ -961,13 +987,14 @@ static BOOL _set_rts(WINPR_COMM* pComm)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _set_lines(pComm, TIOCM_RTS);
|
||||
return set_lines(pComm, TIOCM_RTS);
|
||||
}
|
||||
|
||||
static BOOL _clear_rts(WINPR_COMM* pComm)
|
||||
static BOOL clear_rts(WINPR_COMM* pComm)
|
||||
{
|
||||
SERIAL_HANDFLOW handflow;
|
||||
if (!_get_handflow(pComm, &handflow))
|
||||
SERIAL_HANDFLOW handflow = { 0 };
|
||||
WINPR_ASSERT(pComm);
|
||||
if (!get_handflow(pComm, &handflow))
|
||||
return FALSE;
|
||||
|
||||
if (handflow.FlowReplace & SERIAL_RTS_HANDSHAKE)
|
||||
@ -976,35 +1003,23 @@ static BOOL _clear_rts(WINPR_COMM* pComm)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return _clear_lines(pComm, TIOCM_RTS);
|
||||
return clear_lines(pComm, TIOCM_RTS);
|
||||
}
|
||||
|
||||
static BOOL _get_modemstatus(WINPR_COMM* pComm, ULONG* pRegister)
|
||||
static BOOL get_modemstatus(WINPR_COMM* pComm, ULONG* pRegister)
|
||||
{
|
||||
UINT32 lines = 0;
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pRegister);
|
||||
|
||||
*pRegister = 0;
|
||||
if (ioctl(pComm->fd, TIOCMGET, &lines) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
return FALSE;
|
||||
if (!commstatus_error(pComm, "TIOCMGET"))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ZeroMemory(pRegister, sizeof(ULONG));
|
||||
|
||||
/* FIXME: Is the last read of the MSR register available or
|
||||
* cached somewhere? Not quite sure we need to return the 4
|
||||
* LSBits anyway. A direct access to the register -- which
|
||||
* would reset the register -- is likely not expected from
|
||||
* this function.
|
||||
*/
|
||||
|
||||
/* #define SERIAL_MSR_DCTS 0x01 */
|
||||
/* #define SERIAL_MSR_DDSR 0x02 */
|
||||
/* #define SERIAL_MSR_TERI 0x04 */
|
||||
/* #define SERIAL_MSR_DDCD 0x08 */
|
||||
|
||||
if (lines & TIOCM_CTS)
|
||||
*pRegister |= SERIAL_MSR_CTS;
|
||||
if (lines & TIOCM_DSR)
|
||||
@ -1018,7 +1033,7 @@ static BOOL _get_modemstatus(WINPR_COMM* pComm, ULONG* pRegister)
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
|
||||
static const ULONG _SERIAL_SYS_SUPPORTED_EV_MASK =
|
||||
static const ULONG SERIAL_SYS_SUPPORTED_EV_MASK =
|
||||
SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR |
|
||||
SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING |
|
||||
/* SERIAL_EV_PERR | */
|
||||
@ -1037,7 +1052,7 @@ static BOOL is_wait_set(WINPR_COMM* pComm)
|
||||
return isWaiting;
|
||||
}
|
||||
|
||||
static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
static BOOL set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
{
|
||||
ULONG possibleMask = 0;
|
||||
|
||||
@ -1055,9 +1070,13 @@ static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
pComm->PendingEvents |= SERIAL_EV_WINPR_STOP;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
|
||||
/* waiting the end of the pending _wait_on_mask() */
|
||||
/* waiting the end of the pending wait_on_mask() */
|
||||
while (is_wait_set(pComm))
|
||||
Sleep(10); /* 10ms */
|
||||
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_STOP;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
}
|
||||
|
||||
/* NB: ensure to leave the critical section before to return */
|
||||
@ -1069,27 +1088,18 @@ static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
|
||||
if (ioctl(pComm->fd, TIOCGICOUNT, &(pComm->counters)) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
|
||||
if (pComm->permissive)
|
||||
if (!commstatus_error(pComm, "TIOCGICOUNT"))
|
||||
{
|
||||
/* counters could not be reset but keep on */
|
||||
ZeroMemory(&(pComm->counters), sizeof(struct serial_icounter_struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return FALSE;
|
||||
}
|
||||
ZeroMemory(&(pComm->counters), sizeof(struct serial_icounter_struct));
|
||||
}
|
||||
|
||||
pComm->PendingEvents = 0;
|
||||
}
|
||||
|
||||
possibleMask = *pWaitMask & _SERIAL_SYS_SUPPORTED_EV_MASK;
|
||||
possibleMask = *pWaitMask & SERIAL_SYS_SUPPORTED_EV_MASK;
|
||||
|
||||
if (possibleMask != *pWaitMask)
|
||||
{
|
||||
@ -1111,14 +1121,20 @@ static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _get_wait_mask(WINPR_COMM* pComm, ULONG* pWaitMask)
|
||||
static BOOL get_wait_mask(WINPR_COMM* pComm, ULONG* pWaitMask)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pWaitMask);
|
||||
|
||||
*pWaitMask = pComm->WaitEventMask;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_queue_size(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSize)
|
||||
static BOOL set_queue_size(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSize)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pQueueSize);
|
||||
|
||||
if ((pQueueSize->InSize <= N_TTY_BUF_SIZE) && (pQueueSize->OutSize <= N_TTY_BUF_SIZE))
|
||||
return TRUE; /* nothing to do */
|
||||
|
||||
@ -1140,8 +1156,11 @@ static BOOL _set_queue_size(WINPR_COMM* pComm, const SERIAL_QUEUE_SIZE* pQueueSi
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL _purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
static BOOL purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pPurgeMask);
|
||||
|
||||
if ((*pPurgeMask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR |
|
||||
SERIAL_PURGE_RXCLEAR)) > 0)
|
||||
{
|
||||
@ -1220,42 +1239,56 @@ static BOOL _purge(WINPR_COMM* pComm, const ULONG* pPurgeMask)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* NB: _get_commstatus also produces most of the events consumed by _wait_on_mask(). Exceptions:
|
||||
BOOL commstatus_error(WINPR_COMM* pComm, const char* ctrl)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "%s ioctl failed, errno=[%d] %s.", ctrl, errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
|
||||
if (!pComm->permissive)
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* NB: get_commstatus also produces most of the events consumed by wait_on_mask(). Exceptions:
|
||||
* - SERIAL_EV_RXFLAG: FIXME: once EventChar supported
|
||||
*
|
||||
*/
|
||||
static BOOL _get_commstatus(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus)
|
||||
static BOOL get_commstatus(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
/* http://msdn.microsoft.com/en-us/library/jj673022%28v=vs.85%29.aspx */
|
||||
|
||||
struct serial_icounter_struct currentCounters;
|
||||
struct serial_icounter_struct currentCounters = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pCommstatus);
|
||||
|
||||
/* NB: ensure to leave the critical section before to return */
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
|
||||
ZeroMemory(pCommstatus, sizeof(SERIAL_STATUS));
|
||||
|
||||
ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct));
|
||||
ULONG status = 0;
|
||||
if (!get_modemstatus(pComm, &status))
|
||||
{
|
||||
if (!commstatus_error(pComm, "TIOCGICOUNT"))
|
||||
goto fail;
|
||||
/* Errors and events based on counters could not be
|
||||
* detected but keep on.
|
||||
*/
|
||||
SetLastError(0);
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (ioctl(pComm->fd, TIOCGICOUNT, ¤tCounters) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCGICOUNT ioctl failed, errno=[%d] %s.", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
CommLog_Print(WLOG_WARN, " could not read counters.");
|
||||
|
||||
if (pComm->permissive)
|
||||
{
|
||||
/* Errors and events based on counters could not be
|
||||
* detected but keep on.
|
||||
*/
|
||||
ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return FALSE;
|
||||
}
|
||||
if (!commstatus_error(pComm, "TIOCGICOUNT"))
|
||||
goto fail;
|
||||
ZeroMemory(¤tCounters, sizeof(struct serial_icounter_struct));
|
||||
}
|
||||
|
||||
/* NB: preferred below (currentCounters.* != pComm->counters.*) over (currentCounters.* >
|
||||
@ -1310,26 +1343,16 @@ static BOOL _get_commstatus(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus)
|
||||
|
||||
if (ioctl(pComm->fd, TIOCINQ, &(pCommstatus->AmountInInQueue)) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCINQ ioctl failed, errno=[%d] %s", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return FALSE;
|
||||
if (!commstatus_error(pComm, "TIOCINQ"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* AmountInOutQueue */
|
||||
|
||||
if (ioctl(pComm->fd, TIOCOUTQ, &(pCommstatus->AmountInOutQueue)) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCOUTQ ioctl failed, errno=[%d] %s", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return FALSE;
|
||||
if (!commstatus_error(pComm, "TIOCOUTQ"))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* BOOLEAN EofReceived; FIXME: once EofChar supported */
|
||||
@ -1388,17 +1411,20 @@ static BOOL _get_commstatus(WINPR_COMM* pComm, SERIAL_STATUS* pCommstatus)
|
||||
|
||||
pComm->counters = currentCounters;
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return TRUE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL _refresh_PendingEvents(WINPR_COMM* pComm)
|
||||
static BOOL refresh_PendingEvents(WINPR_COMM* pComm)
|
||||
{
|
||||
SERIAL_STATUS serialStatus;
|
||||
SERIAL_STATUS serialStatus = { 0 };
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
|
||||
/* NB: also ensures PendingEvents to be up to date */
|
||||
ZeroMemory(&serialStatus, sizeof(SERIAL_STATUS));
|
||||
if (!_get_commstatus(pComm, &serialStatus))
|
||||
if (!get_commstatus(pComm, &serialStatus))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@ -1406,8 +1432,11 @@ static BOOL _refresh_PendingEvents(WINPR_COMM* pComm)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void _consume_event(WINPR_COMM* pComm, ULONG* pOutputMask, ULONG event)
|
||||
static void consume_event(WINPR_COMM* pComm, ULONG* pOutputMask, ULONG event)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pOutputMask);
|
||||
|
||||
if ((pComm->WaitEventMask & event) && (pComm->PendingEvents & event))
|
||||
{
|
||||
pComm->PendingEvents &= ~event; /* consumed */
|
||||
@ -1415,11 +1444,20 @@ static void _consume_event(WINPR_COMM* pComm, ULONG* pOutputMask, ULONG event)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: see also: _set_wait_mask()
|
||||
*/
|
||||
static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
static BOOL unlock_return(WINPR_COMM* pComm, BOOL res)
|
||||
{
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_WAITING;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: see also: set_wait_mask()
|
||||
*/
|
||||
static BOOL wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(*pOutputMask == 0);
|
||||
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
@ -1428,22 +1466,15 @@ static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
/* NB: EventsLock also used by _refresh_PendingEvents() */
|
||||
if (!_refresh_PendingEvents(pComm))
|
||||
{
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_WAITING;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return FALSE;
|
||||
}
|
||||
/* NB: EventsLock also used by refresh_PendingEvents() */
|
||||
if (!refresh_PendingEvents(pComm))
|
||||
return unlock_return(pComm, FALSE);
|
||||
|
||||
/* NB: ensure to leave the critical section before to return */
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
|
||||
if (pComm->PendingEvents & SERIAL_EV_WINPR_STOP)
|
||||
{
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_STOP;
|
||||
|
||||
/* pOutputMask must remain empty but should
|
||||
* not have been modified.
|
||||
*
|
||||
@ -1451,21 +1482,20 @@ static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
*/
|
||||
WINPR_ASSERT(*pOutputMask == 0);
|
||||
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_WAITING;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return TRUE;
|
||||
return unlock_return(pComm, TRUE);
|
||||
}
|
||||
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_CTS);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_DSR);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_RLSD);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_BREAK);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_ERR);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_RING);
|
||||
_consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_RXCHAR);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_RXFLAG);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_TXEMPTY);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_CTS);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_DSR);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_RLSD);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_BREAK);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_ERR);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_RING);
|
||||
consume_event(pComm, pOutputMask, SERIAL_EV_RX80FULL);
|
||||
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
|
||||
@ -1473,14 +1503,7 @@ static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
* not pOutputMask */
|
||||
|
||||
if (*pOutputMask != 0)
|
||||
{
|
||||
/* at least an event occurred */
|
||||
|
||||
EnterCriticalSection(&pComm->EventsLock);
|
||||
pComm->PendingEvents &= ~SERIAL_EV_WINPR_WAITING;
|
||||
LeaveCriticalSection(&pComm->EventsLock);
|
||||
return TRUE;
|
||||
}
|
||||
return unlock_return(pComm, TRUE);
|
||||
|
||||
/* waiting for a modification of PendingEvents.
|
||||
*
|
||||
@ -1492,10 +1515,13 @@ static BOOL _wait_on_mask(WINPR_COMM* pComm, ULONG* pOutputMask)
|
||||
|
||||
Sleep(100); /* 100 ms */
|
||||
}
|
||||
|
||||
return unlock_return(pComm, FALSE);
|
||||
}
|
||||
|
||||
static BOOL _set_break_on(WINPR_COMM* pComm)
|
||||
static BOOL set_break_on(WINPR_COMM* pComm)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
if (ioctl(pComm->fd, TIOCSBRK, NULL) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -1508,8 +1534,9 @@ static BOOL _set_break_on(WINPR_COMM* pComm)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_break_off(WINPR_COMM* pComm)
|
||||
static BOOL set_break_off(WINPR_COMM* pComm)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
if (ioctl(pComm->fd, TIOCCBRK, NULL) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -1522,8 +1549,9 @@ static BOOL _set_break_off(WINPR_COMM* pComm)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_xoff(WINPR_COMM* pComm)
|
||||
static BOOL set_xoff(WINPR_COMM* pComm)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
if (tcflow(pComm->fd, TCIOFF) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -1536,8 +1564,9 @@ static BOOL _set_xoff(WINPR_COMM* pComm)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _set_xon(WINPR_COMM* pComm)
|
||||
static BOOL set_xon(WINPR_COMM* pComm)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
if (tcflow(pComm->fd, TCION) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
@ -1550,17 +1579,15 @@ static BOOL _set_xon(WINPR_COMM* pComm)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _get_dtrrts(WINPR_COMM* pComm, ULONG* pMask)
|
||||
static BOOL get_dtrrts(WINPR_COMM* pComm, ULONG* pMask)
|
||||
{
|
||||
UINT32 lines = 0;
|
||||
if (ioctl(pComm->fd, TIOCMGET, &lines) < 0)
|
||||
{
|
||||
char ebuffer[256] = { 0 };
|
||||
CommLog_Print(WLOG_WARN, "TIOCMGET ioctl failed, errno=[%d] %s", errno,
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
SetLastError(ERROR_IO_DEVICE);
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pMask);
|
||||
|
||||
if (!get_modemstatus(pComm, &lines))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*pMask = 0;
|
||||
|
||||
@ -1572,8 +1599,11 @@ static BOOL _get_dtrrts(WINPR_COMM* pComm, ULONG* pMask)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _config_size(WINPR_COMM* pComm, ULONG* pSize)
|
||||
static BOOL config_size(WINPR_COMM* pComm, ULONG* pSize)
|
||||
{
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pSize);
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/ff546548%28v=vs.85%29.aspx */
|
||||
if (!pSize)
|
||||
return FALSE;
|
||||
@ -1582,15 +1612,18 @@ static BOOL _config_size(WINPR_COMM* pComm, ULONG* pSize)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL _immediate_char(WINPR_COMM* pComm, const UCHAR* pChar)
|
||||
static BOOL immediate_char(WINPR_COMM* pComm, const UCHAR* pChar)
|
||||
{
|
||||
BOOL result = 0;
|
||||
DWORD nbBytesWritten = -1;
|
||||
|
||||
WINPR_ASSERT(pComm);
|
||||
WINPR_ASSERT(pChar);
|
||||
|
||||
/* FIXME: CommWriteFile uses a critical section, shall it be
|
||||
* interrupted?
|
||||
*
|
||||
* FIXME: see also _get_commstatus()'s WaitForImmediate boolean
|
||||
* FIXME: see also get_commstatus()'s WaitForImmediate boolean
|
||||
*/
|
||||
|
||||
result = CommWriteFile(pComm, pChar, 1, &nbBytesWritten, NULL);
|
||||
@ -1600,50 +1633,48 @@ static BOOL _immediate_char(WINPR_COMM* pComm, const UCHAR* pChar)
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL _reset_device(WINPR_COMM* pComm)
|
||||
static BOOL reset_device(WINPR_COMM* pComm)
|
||||
{
|
||||
/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static SERIAL_DRIVER _SerialSys = {
|
||||
static SERIAL_DRIVER SerialSys = {
|
||||
.id = SerialDriverSerialSys,
|
||||
.name = _T("Serial.sys"),
|
||||
.set_baud_rate = _set_baud_rate,
|
||||
.get_baud_rate = _get_baud_rate,
|
||||
.get_properties = _get_properties,
|
||||
.set_serial_chars = _set_serial_chars,
|
||||
.get_serial_chars = _get_serial_chars,
|
||||
.set_line_control = _set_line_control,
|
||||
.get_line_control = _get_line_control,
|
||||
.set_handflow = _set_handflow,
|
||||
.get_handflow = _get_handflow,
|
||||
.set_timeouts = _set_timeouts,
|
||||
.get_timeouts = _get_timeouts,
|
||||
.set_dtr = _set_dtr,
|
||||
.clear_dtr = _clear_dtr,
|
||||
.set_rts = _set_rts,
|
||||
.clear_rts = _clear_rts,
|
||||
.get_modemstatus = _get_modemstatus,
|
||||
.set_wait_mask = _set_wait_mask,
|
||||
.get_wait_mask = _get_wait_mask,
|
||||
.wait_on_mask = _wait_on_mask,
|
||||
.set_queue_size = _set_queue_size,
|
||||
.purge = _purge,
|
||||
.get_commstatus = _get_commstatus,
|
||||
.set_break_on = _set_break_on,
|
||||
.set_break_off = _set_break_off,
|
||||
.set_xoff = _set_xoff,
|
||||
.set_xon = _set_xon,
|
||||
.get_dtrrts = _get_dtrrts,
|
||||
.config_size = _config_size,
|
||||
.immediate_char = _immediate_char,
|
||||
.reset_device = _reset_device,
|
||||
.set_baud_rate = set_baud_rate,
|
||||
.get_baud_rate = get_baud_rate,
|
||||
.get_properties = get_properties,
|
||||
.set_serial_chars = set_serial_chars,
|
||||
.get_serial_chars = get_serial_chars,
|
||||
.set_line_control = set_line_control,
|
||||
.get_line_control = get_line_control,
|
||||
.set_handflow = set_handflow,
|
||||
.get_handflow = get_handflow,
|
||||
.set_timeouts = set_timeouts,
|
||||
.get_timeouts = get_timeouts,
|
||||
.set_dtr = set_dtr,
|
||||
.clear_dtr = clear_dtr,
|
||||
.set_rts = set_rts,
|
||||
.clear_rts = clear_rts,
|
||||
.get_modemstatus = get_modemstatus,
|
||||
.set_wait_mask = set_wait_mask,
|
||||
.get_wait_mask = get_wait_mask,
|
||||
.wait_on_mask = wait_on_mask,
|
||||
.set_queue_size = set_queue_size,
|
||||
.purge = purge,
|
||||
.get_commstatus = get_commstatus,
|
||||
.set_break_on = set_break_on,
|
||||
.set_break_off = set_break_off,
|
||||
.set_xoff = set_xoff,
|
||||
.set_xon = set_xon,
|
||||
.get_dtrrts = get_dtrrts,
|
||||
.config_size = config_size,
|
||||
.immediate_char = immediate_char,
|
||||
.reset_device = reset_device,
|
||||
};
|
||||
|
||||
SERIAL_DRIVER* SerialSys_s(void)
|
||||
{
|
||||
return &_SerialSys;
|
||||
return &SerialSys;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
Loading…
Reference in New Issue
Block a user