Merge pull request #1764 from awakecoding/ports
Serial Port Improvements
This commit is contained in:
commit
8bf5559f51
@ -171,6 +171,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
|
||||
else()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
|
||||
endif()
|
||||
if(WITH_SSE2)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
|
||||
|
@ -285,10 +285,10 @@ static void parallel_free(DEVICE* device)
|
||||
|
||||
MessageQueue_PostQuit(parallel->queue, 0);
|
||||
WaitForSingleObject(parallel->thread, INFINITE);
|
||||
CloseHandle(parallel->thread);
|
||||
|
||||
Stream_Free(parallel->device.data, TRUE);
|
||||
MessageQueue_Free(parallel->queue);
|
||||
CloseHandle(parallel->thread);
|
||||
|
||||
free(parallel);
|
||||
}
|
||||
@ -309,10 +309,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
name = device->Name;
|
||||
path = device->Path;
|
||||
|
||||
if (!name || (name[0] == '*'))
|
||||
{
|
||||
/* TODO: implement auto detection of parallel ports */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (name[0] && path[0])
|
||||
{
|
||||
parallel = (PARALLEL_DEVICE*) malloc(sizeof(PARALLEL_DEVICE));
|
||||
ZeroMemory(parallel, sizeof(PARALLEL_DEVICE));
|
||||
parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE));
|
||||
|
||||
if (!parallel)
|
||||
return -1;
|
||||
|
||||
parallel->device.type = RDPDR_DTYP_PARALLEL;
|
||||
parallel->device.name = name;
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "serial_constants.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
@ -64,39 +65,27 @@ struct _SERIAL_DEVICE
|
||||
char* path;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
wLog* log;
|
||||
HANDLE thread;
|
||||
HANDLE mthread;
|
||||
HANDLE stopEvent;
|
||||
HANDLE newEvent;
|
||||
|
||||
wQueue* queue;
|
||||
LIST* pending_irps;
|
||||
|
||||
fd_set read_fds;
|
||||
fd_set write_fds;
|
||||
UINT32 nfds;
|
||||
struct timeval tv;
|
||||
UINT32 select_timeout;
|
||||
UINT32 timeout_id;
|
||||
wMessageQueue* IrpQueue;
|
||||
};
|
||||
|
||||
static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 abort_io, UINT32 io_status);
|
||||
static void serial_check_for_events(SERIAL_DEVICE* serial);
|
||||
static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp);
|
||||
static BOOL serial_check_fds(SERIAL_DEVICE* serial);
|
||||
static void* serial_thread_mfunc(void* arg);
|
||||
|
||||
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
char* path = NULL;
|
||||
int status;
|
||||
SERIAL_TTY* tty;
|
||||
UINT32 PathLength;
|
||||
UINT32 FileId;
|
||||
UINT32 PathLength;
|
||||
char* path = NULL;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
Stream_Seek(irp->input, 28); /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */
|
||||
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */
|
||||
Stream_Read_UINT32(irp->input, PathLength);
|
||||
Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */
|
||||
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* SharedAccess (4 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* CreateDisposition (4 bytes) */
|
||||
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
|
||||
|
||||
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
|
||||
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
|
||||
PathLength / 2, &path, 0, NULL, NULL);
|
||||
@ -108,7 +97,7 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
|
||||
tty = serial_tty_new(serial->path, FileId);
|
||||
|
||||
if (tty == NULL)
|
||||
if (!tty)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
FileId = 0;
|
||||
@ -118,23 +107,11 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
else
|
||||
{
|
||||
serial->tty = tty;
|
||||
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE,
|
||||
STATUS_CANCELLED);
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ,
|
||||
STATUS_CANCELLED);
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE,
|
||||
STATUS_CANCELLED);
|
||||
|
||||
serial->mthread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) serial_thread_mfunc, (void*) serial,
|
||||
0, NULL);
|
||||
|
||||
DEBUG_SVC("%s(%d) created.", serial->path, FileId);
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, FileId);
|
||||
Stream_Write_UINT8(irp->output, 0);
|
||||
Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
|
||||
|
||||
free(path);
|
||||
|
||||
@ -143,11 +120,11 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
|
||||
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
SERIAL_TTY* tty = serial->tty;
|
||||
|
||||
tty = serial->tty;
|
||||
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
|
||||
|
||||
if (tty == NULL)
|
||||
if (!tty)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
DEBUG_WARN("tty not valid.");
|
||||
@ -156,35 +133,27 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
DEBUG_SVC("%s(%d) closed.", serial->path, tty->id);
|
||||
|
||||
TerminateThread(serial->mthread, 0);
|
||||
WaitForSingleObject(serial->mthread, INFINITE);
|
||||
CloseHandle(serial->mthread);
|
||||
serial->mthread = NULL;
|
||||
|
||||
serial_tty_free(tty);
|
||||
serial->tty = NULL;
|
||||
}
|
||||
|
||||
Stream_Zero(irp->output, 5); /* Padding(5) */
|
||||
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
|
||||
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
UINT32 Length;
|
||||
UINT64 Offset;
|
||||
BYTE* buffer = NULL;
|
||||
SERIAL_TTY* tty = serial->tty;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_Read_UINT64(irp->input, Offset);
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
|
||||
DEBUG_SVC("length %u offset %llu", Length, Offset);
|
||||
|
||||
tty = serial->tty;
|
||||
|
||||
if (tty == NULL)
|
||||
if (!tty)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
@ -210,7 +179,7 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
||||
|
||||
if (Length > 0)
|
||||
{
|
||||
@ -225,59 +194,60 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
|
||||
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
int status;
|
||||
UINT32 Length;
|
||||
UINT64 Offset;
|
||||
SERIAL_TTY* tty = serial->tty;
|
||||
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_Read_UINT64(irp->input, Offset);
|
||||
Stream_Seek(irp->input, 20); /* Padding */
|
||||
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
|
||||
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
|
||||
DEBUG_SVC("length %u offset %llu", Length, Offset);
|
||||
|
||||
tty = serial->tty;
|
||||
|
||||
if (tty == NULL)
|
||||
if (!tty)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("tty not valid.");
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||
irp->Complete(irp);
|
||||
return;
|
||||
}
|
||||
else if (!serial_tty_write(tty, Stream_Pointer(irp->input), Length))
|
||||
|
||||
status = serial_tty_write(tty, Stream_Pointer(irp->input), Length);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("write %s(%d) failed.", serial->path, tty->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, serial->path, tty->id);
|
||||
printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno);
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||
irp->Complete(irp);
|
||||
return;
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding */
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
UINT32 IoControlCode;
|
||||
UINT32 InputBufferLength;
|
||||
UINT32 OutputBufferLength;
|
||||
UINT32 abort_io = SERIAL_ABORT_IO_NONE;
|
||||
UINT32 abortIo = SERIAL_ABORT_IO_NONE;
|
||||
SERIAL_TTY* tty = serial->tty;
|
||||
|
||||
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
|
||||
|
||||
Stream_Read_UINT32(irp->input, InputBufferLength);
|
||||
Stream_Read_UINT32(irp->input, OutputBufferLength);
|
||||
Stream_Read_UINT32(irp->input, IoControlCode);
|
||||
Stream_Seek(irp->input, 20); /* Padding */
|
||||
|
||||
tty = serial->tty;
|
||||
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
|
||||
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
|
||||
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
|
||||
|
||||
if (!tty)
|
||||
{
|
||||
@ -288,23 +258,16 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
}
|
||||
else
|
||||
{
|
||||
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abort_io);
|
||||
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo);
|
||||
}
|
||||
|
||||
if (abort_io & SERIAL_ABORT_IO_WRITE)
|
||||
serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_WRITE, STATUS_CANCELLED);
|
||||
if (abort_io & SERIAL_ABORT_IO_READ)
|
||||
serial_abort_single_io(serial, tty->id, SERIAL_ABORT_IO_READ, STATUS_CANCELLED);
|
||||
|
||||
if (irp->IoStatus == STATUS_PENDING)
|
||||
list_enqueue(serial->pending_irps, irp);
|
||||
else
|
||||
irp->Complete(irp);
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
|
||||
irp->MajorFunction, irp->MinorFunction);
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
@ -317,13 +280,11 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
serial_handle_async_irp(serial, irp);
|
||||
//serial_process_irp_read(serial, irp);
|
||||
serial_process_irp_read(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
serial_handle_async_irp(serial, irp);
|
||||
//serial_process_irp_write(serial, irp);
|
||||
serial_process_irp_write(serial, irp);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
@ -336,74 +297,29 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
}
|
||||
|
||||
serial_check_for_events(serial);
|
||||
}
|
||||
|
||||
/* This thread is used as a workaround for the missing serial event
|
||||
* support in WaitForMultipleObjects.
|
||||
* It monitors the terminal for events and posts it in a supported
|
||||
* form that WaitForMultipleObjects can use it. */
|
||||
void* serial_thread_mfunc(void* arg)
|
||||
{
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
|
||||
|
||||
assert(NULL != serial);
|
||||
while(1)
|
||||
{
|
||||
int sl;
|
||||
fd_set rd;
|
||||
|
||||
if(!serial->tty || serial->tty->fd <= 0)
|
||||
{
|
||||
DEBUG_WARN("Monitor thread still running, but no terminal opened!");
|
||||
sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FD_ZERO(&rd);
|
||||
FD_SET(serial->tty->fd, &rd);
|
||||
sl = select(serial->tty->fd + 1, &rd, NULL, NULL, NULL);
|
||||
if( sl > 0 )
|
||||
SetEvent(serial->newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* serial_thread_func(void* arg)
|
||||
{
|
||||
IRP* irp;
|
||||
DWORD status;
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
|
||||
HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue), serial->newEvent};
|
||||
wMessage message;
|
||||
SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg;
|
||||
|
||||
assert(NULL != serial);
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(3, ev, FALSE, INFINITE);
|
||||
|
||||
if (WAIT_OBJECT_0 == status)
|
||||
if (!MessageQueue_Wait(drive->IrpQueue))
|
||||
break;
|
||||
else if (status == WAIT_OBJECT_0 + 1)
|
||||
{
|
||||
FD_ZERO(&serial->read_fds);
|
||||
FD_ZERO(&serial->write_fds);
|
||||
|
||||
serial->tv.tv_sec = 0;
|
||||
serial->tv.tv_usec = 0;
|
||||
serial->select_timeout = 0;
|
||||
if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
|
||||
break;
|
||||
|
||||
if ((irp = (IRP*) Queue_Dequeue(serial->queue)))
|
||||
serial_process_irp(serial, irp);
|
||||
}
|
||||
else if (status == WAIT_OBJECT_0 + 2)
|
||||
ResetEvent(serial->newEvent);
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
if(serial->tty)
|
||||
serial_check_fds(serial);
|
||||
irp = (IRP*) message.wParam;
|
||||
|
||||
if (irp)
|
||||
serial_process_irp(drive, irp);
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
@ -413,366 +329,28 @@ static void* serial_thread_func(void* arg)
|
||||
static void serial_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
||||
|
||||
Queue_Enqueue(serial->queue, irp);
|
||||
MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL);
|
||||
}
|
||||
|
||||
static void serial_free(DEVICE* device)
|
||||
{
|
||||
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
|
||||
|
||||
DEBUG_SVC("freeing device");
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
|
||||
|
||||
/* Stop thread */
|
||||
SetEvent(serial->stopEvent);
|
||||
if(serial->mthread)
|
||||
{
|
||||
TerminateThread(serial->mthread, 0);
|
||||
WaitForSingleObject(serial->mthread, INFINITE);
|
||||
CloseHandle(serial->mthread);
|
||||
}
|
||||
MessageQueue_PostQuit(serial->IrpQueue, 0);
|
||||
WaitForSingleObject(serial->thread, INFINITE);
|
||||
CloseHandle(serial->thread);
|
||||
|
||||
serial_tty_free(serial->tty);
|
||||
|
||||
/* Clean up resources */
|
||||
Stream_Free(serial->device.data, TRUE);
|
||||
Queue_Free(serial->queue);
|
||||
list_free(serial->pending_irps);
|
||||
CloseHandle(serial->stopEvent);
|
||||
CloseHandle(serial->newEvent);
|
||||
CloseHandle(serial->thread);
|
||||
MessageQueue_Free(serial->IrpQueue);
|
||||
|
||||
free(serial);
|
||||
}
|
||||
|
||||
static void serial_abort_single_io(SERIAL_DEVICE* serial, UINT32 file_id, UINT32 abort_io, UINT32 io_status)
|
||||
{
|
||||
UINT32 major;
|
||||
IRP* irp = NULL;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
|
||||
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (abort_io)
|
||||
{
|
||||
case SERIAL_ABORT_IO_NONE:
|
||||
major = 0;
|
||||
break;
|
||||
|
||||
case SERIAL_ABORT_IO_READ:
|
||||
major = IRP_MJ_READ;
|
||||
break;
|
||||
|
||||
case SERIAL_ABORT_IO_WRITE:
|
||||
major = IRP_MJ_WRITE;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("unexpected abort_io code %d", abort_io);
|
||||
return;
|
||||
}
|
||||
|
||||
irp = (IRP*) list_peek(serial->pending_irps);
|
||||
|
||||
while (irp)
|
||||
{
|
||||
if (irp->FileId != file_id || irp->MajorFunction != major)
|
||||
{
|
||||
irp = (IRP*) list_next(serial->pending_irps, irp);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Process a SINGLE FileId and MajorFunction */
|
||||
list_remove(serial->pending_irps, irp);
|
||||
irp->IoStatus = io_status;
|
||||
Stream_Write_UINT32(irp->output, 0);
|
||||
irp->Complete(irp);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
|
||||
}
|
||||
|
||||
static void serial_check_for_events(SERIAL_DEVICE* serial)
|
||||
{
|
||||
IRP* irp = NULL;
|
||||
IRP* prev;
|
||||
UINT32 result = 0;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
|
||||
|
||||
irp = (IRP*) list_peek(serial->pending_irps);
|
||||
|
||||
while (irp)
|
||||
{
|
||||
prev = NULL;
|
||||
|
||||
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
|
||||
{
|
||||
if (serial_tty_get_event(tty, &result))
|
||||
{
|
||||
DEBUG_SVC("got event result %u", result);
|
||||
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
Stream_Write_UINT32(irp->output, result);
|
||||
irp->Complete(irp);
|
||||
|
||||
prev = irp;
|
||||
irp = (IRP*) list_next(serial->pending_irps, irp);
|
||||
list_remove(serial->pending_irps, prev);
|
||||
}
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
irp = (IRP*) list_next(serial->pending_irps, irp);
|
||||
}
|
||||
|
||||
DEBUG_SVC("[out] pending size %d", list_size(serial->pending_irps));
|
||||
}
|
||||
|
||||
void serial_get_timeouts(SERIAL_DEVICE* serial, IRP* irp, UINT32* timeout, UINT32* interval_timeout)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
UINT32 Length;
|
||||
UINT32 pos;
|
||||
|
||||
pos = Stream_GetPosition(irp->input);
|
||||
Stream_Read_UINT32(irp->input, Length);
|
||||
Stream_SetPosition(irp->input, pos);
|
||||
|
||||
DEBUG_SVC("length read %u", Length);
|
||||
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
|
||||
*timeout = (tty->read_total_timeout_multiplier * Length) + tty->read_total_timeout_constant;
|
||||
*interval_timeout = tty->read_interval_timeout;
|
||||
|
||||
DEBUG_SVC("timeouts %u %u", *timeout, *interval_timeout);
|
||||
}
|
||||
|
||||
static void serial_handle_async_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
UINT32 timeout = 0;
|
||||
UINT32 itv_timeout = 0;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_WRITE:
|
||||
DEBUG_SVC("handling IRP_MJ_WRITE");
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
DEBUG_SVC("handling IRP_MJ_READ");
|
||||
|
||||
serial_get_timeouts(serial, irp, &timeout, &itv_timeout);
|
||||
|
||||
/* Check if io request timeout is smaller than current (but not 0). */
|
||||
if (timeout && ((serial->select_timeout == 0) || (timeout < serial->select_timeout)))
|
||||
{
|
||||
serial->select_timeout = timeout;
|
||||
serial->tv.tv_sec = serial->select_timeout / 1000;
|
||||
serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
|
||||
serial->timeout_id = tty->id;
|
||||
}
|
||||
if (itv_timeout && ((serial->select_timeout == 0) || (itv_timeout < serial->select_timeout)))
|
||||
{
|
||||
serial->select_timeout = itv_timeout;
|
||||
serial->tv.tv_sec = serial->select_timeout / 1000;
|
||||
serial->tv.tv_usec = (serial->select_timeout % 1000) * 1000;
|
||||
serial->timeout_id = tty->id;
|
||||
}
|
||||
DEBUG_SVC("select_timeout %u, tv_sec %lu tv_usec %lu, timeout_id %u",
|
||||
serial->select_timeout, serial->tv.tv_sec, serial->tv.tv_usec, serial->timeout_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("no need to handle %d", irp->MajorFunction);
|
||||
return;
|
||||
}
|
||||
|
||||
irp->IoStatus = STATUS_PENDING;
|
||||
list_enqueue(serial->pending_irps, irp);
|
||||
}
|
||||
|
||||
static void __serial_check_fds(SERIAL_DEVICE* serial)
|
||||
{
|
||||
IRP* irp;
|
||||
IRP* prev;
|
||||
SERIAL_TTY* tty;
|
||||
UINT32 result = 0;
|
||||
BOOL irp_completed = FALSE;
|
||||
|
||||
ZeroMemory(&serial->tv, sizeof(struct timeval));
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
|
||||
/* scan every pending */
|
||||
irp = list_peek(serial->pending_irps);
|
||||
|
||||
while (irp)
|
||||
{
|
||||
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_READ:
|
||||
if (FD_ISSET(tty->fd, &serial->read_fds))
|
||||
{
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
serial_process_irp_read(serial, irp);
|
||||
irp_completed = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
if (FD_ISSET(tty->fd, &serial->write_fds))
|
||||
{
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
serial_process_irp_write(serial, irp);
|
||||
irp_completed = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
if (serial_tty_get_event(tty, &result))
|
||||
{
|
||||
DEBUG_SVC("got event result %u", result);
|
||||
|
||||
irp->IoStatus = STATUS_SUCCESS;
|
||||
Stream_Write_UINT32(irp->output, result);
|
||||
irp->Complete(irp);
|
||||
irp_completed = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("no request found");
|
||||
break;
|
||||
}
|
||||
|
||||
prev = irp;
|
||||
irp = (IRP*) list_next(serial->pending_irps, irp);
|
||||
|
||||
if (irp_completed || (prev->IoStatus == STATUS_SUCCESS))
|
||||
list_remove(serial->pending_irps, prev);
|
||||
}
|
||||
}
|
||||
|
||||
static void serial_set_fds(SERIAL_DEVICE* serial)
|
||||
{
|
||||
IRP* irp;
|
||||
fd_set* fds;
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
DEBUG_SVC("[in] pending size %d", list_size(serial->pending_irps));
|
||||
|
||||
tty = serial->tty;
|
||||
if(!tty)
|
||||
{
|
||||
DEBUG_WARN("tty = %p", tty);
|
||||
return;
|
||||
}
|
||||
irp = (IRP*) list_peek(serial->pending_irps);
|
||||
|
||||
while (irp)
|
||||
{
|
||||
fds = NULL;
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_WRITE:
|
||||
fds = &serial->write_fds;
|
||||
break;
|
||||
|
||||
case IRP_MJ_READ:
|
||||
fds = &serial->read_fds;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fds && (tty->fd >= 0))
|
||||
{
|
||||
FD_SET(tty->fd, fds);
|
||||
serial->nfds = MAX(serial->nfds, tty->fd);
|
||||
}
|
||||
|
||||
irp = (IRP*) list_next(serial->pending_irps, irp);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL serial_check_fds(SERIAL_DEVICE* serial)
|
||||
{
|
||||
if (list_size(serial->pending_irps) == 0)
|
||||
return 1;
|
||||
|
||||
FD_ZERO(&serial->read_fds);
|
||||
FD_ZERO(&serial->write_fds);
|
||||
|
||||
serial->tv.tv_sec = 0;
|
||||
serial->tv.tv_usec = 0;
|
||||
serial->select_timeout = 0;
|
||||
|
||||
serial_set_fds(serial);
|
||||
DEBUG_SVC("waiting %lu %lu", serial->tv.tv_sec, serial->tv.tv_usec);
|
||||
|
||||
switch (select(serial->nfds + 1, &serial->read_fds, &serial->write_fds, NULL, &serial->tv))
|
||||
{
|
||||
case -1:
|
||||
DEBUG_SVC("select has returned -1 with error: %s", strerror(errno));
|
||||
return 0;
|
||||
|
||||
case 0:
|
||||
if (serial->select_timeout)
|
||||
{
|
||||
__serial_check_fds(serial);
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_NONE, STATUS_TIMEOUT);
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_READ, STATUS_TIMEOUT);
|
||||
serial_abort_single_io(serial, serial->timeout_id, SERIAL_ABORT_IO_WRITE, STATUS_TIMEOUT);
|
||||
}
|
||||
DEBUG_SVC("select has timed out");
|
||||
return 0;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
__serial_check_fds(serial);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define DeviceServiceEntry serial_DeviceServiceEntry
|
||||
#endif
|
||||
@ -789,10 +367,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
name = device->Name;
|
||||
path = device->Path;
|
||||
|
||||
if (!name || (name[0] == '*'))
|
||||
{
|
||||
/* TODO: implement auto detection of parallel ports */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((name && name[0]) && (path && path[0]))
|
||||
{
|
||||
serial = (SERIAL_DEVICE*) malloc(sizeof(SERIAL_DEVICE));
|
||||
ZeroMemory(serial, sizeof(SERIAL_DEVICE));
|
||||
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
|
||||
|
||||
if (!serial)
|
||||
return -1;
|
||||
|
||||
serial->device.type = RDPDR_DTYP_SERIAL;
|
||||
serial->device.name = name;
|
||||
@ -806,17 +392,16 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
|
||||
|
||||
serial->path = path;
|
||||
serial->queue = Queue_New(TRUE, -1, -1);
|
||||
serial->pending_irps = list_new();
|
||||
serial->IrpQueue = MessageQueue_New(NULL);
|
||||
|
||||
serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
serial->newEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
WLog_Init();
|
||||
serial->log = WLog_Get("com.freerdp.channel.serial.client");
|
||||
WLog_Print(serial->log, WLOG_DEBUG, "initializing");
|
||||
|
||||
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
|
||||
|
||||
serial->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
|
||||
serial->mthread = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -73,24 +73,47 @@
|
||||
#define TIOCOUTQ FIONWRITE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Refer to ReactOS's ntddser.h (public domain) for constant definitions
|
||||
*/
|
||||
|
||||
static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len);
|
||||
static void tty_set_termios(SERIAL_TTY* tty);
|
||||
static BOOL tty_get_termios(SERIAL_TTY* tty);
|
||||
static int tty_get_error_status();
|
||||
|
||||
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io)
|
||||
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abortIo)
|
||||
{
|
||||
int purge_mask;
|
||||
UINT32 result;
|
||||
UINT32 modemstate;
|
||||
BYTE immediate;
|
||||
UINT32 ret = STATUS_SUCCESS;
|
||||
UINT32 length = 0;
|
||||
UINT32 pos;
|
||||
int purge_mask;
|
||||
UINT32 modemstate;
|
||||
UINT32 begPos, endPos;
|
||||
UINT32 OutputBufferLength;
|
||||
UINT32 status = STATUS_SUCCESS;
|
||||
UINT32 IoCtlDeviceType;
|
||||
UINT32 IoCtlFunction;
|
||||
UINT32 IoCtlMethod;
|
||||
UINT32 IoCtlAccess;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
IoCtlMethod = (IoControlCode & 0x3);
|
||||
IoCtlFunction = ((IoControlCode >> 2) & 0xFFF);
|
||||
IoCtlAccess = ((IoControlCode >> 14) & 0x3);
|
||||
IoCtlDeviceType = ((IoControlCode >> 16) & 0xFFFF);
|
||||
|
||||
Stream_Seek(output, sizeof(UINT32));
|
||||
/**
|
||||
* FILE_DEVICE_SERIAL_PORT 0x0000001B
|
||||
* FILE_DEVICE_UNKNOWN 0x00000022
|
||||
*/
|
||||
|
||||
if (IoCtlDeviceType == 0x00000022)
|
||||
{
|
||||
IoControlCode &= 0xFFFF;
|
||||
IoControlCode |= (0x0000001B << 16);
|
||||
}
|
||||
|
||||
Stream_Seek_UINT32(output); /* OutputBufferLength (4 bytes) */
|
||||
begPos = (UINT32) Stream_GetPosition(output);
|
||||
|
||||
switch (IoControlCode)
|
||||
{
|
||||
@ -101,7 +124,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_BAUD_RATE:
|
||||
length = 4;
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, tty->baud_rate);
|
||||
DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
|
||||
break;
|
||||
@ -123,7 +146,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
|
||||
case IOCTL_SERIAL_GET_LINE_CONTROL:
|
||||
DEBUG_SVC("SERIAL_GET_LINE_CONTROL");
|
||||
length = 3;
|
||||
OutputBufferLength = 3;
|
||||
Stream_Write_UINT8(output, tty->stop_bits);
|
||||
Stream_Write_UINT8(output, tty->parity);
|
||||
Stream_Write_UINT8(output, tty->word_length);
|
||||
@ -137,13 +160,13 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
|
||||
case IOCTL_SERIAL_CONFIG_SIZE:
|
||||
DEBUG_SVC("SERIAL_CONFIG_SIZE");
|
||||
length = 4;
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, 0);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_CHARS:
|
||||
DEBUG_SVC("SERIAL_GET_CHARS");
|
||||
length = 6;
|
||||
OutputBufferLength = 6;
|
||||
Stream_Write(output, tty->chars, 6);
|
||||
break;
|
||||
|
||||
@ -154,7 +177,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_HANDFLOW:
|
||||
length = 16;
|
||||
OutputBufferLength = 16;
|
||||
tty_get_termios(tty);
|
||||
Stream_Write_UINT32(output, tty->control);
|
||||
Stream_Write_UINT32(output, tty->xonoff);
|
||||
@ -200,7 +223,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
tty->read_interval_timeout,
|
||||
tty->read_total_timeout_multiplier,
|
||||
tty->read_total_timeout_constant);
|
||||
length = 20;
|
||||
OutputBufferLength = 20;
|
||||
Stream_Write_UINT32(output, tty->read_interval_timeout);
|
||||
Stream_Write_UINT32(output, tty->read_total_timeout_multiplier);
|
||||
Stream_Write_UINT32(output, tty->read_total_timeout_constant);
|
||||
@ -210,7 +233,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
|
||||
case IOCTL_SERIAL_GET_WAIT_MASK:
|
||||
DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
|
||||
length = 4;
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, tty->wait_mask);
|
||||
break;
|
||||
|
||||
@ -269,12 +292,12 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
modemstate |= SERIAL_MS_RTS;
|
||||
#endif
|
||||
DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
|
||||
length = 4;
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, modemstate);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_COMMSTATUS:
|
||||
length = 18;
|
||||
OutputBufferLength = 18;
|
||||
Stream_Write_UINT32(output, 0); /* Errors */
|
||||
Stream_Write_UINT32(output, 0); /* Hold reasons */
|
||||
|
||||
@ -316,21 +339,21 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
#endif
|
||||
|
||||
if (purge_mask & SERIAL_PURGE_TXABORT)
|
||||
*abort_io |= SERIAL_ABORT_IO_WRITE;
|
||||
*abortIo |= SERIAL_ABORT_IO_WRITE;
|
||||
if (purge_mask & SERIAL_PURGE_RXABORT)
|
||||
*abort_io |= SERIAL_ABORT_IO_READ;
|
||||
*abortIo |= SERIAL_ABORT_IO_READ;
|
||||
break;
|
||||
case IOCTL_SERIAL_WAIT_ON_MASK:
|
||||
DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
|
||||
tty->event_pending = 1;
|
||||
length = 4;
|
||||
OutputBufferLength = 4;
|
||||
if (serial_tty_get_event(tty, &result))
|
||||
{
|
||||
DEBUG_SVC("WAIT end event = %X", result);
|
||||
Stream_Write_UINT32(output, result);
|
||||
break;
|
||||
}
|
||||
ret = STATUS_PENDING;
|
||||
status = STATUS_PENDING;
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_BREAK_ON:
|
||||
@ -356,27 +379,33 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL %d", IoControlCode);
|
||||
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL 0x%08X", IoControlCode);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Write OutputBufferLength */
|
||||
pos = Stream_GetPosition(output);
|
||||
Stream_SetPosition(output, 16);
|
||||
Stream_Write_UINT32(output, length);
|
||||
Stream_SetPosition(output, pos);
|
||||
endPos = (UINT32) Stream_GetPosition(output);
|
||||
OutputBufferLength = endPos - begPos;
|
||||
|
||||
return ret;
|
||||
if (OutputBufferLength < 1)
|
||||
{
|
||||
Stream_Write_UINT8(output, 0); /* Padding (1 byte) */
|
||||
endPos = (UINT32) Stream_GetPosition(output);
|
||||
OutputBufferLength = endPos - begPos;
|
||||
}
|
||||
|
||||
Stream_SealLength(output);
|
||||
|
||||
Stream_SetPosition(output, 16);
|
||||
Stream_Write_UINT32(output, OutputBufferLength); /* OutputBufferLength (4 bytes) */
|
||||
Stream_SetPosition(output, endPos);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
|
||||
{
|
||||
ssize_t status;
|
||||
long timeout = 90;
|
||||
struct termios* ptermios;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
ptermios = tty->ptermios;
|
||||
|
||||
/* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
|
||||
with requested read size */
|
||||
@ -391,21 +420,35 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
|
||||
timeout = (tty->read_interval_timeout * (*Length) + 99) / 100;
|
||||
}
|
||||
|
||||
/* If a timeout is set, do a blocking read, which times out after some time.
|
||||
It will make FreeRDP less responsive, but it will improve serial performance,
|
||||
by not reading one character at a time. */
|
||||
if (timeout == 0)
|
||||
{
|
||||
ptermios->c_cc[VTIME] = 0;
|
||||
ptermios->c_cc[VMIN] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptermios->c_cc[VTIME] = timeout;
|
||||
ptermios->c_cc[VMIN] = 1;
|
||||
}
|
||||
if (tty->timeout != timeout)
|
||||
{
|
||||
struct termios* ptermios;
|
||||
|
||||
tcsetattr(tty->fd, TCSANOW, ptermios);
|
||||
ptermios = (struct termios*) calloc(1, sizeof(struct termios));
|
||||
|
||||
if (tcgetattr(tty->fd, ptermios) < 0)
|
||||
return FALSE;
|
||||
|
||||
/**
|
||||
* If a timeout is set, do a blocking read, which times out after some time.
|
||||
* It will make FreeRDP less responsive, but it will improve serial performance,
|
||||
* by not reading one character at a time.
|
||||
*/
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
ptermios->c_cc[VTIME] = 0;
|
||||
ptermios->c_cc[VMIN] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptermios->c_cc[VTIME] = timeout;
|
||||
ptermios->c_cc[VMIN] = 1;
|
||||
}
|
||||
|
||||
tcsetattr(tty->fd, TCSANOW, ptermios);
|
||||
tty->timeout = timeout;
|
||||
}
|
||||
|
||||
ZeroMemory(buffer, *Length);
|
||||
|
||||
@ -424,20 +467,21 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
|
||||
int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
|
||||
{
|
||||
ssize_t status;
|
||||
ssize_t status = 0;
|
||||
UINT32 event_txempty = Length;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
|
||||
while (Length > 0)
|
||||
{
|
||||
status = write(tty->fd, buffer, Length);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
return FALSE;
|
||||
if (errno == EAGAIN)
|
||||
status = 0;
|
||||
else
|
||||
return status;
|
||||
}
|
||||
|
||||
Length -= status;
|
||||
@ -446,7 +490,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
|
||||
|
||||
tty->event_txempty = event_txempty;
|
||||
|
||||
return TRUE;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,9 +502,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
|
||||
*/
|
||||
void serial_tty_free(SERIAL_TTY* tty)
|
||||
{
|
||||
DEBUG_SVC("in");
|
||||
|
||||
if(!tty)
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
if (tty->fd >= 0)
|
||||
@ -480,8 +522,10 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
{
|
||||
SERIAL_TTY* tty;
|
||||
|
||||
tty = (SERIAL_TTY*) malloc(sizeof(SERIAL_TTY));
|
||||
ZeroMemory(tty, sizeof(SERIAL_TTY));
|
||||
tty = (SERIAL_TTY*) calloc(1, sizeof(SERIAL_TTY));
|
||||
|
||||
if (!tty)
|
||||
return NULL;
|
||||
|
||||
tty->id = id;
|
||||
tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
@ -498,19 +542,17 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
DEBUG_SVC("tty fd %d successfully opened", tty->fd);
|
||||
}
|
||||
|
||||
tty->ptermios = (struct termios*) malloc(sizeof(struct termios));
|
||||
ZeroMemory(tty->ptermios, sizeof(struct termios));
|
||||
tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios));
|
||||
|
||||
if (tty->ptermios == NULL)
|
||||
if (!tty->ptermios)
|
||||
{
|
||||
serial_tty_free(tty);
|
||||
return NULL ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tty->pold_termios = (struct termios*) malloc(sizeof(struct termios));
|
||||
ZeroMemory(tty->pold_termios, sizeof(struct termios));
|
||||
tty->pold_termios = (struct termios*) calloc(1, sizeof(struct termios));
|
||||
|
||||
if (tty->pold_termios == NULL)
|
||||
if (!tty->pold_termios)
|
||||
{
|
||||
serial_tty_free(tty);
|
||||
return NULL;
|
||||
@ -526,11 +568,14 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
}
|
||||
|
||||
tty->ptermios->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
||||
tty->ptermios->c_iflag = IGNPAR | ICRNL;
|
||||
tty->ptermios->c_oflag &= ~OPOST;
|
||||
tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
tty->ptermios->c_cflag &= ~(CSIZE | PARENB);
|
||||
tty->ptermios->c_cflag |= CLOCAL | CREAD | CS8;
|
||||
tty->ptermios->c_cflag |= CS8;
|
||||
|
||||
tty->ptermios->c_iflag = IGNPAR;
|
||||
tty->ptermios->c_cflag |= CLOCAL | CREAD;
|
||||
|
||||
tcsetattr(tty->fd, TCSANOW, tty->ptermios);
|
||||
|
||||
tty->event_txempty = 0;
|
||||
@ -558,8 +603,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
int bytes;
|
||||
BOOL status = FALSE;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
|
||||
*result = 0;
|
||||
|
||||
#ifdef TIOCINQ
|
||||
@ -587,7 +630,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
*result |= SERIAL_EV_RLSD;
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG))
|
||||
@ -603,7 +645,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
*result |= SERIAL_EV_RXCHAR;
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -802,16 +843,18 @@ static BOOL tty_get_termios(SERIAL_TTY* tty)
|
||||
tty->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
|
||||
tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
|
||||
|
||||
tty->timeout = ptermios->c_cc[VTIME];
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tty_set_termios(SERIAL_TTY* tty)
|
||||
{
|
||||
speed_t speed;
|
||||
struct termios *ptermios;
|
||||
struct termios* ptermios;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
ptermios = tty->ptermios;
|
||||
|
||||
switch (tty->baud_rate)
|
||||
{
|
||||
#ifdef B75
|
||||
@ -1003,8 +1046,6 @@ static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len)
|
||||
{
|
||||
ssize_t status;
|
||||
|
||||
DEBUG_SVC("in");
|
||||
|
||||
status = write(tty->fd, data, len);
|
||||
|
||||
if (status < 0)
|
||||
@ -1017,8 +1058,6 @@ static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len)
|
||||
|
||||
static int tty_get_error_status()
|
||||
{
|
||||
DEBUG_SVC("in errno %d", errno);
|
||||
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES:
|
||||
|
@ -65,13 +65,14 @@ struct _SERIAL_TTY
|
||||
int event_dsr;
|
||||
int event_rlsd;
|
||||
int event_pending;
|
||||
long timeout;
|
||||
};
|
||||
|
||||
SERIAL_TTY* serial_tty_new(const char* path, UINT32 id);
|
||||
void serial_tty_free(SERIAL_TTY* tty);
|
||||
|
||||
BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length);
|
||||
BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length);
|
||||
int serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length);
|
||||
UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input, wStream* output, UINT32* abort_io);
|
||||
|
||||
BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result);
|
||||
|
@ -322,8 +322,10 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
path = device->Path;
|
||||
|
||||
/* TODO: check if server supports sc redirect (version 5.1) */
|
||||
smartcard = (SMARTCARD_DEVICE*) malloc(sizeof(SMARTCARD_DEVICE));
|
||||
ZeroMemory(smartcard, sizeof(SMARTCARD_DEVICE));
|
||||
smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE));
|
||||
|
||||
if (!smartcard)
|
||||
return -1;
|
||||
|
||||
smartcard->device.type = RDPDR_DTYP_SMARTCARD;
|
||||
smartcard->device.name = "SCARD";
|
||||
@ -337,6 +339,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
smartcard->name = NULL;
|
||||
smartcard->path = NULL;
|
||||
|
||||
if (path)
|
||||
{
|
||||
smartcard->path = path;
|
||||
|
@ -152,7 +152,7 @@ DWORD mac_client_update_thread(void* param)
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD mac_client_input_thread(void* param)
|
||||
@ -177,7 +177,7 @@ DWORD mac_client_input_thread(void* param)
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD mac_client_channels_thread(void* param)
|
||||
@ -214,7 +214,7 @@ DWORD mac_client_channels_thread(void* param)
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD mac_client_thread(void* param)
|
||||
|
@ -93,8 +93,8 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "drives", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect all drives" },
|
||||
{ "home-drive", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect home drive" },
|
||||
{ "clipboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Redirect clipboard" },
|
||||
{ "serial", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
|
||||
{ "parallel", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect parallel device" },
|
||||
{ "serial", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
|
||||
{ "parallel", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect parallel device" },
|
||||
{ "smartcard", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect smartcard device" },
|
||||
{ "printer", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Redirect printer device" },
|
||||
{ "usb", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect USB device" },
|
||||
@ -297,12 +297,18 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
|
||||
if (count < 3)
|
||||
return -1;
|
||||
|
||||
drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
|
||||
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
|
||||
drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
|
||||
|
||||
if (!drive)
|
||||
return -1;
|
||||
|
||||
drive->Type = RDPDR_DTYP_FILESYSTEM;
|
||||
drive->Name = _strdup(params[1]);
|
||||
drive->Path = _strdup(params[2]);
|
||||
|
||||
if (count > 1)
|
||||
drive->Name = _strdup(params[1]);
|
||||
|
||||
if (count > 2)
|
||||
drive->Path = _strdup(params[2]);
|
||||
|
||||
freerdp_device_collection_add(settings, (RDPDR_DEVICE*) drive);
|
||||
settings->DeviceRedirection = TRUE;
|
||||
@ -316,8 +322,10 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
|
||||
if (count < 1)
|
||||
return -1;
|
||||
|
||||
printer = (RDPDR_PRINTER*) malloc(sizeof(RDPDR_PRINTER));
|
||||
ZeroMemory(printer, sizeof(RDPDR_PRINTER));
|
||||
printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER));
|
||||
|
||||
if (!printer)
|
||||
return -1;
|
||||
|
||||
printer->Type = RDPDR_DTYP_PRINT;
|
||||
|
||||
@ -339,12 +347,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
|
||||
if (count < 1)
|
||||
return -1;
|
||||
|
||||
smartcard = (RDPDR_SMARTCARD*) malloc(sizeof(RDPDR_SMARTCARD));
|
||||
ZeroMemory(smartcard, sizeof(RDPDR_SMARTCARD));
|
||||
smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD));
|
||||
|
||||
if (!smartcard)
|
||||
return -1;
|
||||
|
||||
smartcard->Type = RDPDR_DTYP_SMARTCARD;
|
||||
|
||||
if (count > 1)
|
||||
smartcard->Name = _strdup(params[1]);
|
||||
|
||||
if (count > 2)
|
||||
smartcard->Path = _strdup(params[2]);
|
||||
|
||||
@ -360,12 +372,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
|
||||
if (count < 1)
|
||||
return -1;
|
||||
|
||||
serial = (RDPDR_SERIAL*) malloc(sizeof(RDPDR_SERIAL));
|
||||
ZeroMemory(serial, sizeof(RDPDR_SERIAL));
|
||||
serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL));
|
||||
|
||||
if (!serial)
|
||||
return -1;
|
||||
|
||||
serial->Type = RDPDR_DTYP_SERIAL;
|
||||
|
||||
if (count > 1)
|
||||
serial->Name = _strdup(params[1]);
|
||||
|
||||
if (count > 2)
|
||||
serial->Path = _strdup(params[2]);
|
||||
|
||||
@ -381,12 +397,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
|
||||
if (count < 1)
|
||||
return -1;
|
||||
|
||||
parallel = (RDPDR_PARALLEL*) malloc(sizeof(RDPDR_PARALLEL));
|
||||
ZeroMemory(parallel, sizeof(RDPDR_PARALLEL));
|
||||
parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL));
|
||||
|
||||
if (!parallel)
|
||||
return -1;
|
||||
|
||||
parallel->Type = RDPDR_DTYP_PARALLEL;
|
||||
|
||||
if (count > 1)
|
||||
parallel->Name = _strdup(params[1]);
|
||||
|
||||
if (count > 1)
|
||||
parallel->Path = _strdup(params[2]);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#ifndef __REGION_H___
|
||||
#define __REGION_H___
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
|
||||
struct _REGION16_DATA;
|
||||
@ -43,7 +44,7 @@ typedef struct _REGION16 REGION16;
|
||||
* @param r2 second rectangle
|
||||
* @return if the two rectangles intersect
|
||||
*/
|
||||
BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
|
||||
FREERDP_API BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
|
||||
|
||||
/** computes the intersection of two rectangles
|
||||
* @param r1 first rectangle
|
||||
@ -51,15 +52,15 @@ BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
|
||||
* @param dst resulting intersection
|
||||
* @return if the two rectangles intersect
|
||||
*/
|
||||
BOOL rectangles_intersection(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2, RECTANGLE_16 *dst);
|
||||
FREERDP_API BOOL rectangles_intersection(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2, RECTANGLE_16 *dst);
|
||||
|
||||
/** initialize a region16
|
||||
* @param region the region to initialise
|
||||
*/
|
||||
void region16_init(REGION16 *region);
|
||||
FREERDP_API void region16_init(REGION16 *region);
|
||||
|
||||
/** @return the number of rectangles of this region16 */
|
||||
int region16_n_rects(const REGION16 *region);
|
||||
FREERDP_API int region16_n_rects(const REGION16 *region);
|
||||
|
||||
/** returns a pointer on rectangles and the number of rectangles in this region.
|
||||
* nbRect can be set to NULL if not interested by the numnber of rectangles.
|
||||
@ -67,33 +68,33 @@ int region16_n_rects(const REGION16 *region);
|
||||
* @param nbRects a pointer that will be filled with the number of rectangles
|
||||
* @return a pointer on the rectangles
|
||||
*/
|
||||
const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects);
|
||||
FREERDP_API const RECTANGLE_16 *region16_rects(const REGION16 *region, int *nbRects);
|
||||
|
||||
/** @return the extents rectangle of this region */
|
||||
const RECTANGLE_16 *region16_extents(const REGION16 *region);
|
||||
FREERDP_API const RECTANGLE_16 *region16_extents(const REGION16 *region);
|
||||
|
||||
/** returns if the region is empty
|
||||
* @param region
|
||||
* @return if the region is empty
|
||||
*/
|
||||
BOOL region16_is_empty(const REGION16 *region);
|
||||
FREERDP_API BOOL region16_is_empty(const REGION16 *region);
|
||||
|
||||
/** clears the region, the region is resetted to a (0,0,0,0) region
|
||||
* @param region
|
||||
*/
|
||||
void region16_clear(REGION16 *region);
|
||||
FREERDP_API void region16_clear(REGION16 *region);
|
||||
|
||||
/** dumps the region on stderr
|
||||
* @param region the region to dump
|
||||
*/
|
||||
void region16_print(const REGION16 *region);
|
||||
FREERDP_API void region16_print(const REGION16 *region);
|
||||
|
||||
/** copies the region to another region
|
||||
* @param dst destination region
|
||||
* @param src source region
|
||||
* @return if the operation was successful (false meaning out-of-memory)
|
||||
*/
|
||||
BOOL region16_copy(REGION16 *dst, const REGION16 *src);
|
||||
FREERDP_API BOOL region16_copy(REGION16 *dst, const REGION16 *src);
|
||||
|
||||
/** adds a rectangle in src and stores the resulting region in dst
|
||||
* @param dst destination region
|
||||
@ -101,14 +102,14 @@ BOOL region16_copy(REGION16 *dst, const REGION16 *src);
|
||||
* @param rect the rectangle to add
|
||||
* @return if the operation was successful (false meaning out-of-memory)
|
||||
*/
|
||||
BOOL region16_union_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect);
|
||||
FREERDP_API BOOL region16_union_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *rect);
|
||||
|
||||
/** returns if a rectangle intersects the region
|
||||
* @param src the region
|
||||
* @param arg2 the rectangle
|
||||
* @return if region and rectangle intersect
|
||||
*/
|
||||
BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
|
||||
FREERDP_API BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
|
||||
|
||||
/** computes the intersection between a region and a rectangle
|
||||
* @param dst destination region
|
||||
@ -116,12 +117,12 @@ BOOL region16_intersects_rect(const REGION16 *src, const RECTANGLE_16 *arg2);
|
||||
* @param arg2 the rectangle that intersects
|
||||
* @return if the operation was successful (false meaning out-of-memory)
|
||||
*/
|
||||
BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *arg2);
|
||||
FREERDP_API BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE_16 *arg2);
|
||||
|
||||
/** release internal data associated with this region
|
||||
* @param region the region to release
|
||||
*/
|
||||
void region16_uninit(REGION16 *region);
|
||||
FREERDP_API void region16_uninit(REGION16 *region);
|
||||
|
||||
|
||||
#endif /* __REGION_H___ */
|
||||
|
@ -84,7 +84,7 @@ struct rdp_tls
|
||||
int alertDescription;
|
||||
};
|
||||
|
||||
FREERDP_API BOOL tls_connect(rdpTls* tls);
|
||||
FREERDP_API int tls_connect(rdpTls* tls);
|
||||
FREERDP_API BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file);
|
||||
FREERDP_API BOOL tls_disconnect(rdpTls* tls);
|
||||
|
||||
@ -99,7 +99,7 @@ FREERDP_API int tls_wait_write(rdpTls* tls);
|
||||
FREERDP_API int tls_set_alert_code(rdpTls* tls, int level, int description);
|
||||
|
||||
FREERDP_API BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname);
|
||||
FREERDP_API BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
|
||||
FREERDP_API int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port);
|
||||
FREERDP_API void tls_print_certificate_error(char* hostname, char* fingerprint, char* hosts_file);
|
||||
FREERDP_API void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count);
|
||||
|
||||
|
@ -177,7 +177,6 @@ FREERDP_API extern int connectErrorCode;
|
||||
#define CANCELEDBYUSER ERRORSTART + 11
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FreeRDP Context Error Codes
|
||||
*/
|
||||
@ -229,6 +228,8 @@ FREERDP_API extern int connectErrorCode;
|
||||
#define FREERDP_ERROR_AUTHENTICATION_FAILED MAKE_FREERDP_ERROR(CONNECT, 9)
|
||||
#define FREERDP_ERROR_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(CONNECT, 10)
|
||||
#define FREERDP_ERROR_CONNECT_CANCELLED MAKE_FREERDP_ERROR(CONNECT, 11)
|
||||
#define FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED MAKE_FREERDP_ERROR(CONNECT, 12)
|
||||
#define FREERDP_ERROR_CONNECT_TRANSPORT_FAILED MAKE_FREERDP_ERROR(CONNECT, 13)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -87,11 +87,11 @@ struct _BITMAP_PLANAR_CONTEXT
|
||||
BYTE* rlePlanesBuffer;
|
||||
};
|
||||
|
||||
int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size);
|
||||
FREERDP_API int freerdp_bitmap_planar_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size);
|
||||
|
||||
int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]);
|
||||
BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int width, int height, BYTE* outPlane, int* dstSize);
|
||||
BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane);
|
||||
int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
|
||||
FREERDP_API int freerdp_split_color_planes(BYTE* data, UINT32 format, int width, int height, int scanline, BYTE* planes[4]);
|
||||
FREERDP_API BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int width, int height, BYTE* outPlane, int* dstSize);
|
||||
FREERDP_API BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane);
|
||||
FREERDP_API int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
|
||||
|
||||
#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */
|
||||
|
@ -690,7 +690,7 @@ struct UnitaryTest tests[] = {
|
||||
|
||||
int TestFreeRDPRegion(int argc, char* argv[])
|
||||
{
|
||||
int i, testNb;
|
||||
int i, testNb = 0;
|
||||
int retCode = -1;
|
||||
|
||||
for (i = 0; tests[i].func; i++)
|
||||
|
@ -154,7 +154,7 @@ RDPDR_DEVICE* freerdp_device_collection_find(rdpSettings* settings, const char*
|
||||
{
|
||||
device = (RDPDR_DEVICE*) settings->DeviceArray[index];
|
||||
|
||||
if (NULL == device->Name)
|
||||
if (!device->Name)
|
||||
continue;
|
||||
|
||||
if (strcmp(device->Name, name) == 0)
|
||||
@ -169,24 +169,27 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
|
||||
if (device->Type == RDPDR_DTYP_FILESYSTEM)
|
||||
{
|
||||
RDPDR_DRIVE* drive = (RDPDR_DRIVE*) device;
|
||||
RDPDR_DRIVE* _drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE));
|
||||
RDPDR_DRIVE* _drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
|
||||
|
||||
if (!_drive)
|
||||
return NULL;
|
||||
|
||||
_drive->Id = drive->Id;
|
||||
_drive->Type = drive->Type;
|
||||
|
||||
_drive->Name = _strdup(drive->Name);
|
||||
if (!_drive->Name)
|
||||
goto out_fs_name_error;
|
||||
|
||||
_drive->Path = _strdup(drive->Path);
|
||||
if (!_drive->Path)
|
||||
goto out_fs_path_error;
|
||||
|
||||
return (RDPDR_DEVICE*) _drive;
|
||||
|
||||
out_fs_path_error:
|
||||
out_fs_path_error:
|
||||
free(_drive->Name);
|
||||
out_fs_name_error:
|
||||
out_fs_name_error:
|
||||
free(_drive);
|
||||
return NULL;
|
||||
}
|
||||
@ -194,24 +197,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
|
||||
if (device->Type == RDPDR_DTYP_PRINT)
|
||||
{
|
||||
RDPDR_PRINTER* printer = (RDPDR_PRINTER*) device;
|
||||
RDPDR_PRINTER* _printer = (RDPDR_PRINTER*) malloc(sizeof(RDPDR_PRINTER));
|
||||
RDPDR_PRINTER* _printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER));
|
||||
|
||||
if (!_printer)
|
||||
return NULL;
|
||||
|
||||
_printer->Id = printer->Id;
|
||||
_printer->Type = printer->Type;
|
||||
_printer->Name = _strdup(printer->Name);
|
||||
if (!_printer->Name)
|
||||
goto out_print_name_error;
|
||||
_printer->DriverName = _strdup(printer->DriverName);
|
||||
if(!_printer->DriverName)
|
||||
goto out_print_path_error;
|
||||
|
||||
if (printer->Name)
|
||||
{
|
||||
_printer->Name = _strdup(printer->Name);
|
||||
if (!_printer->Name)
|
||||
goto out_print_name_error;
|
||||
}
|
||||
|
||||
if (printer->DriverName)
|
||||
{
|
||||
_printer->DriverName = _strdup(printer->DriverName);
|
||||
if (!_printer->DriverName)
|
||||
goto out_print_path_error;
|
||||
}
|
||||
|
||||
return (RDPDR_DEVICE*) _printer;
|
||||
|
||||
out_print_path_error:
|
||||
out_print_path_error:
|
||||
free(_printer->Name);
|
||||
out_print_name_error:
|
||||
out_print_name_error:
|
||||
free(_printer);
|
||||
return NULL;
|
||||
}
|
||||
@ -219,24 +231,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
|
||||
if (device->Type == RDPDR_DTYP_SMARTCARD)
|
||||
{
|
||||
RDPDR_SMARTCARD* smartcard = (RDPDR_SMARTCARD*) device;
|
||||
RDPDR_SMARTCARD* _smartcard = (RDPDR_SMARTCARD*) malloc(sizeof(RDPDR_SMARTCARD));
|
||||
RDPDR_SMARTCARD* _smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD));
|
||||
|
||||
if (!_smartcard)
|
||||
return NULL;
|
||||
|
||||
_smartcard->Id = smartcard->Id;
|
||||
_smartcard->Type = smartcard->Type;
|
||||
_smartcard->Name = _strdup(smartcard->Name);
|
||||
if (!_smartcard->Name)
|
||||
goto out_smartc_name_error;
|
||||
_smartcard->Path = _strdup(smartcard->Path);
|
||||
if (!_smartcard->Path)
|
||||
goto out_smartc_path_error;
|
||||
|
||||
if (smartcard->Name)
|
||||
{
|
||||
_smartcard->Name = _strdup(smartcard->Name);
|
||||
if (!_smartcard->Name)
|
||||
goto out_smartc_name_error;
|
||||
}
|
||||
|
||||
if (smartcard->Path)
|
||||
{
|
||||
_smartcard->Path = _strdup(smartcard->Path);
|
||||
if (!_smartcard->Path)
|
||||
goto out_smartc_path_error;
|
||||
}
|
||||
|
||||
return (RDPDR_DEVICE*) _smartcard;
|
||||
|
||||
out_smartc_path_error:
|
||||
out_smartc_path_error:
|
||||
free(_smartcard->Name);
|
||||
out_smartc_name_error:
|
||||
out_smartc_name_error:
|
||||
free(_smartcard);
|
||||
return NULL;
|
||||
}
|
||||
@ -244,24 +265,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
|
||||
if (device->Type == RDPDR_DTYP_SERIAL)
|
||||
{
|
||||
RDPDR_SERIAL* serial = (RDPDR_SERIAL*) device;
|
||||
RDPDR_SERIAL* _serial = (RDPDR_SERIAL*) malloc(sizeof(RDPDR_SERIAL));
|
||||
RDPDR_SERIAL* _serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL));
|
||||
|
||||
if (!_serial)
|
||||
return NULL;
|
||||
|
||||
_serial->Id = serial->Id;
|
||||
_serial->Type = serial->Type;
|
||||
_serial->Name = _strdup(serial->Name);
|
||||
if (!_serial->Name)
|
||||
goto out_serial_name_error;
|
||||
_serial->Path = _strdup(serial->Path);
|
||||
if (!_serial->Path)
|
||||
goto out_serial_path_error;
|
||||
|
||||
if (serial->Name)
|
||||
{
|
||||
_serial->Name = _strdup(serial->Name);
|
||||
if (!_serial->Name)
|
||||
goto out_serial_name_error;
|
||||
}
|
||||
|
||||
if (serial->Path)
|
||||
{
|
||||
_serial->Path = _strdup(serial->Path);
|
||||
if (!_serial->Path)
|
||||
goto out_serial_path_error;
|
||||
}
|
||||
|
||||
return (RDPDR_DEVICE*) _serial;
|
||||
|
||||
out_serial_path_error:
|
||||
out_serial_path_error:
|
||||
free(_serial->Name);
|
||||
out_serial_name_error:
|
||||
out_serial_name_error:
|
||||
free(_serial);
|
||||
return NULL;
|
||||
}
|
||||
@ -269,23 +299,32 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
|
||||
if (device->Type == RDPDR_DTYP_PARALLEL)
|
||||
{
|
||||
RDPDR_PARALLEL* parallel = (RDPDR_PARALLEL*) device;
|
||||
RDPDR_PARALLEL* _parallel = (RDPDR_PARALLEL*) malloc(sizeof(RDPDR_PARALLEL));
|
||||
RDPDR_PARALLEL* _parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL));
|
||||
|
||||
if (!_parallel)
|
||||
return NULL;
|
||||
|
||||
_parallel->Id = parallel->Id;
|
||||
_parallel->Type = parallel->Type;
|
||||
_parallel->Name = _strdup(parallel->Name);
|
||||
if (!_parallel->Name)
|
||||
goto out_parallel_name_error;
|
||||
_parallel->Path = _strdup(parallel->Path);
|
||||
if (!_parallel->Path)
|
||||
goto out_parallel_path_error;
|
||||
|
||||
if (parallel->Name)
|
||||
{
|
||||
_parallel->Name = _strdup(parallel->Name);
|
||||
if (!_parallel->Name)
|
||||
goto out_parallel_name_error;
|
||||
}
|
||||
|
||||
if (parallel->Path)
|
||||
{
|
||||
_parallel->Path = _strdup(parallel->Path);
|
||||
if (!_parallel->Path)
|
||||
goto out_parallel_path_error;
|
||||
}
|
||||
|
||||
return (RDPDR_DEVICE*) _parallel;
|
||||
out_parallel_path_error:
|
||||
out_parallel_path_error:
|
||||
free(_parallel->Name);
|
||||
out_parallel_name_error:
|
||||
out_parallel_name_error:
|
||||
free(_parallel);
|
||||
return NULL;
|
||||
|
||||
|
@ -251,6 +251,11 @@ BOOL rdp_client_connect(rdpRdp* rdp)
|
||||
|
||||
if (!nego_connect(rdp->nego))
|
||||
{
|
||||
if (!freerdp_get_last_error(rdp->context))
|
||||
{
|
||||
freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Error: protocol security negotiation or connection failure\n");
|
||||
return FALSE;
|
||||
}
|
||||
@ -286,7 +291,14 @@ BOOL rdp_client_connect(rdpRdp* rdp)
|
||||
while (rdp->state != CONNECTION_STATE_ACTIVE)
|
||||
{
|
||||
if (rdp_check_fds(rdp) < 0)
|
||||
{
|
||||
if (!freerdp_get_last_error(rdp->context))
|
||||
{
|
||||
freerdp_set_last_error(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -192,11 +192,6 @@ BOOL freerdp_connect(freerdp* instance)
|
||||
freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
|
||||
}
|
||||
|
||||
if (!connectErrorCode)
|
||||
{
|
||||
connectErrorCode = UNDEFINEDCONNECTERROR;
|
||||
}
|
||||
|
||||
SetEvent(rdp->transport->connectedEvent);
|
||||
|
||||
freerdp_connect_finally:
|
||||
|
@ -224,6 +224,7 @@ BIO_METHOD* BIO_s_tsg(void)
|
||||
|
||||
BOOL transport_connect_tls(rdpTransport* transport)
|
||||
{
|
||||
int tls_status;
|
||||
freerdp* instance;
|
||||
rdpContext* context;
|
||||
|
||||
@ -245,13 +246,23 @@ BOOL transport_connect_tls(rdpTransport* transport)
|
||||
if (transport->TsgTls->port == 0)
|
||||
transport->TsgTls->port = 3389;
|
||||
|
||||
if (!tls_connect(transport->TsgTls))
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
connectErrorCode = TLSCONNECTERROR;
|
||||
tls_status = tls_connect(transport->TsgTls);
|
||||
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
connectErrorCode = TLSCONNECTERROR;
|
||||
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
|
||||
}
|
||||
|
||||
tls_free(transport->TsgTls);
|
||||
transport->TsgTls = NULL;
|
||||
@ -277,13 +288,23 @@ BOOL transport_connect_tls(rdpTransport* transport)
|
||||
if (transport->TlsIn->port == 0)
|
||||
transport->TlsIn->port = 3389;
|
||||
|
||||
if (!tls_connect(transport->TlsIn))
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
connectErrorCode = TLSCONNECTERROR;
|
||||
tls_status = tls_connect(transport->TlsIn);
|
||||
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
{
|
||||
if (!connectErrorCode)
|
||||
connectErrorCode = TLSCONNECTERROR;
|
||||
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
|
||||
}
|
||||
|
||||
tls_free(transport->TlsIn);
|
||||
|
||||
@ -317,6 +338,7 @@ BOOL transport_connect_nla(rdpTransport* transport)
|
||||
if (!transport->credssp)
|
||||
{
|
||||
transport->credssp = credssp_new(instance, transport, settings);
|
||||
transport_set_nla_mode(transport, TRUE);
|
||||
|
||||
if (settings->AuthenticationServiceClass)
|
||||
{
|
||||
@ -338,11 +360,14 @@ BOOL transport_connect_nla(rdpTransport* transport)
|
||||
fprintf(stderr, "Authentication failure, check credentials.\n"
|
||||
"If credentials are valid, the NTLMSSP implementation may be to blame.\n");
|
||||
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
credssp_free(transport->credssp);
|
||||
transport->credssp = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
credssp_free(transport->credssp);
|
||||
transport->credssp = NULL;
|
||||
|
||||
@ -351,7 +376,15 @@ BOOL transport_connect_nla(rdpTransport* transport)
|
||||
|
||||
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port)
|
||||
{
|
||||
rdpTsg* tsg = tsg_new(transport);
|
||||
rdpTsg* tsg;
|
||||
int tls_status;
|
||||
freerdp* instance;
|
||||
rdpContext* context;
|
||||
|
||||
instance = (freerdp*) transport->settings->instance;
|
||||
context = instance->context;
|
||||
|
||||
tsg = tsg_new(transport);
|
||||
|
||||
tsg->transport = transport;
|
||||
transport->tsg = tsg;
|
||||
@ -377,11 +410,41 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
|
||||
if (transport->TlsOut->port == 0)
|
||||
transport->TlsOut->port = 443;
|
||||
|
||||
if (!tls_connect(transport->TlsIn))
|
||||
return FALSE;
|
||||
tls_status = tls_connect(transport->TlsIn);
|
||||
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
|
||||
}
|
||||
|
||||
if (!tls_connect(transport->TlsOut))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tls_status = tls_connect(transport->TlsOut);
|
||||
|
||||
if (tls_status < 1)
|
||||
{
|
||||
if (tls_status < 0)
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!freerdp_get_last_error(context))
|
||||
freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsg_connect(tsg, hostname, port))
|
||||
return FALSE;
|
||||
@ -481,11 +544,16 @@ BOOL transport_accept_nla(rdpTransport* transport)
|
||||
return TRUE;
|
||||
|
||||
if (!transport->credssp)
|
||||
{
|
||||
transport->credssp = credssp_new(instance, transport, settings);
|
||||
transport_set_nla_mode(transport, TRUE);
|
||||
}
|
||||
|
||||
if (credssp_authenticate(transport->credssp) < 0)
|
||||
{
|
||||
fprintf(stderr, "client authentication failure\n");
|
||||
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
credssp_free(transport->credssp);
|
||||
transport->credssp = NULL;
|
||||
|
||||
@ -495,6 +563,7 @@ BOOL transport_accept_nla(rdpTransport* transport)
|
||||
}
|
||||
|
||||
/* don't free credssp module yet, we need to copy the credentials from it first */
|
||||
transport_set_nla_mode(transport, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -643,49 +712,56 @@ int transport_read(rdpTransport* transport, wStream* s)
|
||||
|
||||
CopyMemory(header, Stream_Buffer(s), 4); /* peek at first 4 bytes */
|
||||
|
||||
/* if header is present, read in exactly one PDU */
|
||||
if (header[0] == 0x03)
|
||||
{
|
||||
/* TPKT header */
|
||||
/* if header is present, read exactly one PDU */
|
||||
|
||||
pduLength = (header[2] << 8) | header[3];
|
||||
}
|
||||
else if (header[0] == 0x30)
|
||||
if (transport->NlaMode)
|
||||
{
|
||||
/* TSRequest (NLA) */
|
||||
|
||||
if (header[1] & 0x80)
|
||||
if (header[0] == 0x30)
|
||||
{
|
||||
if ((header[1] & ~(0x80)) == 1)
|
||||
/* TSRequest (NLA) */
|
||||
|
||||
if (header[1] & 0x80)
|
||||
{
|
||||
pduLength = header[2];
|
||||
pduLength += 3;
|
||||
}
|
||||
else if ((header[1] & ~(0x80)) == 2)
|
||||
{
|
||||
pduLength = (header[2] << 8) | header[3];
|
||||
pduLength += 4;
|
||||
if ((header[1] & ~(0x80)) == 1)
|
||||
{
|
||||
pduLength = header[2];
|
||||
pduLength += 3;
|
||||
}
|
||||
else if ((header[1] & ~(0x80)) == 2)
|
||||
{
|
||||
pduLength = (header[2] << 8) | header[3];
|
||||
pduLength += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error reading TSRequest!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error reading TSRequest!\n");
|
||||
return -1;
|
||||
pduLength = header[1];
|
||||
pduLength += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pduLength = header[1];
|
||||
pduLength += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fast-Path Header */
|
||||
if (header[0] == 0x03)
|
||||
{
|
||||
/* TPKT header */
|
||||
|
||||
if (header[1] & 0x80)
|
||||
pduLength = ((header[1] & 0x7F) << 8) | header[2];
|
||||
pduLength = (header[2] << 8) | header[3];
|
||||
}
|
||||
else
|
||||
pduLength = header[1];
|
||||
{
|
||||
/* Fast-Path Header */
|
||||
|
||||
if (header[1] & 0x80)
|
||||
pduLength = ((header[1] & 0x7F) << 8) | header[2];
|
||||
else
|
||||
pduLength = header[1];
|
||||
}
|
||||
}
|
||||
|
||||
status = transport_read_layer(transport, Stream_Buffer(s) + position, pduLength - position);
|
||||
@ -889,72 +965,78 @@ int transport_check_fds(rdpTransport* transport)
|
||||
* Loop through and read all available PDUs. Since multiple
|
||||
* PDUs can exist, it's important to deliver them all before
|
||||
* returning. Otherwise we run the risk of having a thread
|
||||
* wait for a socket to get signalled that data is available
|
||||
* wait for a socket to get signaled that data is available
|
||||
* (which may never happen).
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
status = transport_read_nonblocking(transport);
|
||||
|
||||
if (status < 0 || Stream_GetPosition(transport->ReceiveBuffer) == 0)
|
||||
if ((status <= 0) || (Stream_GetPosition(transport->ReceiveBuffer) < 2))
|
||||
return status;
|
||||
|
||||
while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, 0);
|
||||
|
||||
if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */
|
||||
if (transport->NlaMode)
|
||||
{
|
||||
/* Ensure the TPKT header is available. */
|
||||
if (pos <= 4)
|
||||
if (nla_verify_header(transport->ReceiveBuffer))
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
/* TSRequest */
|
||||
|
||||
length = tpkt_read_header(transport->ReceiveBuffer);
|
||||
/* Ensure the TSRequest header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TSRequest header can be 2, 3 or 4 bytes long */
|
||||
length = nla_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = nla_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
}
|
||||
else if (nla_verify_header(transport->ReceiveBuffer))
|
||||
else
|
||||
{
|
||||
/* TSRequest */
|
||||
|
||||
/* Ensure the TSRequest header is available. */
|
||||
if (pos <= 4)
|
||||
if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
/* Ensure the TPKT header is available. */
|
||||
if (pos <= 4)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = tpkt_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
|
||||
/* TSRequest header can be 2, 3 or 4 bytes long */
|
||||
length = nla_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
else /* Fast Path */
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
/* Ensure the Fast Path header is available. */
|
||||
if (pos <= 2)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fastpath header can be two or three bytes long. */
|
||||
length = fastpath_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = fastpath_read_header(NULL, transport->ReceiveBuffer);
|
||||
}
|
||||
|
||||
length = nla_read_header(transport->ReceiveBuffer);
|
||||
}
|
||||
else /* Fast Path */
|
||||
{
|
||||
/* Ensure the Fast Path header is available. */
|
||||
if (pos <= 2)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fastpath header can be two or three bytes long. */
|
||||
length = fastpath_header_length(transport->ReceiveBuffer);
|
||||
|
||||
if (pos < length)
|
||||
{
|
||||
Stream_SetPosition(transport->ReceiveBuffer, pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
length = fastpath_read_header(NULL, transport->ReceiveBuffer);
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
@ -1039,6 +1121,11 @@ void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled)
|
||||
transport->GatewayEnabled = GatewayEnabled;
|
||||
}
|
||||
|
||||
void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode)
|
||||
{
|
||||
transport->NlaMode = NlaMode;
|
||||
}
|
||||
|
||||
static void* transport_client_thread(void* arg)
|
||||
{
|
||||
DWORD status;
|
||||
|
@ -75,6 +75,7 @@ struct rdp_transport
|
||||
HANDLE stopEvent;
|
||||
HANDLE thread;
|
||||
BOOL async;
|
||||
BOOL NlaMode;
|
||||
BOOL GatewayEnabled;
|
||||
CRITICAL_SECTION ReadLock;
|
||||
CRITICAL_SECTION WriteLock;
|
||||
@ -99,6 +100,7 @@ void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount);
|
||||
int transport_check_fds(rdpTransport* transport);
|
||||
BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking);
|
||||
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled);
|
||||
void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode);
|
||||
void transport_get_read_handles(rdpTransport* transport, HANDLE* events, DWORD* count);
|
||||
|
||||
wStream* transport_receive_pool_take(rdpTransport* transport);
|
||||
|
@ -105,10 +105,11 @@ static void tls_ssl_info_callback(const SSL* ssl, int type, int val)
|
||||
}
|
||||
}
|
||||
|
||||
BOOL tls_connect(rdpTls* tls)
|
||||
int tls_connect(rdpTls* tls)
|
||||
{
|
||||
CryptoCert cert;
|
||||
long options = 0;
|
||||
int verify_status;
|
||||
int connection_status;
|
||||
|
||||
tls->ctx = SSL_CTX_new(TLSv1_client_method());
|
||||
@ -116,7 +117,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
if (!tls->ctx)
|
||||
{
|
||||
fprintf(stderr, "SSL_CTX_new failed\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//SSL_CTX_set_mode(tls->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
@ -157,7 +158,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
if (!tls->ssl)
|
||||
{
|
||||
fprintf(stderr, "SSL_new failed\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tls->tsg)
|
||||
@ -167,7 +168,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
if (!tls->bio)
|
||||
{
|
||||
fprintf(stderr, "BIO_new failed\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tls->bio->ptr = tls->tsg;
|
||||
@ -181,7 +182,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
|
||||
{
|
||||
fprintf(stderr, "SSL_set_fd failed\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +192,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
{
|
||||
if (tls_print_error("SSL_connect", tls->ssl, connection_status))
|
||||
{
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,7 +201,7 @@ BOOL tls_connect(rdpTls* tls)
|
||||
if (!cert)
|
||||
{
|
||||
fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tls->Bindings = tls_get_channel_bindings(cert->px509);
|
||||
@ -209,20 +210,22 @@ BOOL tls_connect(rdpTls* tls)
|
||||
{
|
||||
fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n");
|
||||
tls_free_certificate(cert);
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!tls_verify_certificate(tls, cert, tls->hostname, tls->port))
|
||||
verify_status = tls_verify_certificate(tls, cert, tls->hostname, tls->port);
|
||||
|
||||
if (verify_status < 1)
|
||||
{
|
||||
fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n");
|
||||
tls_disconnect(tls);
|
||||
tls_free_certificate(cert);
|
||||
return FALSE;
|
||||
return verify_status;
|
||||
}
|
||||
|
||||
tls_free_certificate(cert);
|
||||
|
||||
return TRUE;
|
||||
return (verify_status == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
BOOL tls_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file)
|
||||
@ -612,7 +615,7 @@ BOOL tls_match_hostname(char *pattern, int pattern_length, char *hostname)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port)
|
||||
int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int port)
|
||||
{
|
||||
int match;
|
||||
int index;
|
||||
@ -644,7 +647,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
if (!bio)
|
||||
{
|
||||
fprintf(stderr, "tls_verify_certificate: BIO_new() failure\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = PEM_write_bio_X509(bio, cert->px509);
|
||||
@ -652,7 +655,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
if (status < 0)
|
||||
{
|
||||
fprintf(stderr, "tls_verify_certificate: PEM_write_bio_X509 failure: %d\n", status);
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
@ -664,7 +667,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
if (status < 0)
|
||||
{
|
||||
fprintf(stderr, "tls_verify_certificate: failed to read certificate\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset += status;
|
||||
@ -685,7 +688,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
if (status < 0)
|
||||
{
|
||||
fprintf(stderr, "tls_verify_certificate: failed to read certificate\n");
|
||||
return FALSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
length = offset;
|
||||
@ -704,12 +707,15 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
free(pemCert);
|
||||
BIO_free(bio);
|
||||
|
||||
return (status < 0) ? FALSE : TRUE;
|
||||
if (status < 0)
|
||||
return -1;
|
||||
|
||||
return (status == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* ignore certificate verification if user explicitly required it (discouraged) */
|
||||
if (tls->settings->IgnoreCertificate)
|
||||
return TRUE; /* success! */
|
||||
return 1; /* success! */
|
||||
|
||||
/* if user explicitly specified a certificate name, use it instead of the hostname */
|
||||
if (tls->settings->CertificateName)
|
||||
@ -727,7 +733,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
|
||||
/* compare against common name */
|
||||
|
||||
if (common_name != NULL)
|
||||
if (common_name)
|
||||
{
|
||||
if (tls_match_hostname(common_name, common_name_length, hostname))
|
||||
hostname_match = TRUE;
|
||||
@ -735,7 +741,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
|
||||
/* compare against alternative names */
|
||||
|
||||
if (alt_names != NULL)
|
||||
if (alt_names)
|
||||
{
|
||||
for (index = 0; index < alt_names_count; index++)
|
||||
{
|
||||
@ -851,7 +857,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
|
||||
crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths,
|
||||
alt_names);
|
||||
|
||||
return verification_status;
|
||||
return (verification_status == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
|
||||
#include <freerdp/gdi/dc.h>
|
||||
#include <freerdp/gdi/drawing.h>
|
||||
|
||||
/**
|
||||
* Set current foreground draw mode.\n
|
||||
|
Loading…
Reference in New Issue
Block a user