hardend serial channel
This commit is contained in:
parent
dc68bdfce5
commit
62d7b1e4df
@ -40,6 +40,9 @@
|
|||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
#include <freerdp/channels/rdpdr.h>
|
#include <freerdp/channels/rdpdr.h>
|
||||||
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
|
#define TAG CHANNELS_TAG("serial.client")
|
||||||
|
|
||||||
/* TODO: all #ifdef __linux__ could be removed once only some generic
|
/* TODO: all #ifdef __linux__ could be removed once only some generic
|
||||||
* functions will be used. Replace CommReadFile by ReadFile,
|
* functions will be used. Replace CommReadFile by ReadFile,
|
||||||
@ -226,7 +229,7 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
static WIN32ERROR serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
UINT32 Length;
|
UINT32 Length;
|
||||||
UINT64 Offset;
|
UINT64 Offset;
|
||||||
@ -273,11 +276,17 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
|
|
||||||
if (nbRead > 0)
|
if (nbRead > 0)
|
||||||
{
|
{
|
||||||
Stream_EnsureRemainingCapacity(irp->output, nbRead);
|
if (!Stream_EnsureRemainingCapacity(irp->output, nbRead))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||||
|
free(buffer);
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
Stream_Write(irp->output, buffer, nbRead); /* ReadData */
|
Stream_Write(irp->output, buffer, nbRead); /* ReadData */
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
@ -318,7 +327,7 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
static WIN32ERROR serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
UINT32 IoControlCode;
|
UINT32 IoControlCode;
|
||||||
UINT32 InputBufferLength;
|
UINT32 InputBufferLength;
|
||||||
@ -376,7 +385,14 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
|
|
||||||
if (BytesReturned > 0)
|
if (BytesReturned > 0)
|
||||||
{
|
{
|
||||||
Stream_EnsureRemainingCapacity(irp->output, BytesReturned);
|
if (!Stream_EnsureRemainingCapacity(irp->output, BytesReturned))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||||
|
free(InputBuffer);
|
||||||
|
free(OutputBuffer);
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
|
Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
|
||||||
}
|
}
|
||||||
/* FIXME: Why at least Windows 2008R2 gets lost with this
|
/* FIXME: Why at least Windows 2008R2 gets lost with this
|
||||||
@ -390,10 +406,12 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
|
|
||||||
free(InputBuffer);
|
free(InputBuffer);
|
||||||
free(OutputBuffer);
|
free(OutputBuffer);
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
static WIN32ERROR serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||||
{
|
{
|
||||||
|
WIN32ERROR error = CHANNEL_RC_OK;
|
||||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
|
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
|
||||||
irp->MajorFunction, irp->MinorFunction);
|
irp->MajorFunction, irp->MinorFunction);
|
||||||
|
|
||||||
@ -408,7 +426,8 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_READ:
|
case IRP_MJ_READ:
|
||||||
serial_process_irp_read(serial, irp);
|
if ((error = serial_process_irp_read(serial, irp)))
|
||||||
|
WLog_ERR(TAG, "serial_process_irp_read failed with error %lu!", error);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_WRITE:
|
case IRP_MJ_WRITE:
|
||||||
@ -416,22 +435,26 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IRP_MJ_DEVICE_CONTROL:
|
case IRP_MJ_DEVICE_CONTROL:
|
||||||
serial_process_irp_device_control(serial, irp);
|
if ((error = serial_process_irp_device_control(serial, irp)))
|
||||||
|
WLog_ERR(TAG, "serial_process_irp_device_control failed with error %lu!", error);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* irp_thread_func(void* arg)
|
static void* irp_thread_func(void* arg)
|
||||||
{
|
{
|
||||||
IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg;
|
IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg;
|
||||||
|
WIN32ERROR error;
|
||||||
|
|
||||||
/* blocks until the end of the request */
|
/* blocks until the end of the request */
|
||||||
serial_process_irp(data->serial, data->irp);
|
if ((error = serial_process_irp(data->serial, data->irp)))
|
||||||
|
WLog_ERR(TAG, "serial_process_irp failed with error %lu", error);
|
||||||
|
|
||||||
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
|
||||||
data->serial->IrpThreadToBeTerminatedCount++;
|
data->serial->IrpThreadToBeTerminatedCount++;
|
||||||
@ -680,14 +703,14 @@ static void* serial_thread_func(void* arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void serial_irp_request(DEVICE* device, IRP* irp)
|
static WIN32ERROR serial_irp_request(DEVICE* device, IRP* irp)
|
||||||
{
|
{
|
||||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
||||||
|
|
||||||
assert(irp != NULL);
|
assert(irp != NULL);
|
||||||
|
|
||||||
if (irp == NULL)
|
if (irp == NULL)
|
||||||
return;
|
return CHANNEL_RC_OK;
|
||||||
|
|
||||||
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
|
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
|
||||||
* allows the server to send multiple simultaneous read or
|
* allows the server to send multiple simultaneous read or
|
||||||
@ -695,6 +718,7 @@ static void serial_irp_request(DEVICE* device, IRP* irp)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL);
|
MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL);
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -726,7 +750,7 @@ static void serial_free(DEVICE* device)
|
|||||||
#define DeviceServiceEntry serial_DeviceServiceEntry
|
#define DeviceServiceEntry serial_DeviceServiceEntry
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
WIN32ERROR DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||||
{
|
{
|
||||||
char* name;
|
char* name;
|
||||||
char* path;
|
char* path;
|
||||||
@ -736,6 +760,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
int i, len;
|
int i, len;
|
||||||
SERIAL_DEVICE* serial;
|
SERIAL_DEVICE* serial;
|
||||||
#endif /* __linux__ */
|
#endif /* __linux__ */
|
||||||
|
WIN32ERROR error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
device = (RDPDR_SERIAL*) pEntryPoints->device;
|
device = (RDPDR_SERIAL*) pEntryPoints->device;
|
||||||
name = device->Name;
|
name = device->Name;
|
||||||
@ -745,7 +770,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
if (!name || (name[0] == '*'))
|
if (!name || (name[0] == '*'))
|
||||||
{
|
{
|
||||||
/* TODO: implement auto detection of serial ports */
|
/* TODO: implement auto detection of serial ports */
|
||||||
return 0;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((name && name[0]) && (path && path[0]))
|
if ((name && name[0]) && (path && path[0]))
|
||||||
@ -759,7 +784,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
#ifndef __linux__ /* to be removed */
|
#ifndef __linux__ /* to be removed */
|
||||||
|
|
||||||
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
|
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
|
||||||
return -1;
|
return CHANNEL_RC_INITIALIZATION_ERROR;
|
||||||
|
|
||||||
#else /* __linux __ */
|
#else /* __linux __ */
|
||||||
|
|
||||||
@ -767,12 +792,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
|
|
||||||
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
|
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
|
||||||
{
|
{
|
||||||
return -1;
|
WLog_ERR(TAG, "DefineCommDevice failed!");
|
||||||
|
return ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
|
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
|
||||||
if (!serial)
|
if (!serial)
|
||||||
return -1;
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
serial->log = log;
|
serial->log = log;
|
||||||
|
|
||||||
@ -783,6 +812,12 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
|
|
||||||
len = strlen(name);
|
len = strlen(name);
|
||||||
serial->device.data = Stream_New(NULL, len + 1);
|
serial->device.data = Stream_New(NULL, len + 1);
|
||||||
|
if (!serial->device.data)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i <= len; i++)
|
for (i = 0; i <= len; i++)
|
||||||
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
|
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
|
||||||
@ -828,22 +863,49 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
|||||||
/* TODO: implement auto detection of the server's serial driver */
|
/* TODO: implement auto detection of the server's serial driver */
|
||||||
|
|
||||||
serial->MainIrpQueue = MessageQueue_New(NULL);
|
serial->MainIrpQueue = MessageQueue_New(NULL);
|
||||||
|
if (!serial->MainIrpQueue)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "MessageQueue_New failed!");
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
/* IrpThreads content only modified by create_irp_thread() */
|
/* IrpThreads content only modified by create_irp_thread() */
|
||||||
serial->IrpThreads = ListDictionary_New(FALSE);
|
serial->IrpThreads = ListDictionary_New(FALSE);
|
||||||
|
if(!serial->IrpThreads)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
||||||
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
serial->IrpThreadToBeTerminatedCount = 0;
|
serial->IrpThreadToBeTerminatedCount = 0;
|
||||||
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
|
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
|
||||||
|
|
||||||
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
|
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %lu!", error);
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
serial->MainThread = CreateThread(NULL,
|
if (!(serial->MainThread = CreateThread(NULL,
|
||||||
0,
|
0,
|
||||||
(LPTHREAD_START_ROUTINE) serial_thread_func,
|
(LPTHREAD_START_ROUTINE) serial_thread_func,
|
||||||
(void*) serial,
|
(void*) serial,
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL)))
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "CreateThread failed!");
|
||||||
|
error = ERROR_INTERNAL_ERROR;
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
#endif /* __linux __ */
|
#endif /* __linux __ */
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return error;
|
||||||
|
error_out:
|
||||||
|
ListDictionary_Free(serial->IrpThreads);
|
||||||
|
MessageQueue_Free(serial->MainIrpQueue);
|
||||||
|
Stream_Free(serial->device.data, TRUE);
|
||||||
|
free(serial);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user