Merge pull request #1764 from awakecoding/ports

Serial Port Improvements
This commit is contained in:
Marc-André Moreau 2014-04-01 21:37:25 -04:00
commit 8bf5559f51
20 changed files with 587 additions and 786 deletions

View File

@ -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")

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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]);

View File

@ -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___ */

View File

@ -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);

View File

@ -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
}

View File

@ -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 */

View File

@ -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++)

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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;

View File

@ -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);

View File

@ -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)

View 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