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") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
else() else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
endif() endif()
if(WITH_SSE2) if(WITH_SSE2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2") 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); MessageQueue_PostQuit(parallel->queue, 0);
WaitForSingleObject(parallel->thread, INFINITE); WaitForSingleObject(parallel->thread, INFINITE);
CloseHandle(parallel->thread);
Stream_Free(parallel->device.data, TRUE); Stream_Free(parallel->device.data, TRUE);
MessageQueue_Free(parallel->queue); MessageQueue_Free(parallel->queue);
CloseHandle(parallel->thread);
free(parallel); free(parallel);
} }
@ -309,10 +309,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
name = device->Name; name = device->Name;
path = device->Path; path = device->Path;
if (!name || (name[0] == '*'))
{
/* TODO: implement auto detection of parallel ports */
return 0;
}
if (name[0] && path[0]) if (name[0] && path[0])
{ {
parallel = (PARALLEL_DEVICE*) malloc(sizeof(PARALLEL_DEVICE)); parallel = (PARALLEL_DEVICE*) calloc(1, sizeof(PARALLEL_DEVICE));
ZeroMemory(parallel, sizeof(PARALLEL_DEVICE));
if (!parallel)
return -1;
parallel->device.type = RDPDR_DTYP_PARALLEL; parallel->device.type = RDPDR_DTYP_PARALLEL;
parallel->device.name = name; parallel->device.name = name;

View File

@ -45,6 +45,7 @@
#include "serial_constants.h" #include "serial_constants.h"
#include <winpr/crt.h> #include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/synch.h> #include <winpr/synch.h>
#include <winpr/thread.h> #include <winpr/thread.h>
#include <winpr/stream.h> #include <winpr/stream.h>
@ -64,39 +65,27 @@ struct _SERIAL_DEVICE
char* path; char* path;
SERIAL_TTY* tty; SERIAL_TTY* tty;
wLog* log;
HANDLE thread; HANDLE thread;
HANDLE mthread; wMessageQueue* IrpQueue;
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;
}; };
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) static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{ {
char* path = NULL;
int status; int status;
SERIAL_TTY* tty;
UINT32 PathLength;
UINT32 FileId; UINT32 FileId;
UINT32 PathLength;
char* path = NULL;
SERIAL_TTY* tty;
Stream_Seek(irp->input, 28); /* DesiredAccess(4) AllocationSize(8), FileAttributes(4) */ Stream_Seek_UINT32(irp->input); /* DesiredAccess (4 bytes) */
/* SharedAccess(4) CreateDisposition(4), CreateOptions(4) */ Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
Stream_Read_UINT32(irp->input, PathLength); 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), status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
PathLength / 2, &path, 0, NULL, NULL); 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); tty = serial_tty_new(serial->path, FileId);
if (tty == NULL) if (!tty)
{ {
irp->IoStatus = STATUS_UNSUCCESSFUL; irp->IoStatus = STATUS_UNSUCCESSFUL;
FileId = 0; FileId = 0;
@ -118,23 +107,11 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
else else
{ {
serial->tty = tty; 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); DEBUG_SVC("%s(%d) created.", serial->path, FileId);
} }
Stream_Write_UINT32(irp->output, FileId); Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
Stream_Write_UINT8(irp->output, 0); Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
free(path); 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) 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; irp->IoStatus = STATUS_UNSUCCESSFUL;
DEBUG_WARN("tty not valid."); 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); 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_free(tty);
serial->tty = NULL; serial->tty = NULL;
} }
Stream_Zero(irp->output, 5); /* Padding(5) */ Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
irp->Complete(irp); irp->Complete(irp);
} }
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{ {
SERIAL_TTY* tty;
UINT32 Length; UINT32 Length;
UINT64 Offset; UINT64 Offset;
BYTE* buffer = NULL; BYTE* buffer = NULL;
SERIAL_TTY* tty = serial->tty;
Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); 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); if (!tty)
tty = serial->tty;
if (tty == NULL)
{ {
irp->IoStatus = STATUS_UNSUCCESSFUL; irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0; 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) 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) static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{ {
SERIAL_TTY* tty; int status;
UINT32 Length; UINT32 Length;
UINT64 Offset; UINT64 Offset;
SERIAL_TTY* tty = serial->tty;
Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
Stream_Seek(irp->input, 20); /* Padding */ Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
DEBUG_SVC("length %u offset %llu", Length, Offset); if (!tty)
tty = serial->tty;
if (tty == NULL)
{ {
irp->IoStatus = STATUS_UNSUCCESSFUL; irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0; Length = 0;
DEBUG_WARN("tty not valid."); 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; irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0; Length = 0;
DEBUG_WARN("write %s(%d) failed.", serial->path, tty->id); printf("serial_tty_write failure: status: %d, errno: %d\n", status, errno);
}
else Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
{ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
DEBUG_SVC("write %llu-%llu to %s(%d).", Offset, Offset + Length, serial->path, tty->id); irp->Complete(irp);
return;
} }
Stream_Write_UINT32(irp->output, Length); Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding */ Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
irp->Complete(irp); irp->Complete(irp);
} }
static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp) static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
{ {
SERIAL_TTY* tty;
UINT32 IoControlCode; UINT32 IoControlCode;
UINT32 InputBufferLength; UINT32 InputBufferLength;
UINT32 OutputBufferLength; 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, OutputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, InputBufferLength); Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
Stream_Read_UINT32(irp->input, OutputBufferLength); Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
Stream_Read_UINT32(irp->input, IoControlCode);
Stream_Seek(irp->input, 20); /* Padding */
tty = serial->tty;
if (!tty) if (!tty)
{ {
@ -288,23 +258,16 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
} }
else 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) irp->Complete(irp);
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);
} }
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* 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) switch (irp->MajorFunction)
{ {
@ -317,13 +280,11 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
break; break;
case IRP_MJ_READ: case IRP_MJ_READ:
serial_handle_async_irp(serial, irp); serial_process_irp_read(serial, irp);
//serial_process_irp_read(serial, irp);
break; break;
case IRP_MJ_WRITE: case IRP_MJ_WRITE:
serial_handle_async_irp(serial, irp); serial_process_irp_write(serial, irp);
//serial_process_irp_write(serial, irp);
break; break;
case IRP_MJ_DEVICE_CONTROL: case IRP_MJ_DEVICE_CONTROL:
@ -336,74 +297,29 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
irp->Complete(irp); irp->Complete(irp);
break; 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) static void* serial_thread_func(void* arg)
{ {
IRP* irp; IRP* irp;
DWORD status; wMessage message;
SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg; SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg;
HANDLE ev[] = {serial->stopEvent, Queue_Event(serial->queue), serial->newEvent};
assert(NULL != serial);
while (1) while (1)
{ {
status = WaitForMultipleObjects(3, ev, FALSE, INFINITE); if (!MessageQueue_Wait(drive->IrpQueue))
if (WAIT_OBJECT_0 == status)
break; break;
else if (status == WAIT_OBJECT_0 + 1)
{
FD_ZERO(&serial->read_fds);
FD_ZERO(&serial->write_fds);
serial->tv.tv_sec = 0; if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
serial->tv.tv_usec = 0; break;
serial->select_timeout = 0;
if ((irp = (IRP*) Queue_Dequeue(serial->queue))) if (message.id == WMQ_QUIT)
serial_process_irp(serial, irp); break;
}
else if (status == WAIT_OBJECT_0 + 2)
ResetEvent(serial->newEvent);
if(serial->tty) irp = (IRP*) message.wParam;
serial_check_fds(serial);
if (irp)
serial_process_irp(drive, irp);
} }
ExitThread(0); ExitThread(0);
@ -413,366 +329,28 @@ static void* serial_thread_func(void* arg)
static void serial_irp_request(DEVICE* device, IRP* irp) static void serial_irp_request(DEVICE* device, IRP* irp)
{ {
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL);
Queue_Enqueue(serial->queue, irp);
} }
static void serial_free(DEVICE* device) static void serial_free(DEVICE* device)
{ {
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device; SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
DEBUG_SVC("freeing device"); WLog_Print(serial->log, WLOG_DEBUG, "freeing");
/* Stop thread */ MessageQueue_PostQuit(serial->IrpQueue, 0);
SetEvent(serial->stopEvent);
if(serial->mthread)
{
TerminateThread(serial->mthread, 0);
WaitForSingleObject(serial->mthread, INFINITE);
CloseHandle(serial->mthread);
}
WaitForSingleObject(serial->thread, INFINITE); WaitForSingleObject(serial->thread, INFINITE);
CloseHandle(serial->thread);
serial_tty_free(serial->tty); serial_tty_free(serial->tty);
/* Clean up resources */ /* Clean up resources */
Stream_Free(serial->device.data, TRUE); Stream_Free(serial->device.data, TRUE);
Queue_Free(serial->queue); MessageQueue_Free(serial->IrpQueue);
list_free(serial->pending_irps);
CloseHandle(serial->stopEvent);
CloseHandle(serial->newEvent);
CloseHandle(serial->thread);
free(serial); 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 #ifdef STATIC_CHANNELS
#define DeviceServiceEntry serial_DeviceServiceEntry #define DeviceServiceEntry serial_DeviceServiceEntry
#endif #endif
@ -789,10 +367,18 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
name = device->Name; name = device->Name;
path = device->Path; path = device->Path;
if (!name || (name[0] == '*'))
{
/* TODO: implement auto detection of parallel ports */
return 0;
}
if ((name && name[0]) && (path && path[0])) if ((name && name[0]) && (path && path[0]))
{ {
serial = (SERIAL_DEVICE*) malloc(sizeof(SERIAL_DEVICE)); serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
ZeroMemory(serial, sizeof(SERIAL_DEVICE));
if (!serial)
return -1;
serial->device.type = RDPDR_DTYP_SERIAL; serial->device.type = RDPDR_DTYP_SERIAL;
serial->device.name = name; 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]); Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
serial->path = path; serial->path = path;
serial->queue = Queue_New(TRUE, -1, -1); serial->IrpQueue = MessageQueue_New(NULL);
serial->pending_irps = list_new();
serial->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); WLog_Init();
serial->newEvent = CreateEvent(NULL, TRUE, FALSE, NULL); serial->log = WLog_Get("com.freerdp.channel.serial.client");
WLog_Print(serial->log, WLOG_DEBUG, "initializing");
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial); pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
serial->thread = CreateThread(NULL, 0, serial->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL); (LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
serial->mthread = NULL;
} }
return 0; return 0;

View File

@ -73,24 +73,47 @@
#define TIOCOUTQ FIONWRITE #define TIOCOUTQ FIONWRITE
#endif #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 UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len);
static void tty_set_termios(SERIAL_TTY* tty); static void tty_set_termios(SERIAL_TTY* tty);
static BOOL tty_get_termios(SERIAL_TTY* tty); static BOOL tty_get_termios(SERIAL_TTY* tty);
static int tty_get_error_status(); 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 result;
UINT32 modemstate;
BYTE immediate; BYTE immediate;
UINT32 ret = STATUS_SUCCESS; int purge_mask;
UINT32 length = 0; UINT32 modemstate;
UINT32 pos; 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) switch (IoControlCode)
{ {
@ -101,7 +124,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break; break;
case IOCTL_SERIAL_GET_BAUD_RATE: case IOCTL_SERIAL_GET_BAUD_RATE:
length = 4; OutputBufferLength = 4;
Stream_Write_UINT32(output, tty->baud_rate); Stream_Write_UINT32(output, tty->baud_rate);
DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate); DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
break; break;
@ -123,7 +146,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
case IOCTL_SERIAL_GET_LINE_CONTROL: case IOCTL_SERIAL_GET_LINE_CONTROL:
DEBUG_SVC("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->stop_bits);
Stream_Write_UINT8(output, tty->parity); Stream_Write_UINT8(output, tty->parity);
Stream_Write_UINT8(output, tty->word_length); 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: case IOCTL_SERIAL_CONFIG_SIZE:
DEBUG_SVC("SERIAL_CONFIG_SIZE"); DEBUG_SVC("SERIAL_CONFIG_SIZE");
length = 4; OutputBufferLength = 4;
Stream_Write_UINT32(output, 0); Stream_Write_UINT32(output, 0);
break; break;
case IOCTL_SERIAL_GET_CHARS: case IOCTL_SERIAL_GET_CHARS:
DEBUG_SVC("SERIAL_GET_CHARS"); DEBUG_SVC("SERIAL_GET_CHARS");
length = 6; OutputBufferLength = 6;
Stream_Write(output, tty->chars, 6); Stream_Write(output, tty->chars, 6);
break; break;
@ -154,7 +177,7 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break; break;
case IOCTL_SERIAL_GET_HANDFLOW: case IOCTL_SERIAL_GET_HANDFLOW:
length = 16; OutputBufferLength = 16;
tty_get_termios(tty); tty_get_termios(tty);
Stream_Write_UINT32(output, tty->control); Stream_Write_UINT32(output, tty->control);
Stream_Write_UINT32(output, tty->xonoff); 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_interval_timeout,
tty->read_total_timeout_multiplier, tty->read_total_timeout_multiplier,
tty->read_total_timeout_constant); tty->read_total_timeout_constant);
length = 20; OutputBufferLength = 20;
Stream_Write_UINT32(output, tty->read_interval_timeout); 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_multiplier);
Stream_Write_UINT32(output, tty->read_total_timeout_constant); 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: case IOCTL_SERIAL_GET_WAIT_MASK:
DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask); DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
length = 4; OutputBufferLength = 4;
Stream_Write_UINT32(output, tty->wait_mask); Stream_Write_UINT32(output, tty->wait_mask);
break; break;
@ -269,12 +292,12 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
modemstate |= SERIAL_MS_RTS; modemstate |= SERIAL_MS_RTS;
#endif #endif
DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate); DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
length = 4; OutputBufferLength = 4;
Stream_Write_UINT32(output, modemstate); Stream_Write_UINT32(output, modemstate);
break; break;
case IOCTL_SERIAL_GET_COMMSTATUS: case IOCTL_SERIAL_GET_COMMSTATUS:
length = 18; OutputBufferLength = 18;
Stream_Write_UINT32(output, 0); /* Errors */ Stream_Write_UINT32(output, 0); /* Errors */
Stream_Write_UINT32(output, 0); /* Hold reasons */ Stream_Write_UINT32(output, 0); /* Hold reasons */
@ -316,21 +339,21 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
#endif #endif
if (purge_mask & SERIAL_PURGE_TXABORT) if (purge_mask & SERIAL_PURGE_TXABORT)
*abort_io |= SERIAL_ABORT_IO_WRITE; *abortIo |= SERIAL_ABORT_IO_WRITE;
if (purge_mask & SERIAL_PURGE_RXABORT) if (purge_mask & SERIAL_PURGE_RXABORT)
*abort_io |= SERIAL_ABORT_IO_READ; *abortIo |= SERIAL_ABORT_IO_READ;
break; break;
case IOCTL_SERIAL_WAIT_ON_MASK: case IOCTL_SERIAL_WAIT_ON_MASK:
DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask); DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
tty->event_pending = 1; tty->event_pending = 1;
length = 4; OutputBufferLength = 4;
if (serial_tty_get_event(tty, &result)) if (serial_tty_get_event(tty, &result))
{ {
DEBUG_SVC("WAIT end event = %X", result); DEBUG_SVC("WAIT end event = %X", result);
Stream_Write_UINT32(output, result); Stream_Write_UINT32(output, result);
break; break;
} }
ret = STATUS_PENDING; status = STATUS_PENDING;
break; break;
case IOCTL_SERIAL_SET_BREAK_ON: case IOCTL_SERIAL_SET_BREAK_ON:
@ -356,27 +379,33 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
break; break;
default: default:
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL %d", IoControlCode); DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL 0x%08X", IoControlCode);
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
/* Write OutputBufferLength */ endPos = (UINT32) Stream_GetPosition(output);
pos = Stream_GetPosition(output); OutputBufferLength = endPos - begPos;
Stream_SetPosition(output, 16);
Stream_Write_UINT32(output, length);
Stream_SetPosition(output, pos);
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) BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
{ {
ssize_t status; ssize_t status;
long timeout = 90; long timeout = 90;
struct termios* ptermios;
DEBUG_SVC("in");
ptermios = tty->ptermios;
/* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout /* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
with requested read size */ 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; timeout = (tty->read_interval_timeout * (*Length) + 99) / 100;
} }
/* If a timeout is set, do a blocking read, which times out after some time. if (tty->timeout != timeout)
It will make FreeRDP less responsive, but it will improve serial performance, {
by not reading one character at a time. */ struct termios* ptermios;
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); 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); ZeroMemory(buffer, *Length);
@ -424,20 +467,21 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
return TRUE; 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; UINT32 event_txempty = Length;
DEBUG_SVC("in");
while (Length > 0) while (Length > 0)
{ {
status = write(tty->fd, buffer, Length); status = write(tty->fd, buffer, Length);
if (status < 0) if (status < 0)
{ {
return FALSE; if (errno == EAGAIN)
status = 0;
else
return status;
} }
Length -= status; Length -= status;
@ -446,7 +490,7 @@ BOOL serial_tty_write(SERIAL_TTY* tty, BYTE* buffer, UINT32 Length)
tty->event_txempty = event_txempty; 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) void serial_tty_free(SERIAL_TTY* tty)
{ {
DEBUG_SVC("in"); if (!tty)
if(!tty)
return; return;
if (tty->fd >= 0) if (tty->fd >= 0)
@ -480,8 +522,10 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
{ {
SERIAL_TTY* tty; SERIAL_TTY* tty;
tty = (SERIAL_TTY*) malloc(sizeof(SERIAL_TTY)); tty = (SERIAL_TTY*) calloc(1, sizeof(SERIAL_TTY));
ZeroMemory(tty, sizeof(SERIAL_TTY));
if (!tty)
return NULL;
tty->id = id; tty->id = id;
tty->fd = open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); 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); DEBUG_SVC("tty fd %d successfully opened", tty->fd);
} }
tty->ptermios = (struct termios*) malloc(sizeof(struct termios)); tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios));
ZeroMemory(tty->ptermios, sizeof(struct termios));
if (tty->ptermios == NULL) if (!tty->ptermios)
{ {
serial_tty_free(tty); serial_tty_free(tty);
return NULL ; return NULL;
} }
tty->pold_termios = (struct termios*) malloc(sizeof(struct termios)); tty->pold_termios = (struct termios*) calloc(1, sizeof(struct termios));
ZeroMemory(tty->pold_termios, sizeof(struct termios));
if (tty->pold_termios == NULL) if (!tty->pold_termios)
{ {
serial_tty_free(tty); serial_tty_free(tty);
return NULL; 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 &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty->ptermios->c_iflag = IGNPAR | ICRNL;
tty->ptermios->c_oflag &= ~OPOST; tty->ptermios->c_oflag &= ~OPOST;
tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tty->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty->ptermios->c_cflag &= ~(CSIZE | PARENB); 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); tcsetattr(tty->fd, TCSANOW, tty->ptermios);
tty->event_txempty = 0; tty->event_txempty = 0;
@ -558,8 +603,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
int bytes; int bytes;
BOOL status = FALSE; BOOL status = FALSE;
DEBUG_SVC("in");
*result = 0; *result = 0;
#ifdef TIOCINQ #ifdef TIOCINQ
@ -587,7 +630,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
*result |= SERIAL_EV_RLSD; *result |= SERIAL_EV_RLSD;
status = TRUE; status = TRUE;
} }
} }
if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG)) 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; *result |= SERIAL_EV_RXCHAR;
status = TRUE; status = TRUE;
} }
} }
else 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_BREAK] = ptermios->c_cc[VINTR];
tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL]; tty->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
tty->timeout = ptermios->c_cc[VTIME];
return TRUE; return TRUE;
} }
static void tty_set_termios(SERIAL_TTY* tty) static void tty_set_termios(SERIAL_TTY* tty)
{ {
speed_t speed; speed_t speed;
struct termios *ptermios; struct termios* ptermios;
DEBUG_SVC("in");
ptermios = tty->ptermios; ptermios = tty->ptermios;
switch (tty->baud_rate) switch (tty->baud_rate)
{ {
#ifdef B75 #ifdef B75
@ -1003,8 +1046,6 @@ static UINT32 tty_write_data(SERIAL_TTY* tty, BYTE* data, int len)
{ {
ssize_t status; ssize_t status;
DEBUG_SVC("in");
status = write(tty->fd, data, len); status = write(tty->fd, data, len);
if (status < 0) 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() static int tty_get_error_status()
{ {
DEBUG_SVC("in errno %d", errno);
switch (errno) switch (errno)
{ {
case EACCES: case EACCES:

View File

@ -65,13 +65,14 @@ struct _SERIAL_TTY
int event_dsr; int event_dsr;
int event_rlsd; int event_rlsd;
int event_pending; int event_pending;
long timeout;
}; };
SERIAL_TTY* serial_tty_new(const char* path, UINT32 id); SERIAL_TTY* serial_tty_new(const char* path, UINT32 id);
void serial_tty_free(SERIAL_TTY* tty); void serial_tty_free(SERIAL_TTY* tty);
BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length); 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); 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); 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; path = device->Path;
/* TODO: check if server supports sc redirect (version 5.1) */ /* TODO: check if server supports sc redirect (version 5.1) */
smartcard = (SMARTCARD_DEVICE*) malloc(sizeof(SMARTCARD_DEVICE)); smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE));
ZeroMemory(smartcard, sizeof(SMARTCARD_DEVICE));
if (!smartcard)
return -1;
smartcard->device.type = RDPDR_DTYP_SMARTCARD; smartcard->device.type = RDPDR_DTYP_SMARTCARD;
smartcard->device.name = "SCARD"; smartcard->device.name = "SCARD";
@ -337,6 +339,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
smartcard->name = NULL; smartcard->name = NULL;
smartcard->path = NULL; smartcard->path = NULL;
if (path) if (path)
{ {
smartcard->path = path; smartcard->path = path;

View File

@ -152,7 +152,7 @@ DWORD mac_client_update_thread(void* param)
} }
ExitThread(0); ExitThread(0);
return NULL; return 0;
} }
DWORD mac_client_input_thread(void* param) DWORD mac_client_input_thread(void* param)
@ -177,7 +177,7 @@ DWORD mac_client_input_thread(void* param)
} }
ExitThread(0); ExitThread(0);
return NULL; return 0;
} }
DWORD mac_client_channels_thread(void* param) DWORD mac_client_channels_thread(void* param)
@ -214,7 +214,7 @@ DWORD mac_client_channels_thread(void* param)
} }
ExitThread(0); ExitThread(0);
return NULL; return 0;
} }
DWORD mac_client_thread(void* param) 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" }, { "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" }, { "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" }, { "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" }, { "serial", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, "tty", "Redirect serial device" },
{ "parallel", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "Redirect parallel 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" }, { "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" }, { "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" }, { "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) if (count < 3)
return -1; return -1;
drive = (RDPDR_DRIVE*) malloc(sizeof(RDPDR_DRIVE)); drive = (RDPDR_DRIVE*) calloc(1, sizeof(RDPDR_DRIVE));
ZeroMemory(drive, sizeof(RDPDR_DRIVE));
if (!drive)
return -1;
drive->Type = RDPDR_DTYP_FILESYSTEM; 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); freerdp_device_collection_add(settings, (RDPDR_DEVICE*) drive);
settings->DeviceRedirection = TRUE; settings->DeviceRedirection = TRUE;
@ -316,8 +322,10 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1) if (count < 1)
return -1; return -1;
printer = (RDPDR_PRINTER*) malloc(sizeof(RDPDR_PRINTER)); printer = (RDPDR_PRINTER*) calloc(1, sizeof(RDPDR_PRINTER));
ZeroMemory(printer, sizeof(RDPDR_PRINTER));
if (!printer)
return -1;
printer->Type = RDPDR_DTYP_PRINT; printer->Type = RDPDR_DTYP_PRINT;
@ -339,12 +347,16 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count < 1) if (count < 1)
return -1; return -1;
smartcard = (RDPDR_SMARTCARD*) malloc(sizeof(RDPDR_SMARTCARD)); smartcard = (RDPDR_SMARTCARD*) calloc(1, sizeof(RDPDR_SMARTCARD));
ZeroMemory(smartcard, sizeof(RDPDR_SMARTCARD));
if (!smartcard)
return -1;
smartcard->Type = RDPDR_DTYP_SMARTCARD; smartcard->Type = RDPDR_DTYP_SMARTCARD;
if (count > 1) if (count > 1)
smartcard->Name = _strdup(params[1]); smartcard->Name = _strdup(params[1]);
if (count > 2) if (count > 2)
smartcard->Path = _strdup(params[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) if (count < 1)
return -1; return -1;
serial = (RDPDR_SERIAL*) malloc(sizeof(RDPDR_SERIAL)); serial = (RDPDR_SERIAL*) calloc(1, sizeof(RDPDR_SERIAL));
ZeroMemory(serial, sizeof(RDPDR_SERIAL));
if (!serial)
return -1;
serial->Type = RDPDR_DTYP_SERIAL; serial->Type = RDPDR_DTYP_SERIAL;
if (count > 1) if (count > 1)
serial->Name = _strdup(params[1]); serial->Name = _strdup(params[1]);
if (count > 2) if (count > 2)
serial->Path = _strdup(params[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) if (count < 1)
return -1; return -1;
parallel = (RDPDR_PARALLEL*) malloc(sizeof(RDPDR_PARALLEL)); parallel = (RDPDR_PARALLEL*) calloc(1, sizeof(RDPDR_PARALLEL));
ZeroMemory(parallel, sizeof(RDPDR_PARALLEL));
if (!parallel)
return -1;
parallel->Type = RDPDR_DTYP_PARALLEL; parallel->Type = RDPDR_DTYP_PARALLEL;
if (count > 1) if (count > 1)
parallel->Name = _strdup(params[1]); parallel->Name = _strdup(params[1]);
if (count > 1) if (count > 1)
parallel->Path = _strdup(params[2]); parallel->Path = _strdup(params[2]);

View File

@ -24,6 +24,7 @@
#ifndef __REGION_H___ #ifndef __REGION_H___
#define __REGION_H___ #define __REGION_H___
#include <freerdp/api.h>
#include <freerdp/types.h> #include <freerdp/types.h>
struct _REGION16_DATA; struct _REGION16_DATA;
@ -43,7 +44,7 @@ typedef struct _REGION16 REGION16;
* @param r2 second rectangle * @param r2 second rectangle
* @return if the two rectangles intersect * @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 /** computes the intersection of two rectangles
* @param r1 first rectangle * @param r1 first rectangle
@ -51,15 +52,15 @@ BOOL rectangles_intersects(const RECTANGLE_16 *r1, const RECTANGLE_16 *r2);
* @param dst resulting intersection * @param dst resulting intersection
* @return if the two rectangles intersect * @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 /** initialize a region16
* @param region the region to initialise * @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 */ /** @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. /** 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. * 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 * @param nbRects a pointer that will be filled with the number of rectangles
* @return a pointer on the 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 */ /** @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 /** returns if the region is empty
* @param region * @param region
* @return if the region is empty * @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 /** clears the region, the region is resetted to a (0,0,0,0) region
* @param region * @param region
*/ */
void region16_clear(REGION16 *region); FREERDP_API void region16_clear(REGION16 *region);
/** dumps the region on stderr /** dumps the region on stderr
* @param region the region to dump * @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 /** copies the region to another region
* @param dst destination region * @param dst destination region
* @param src source region * @param src source region
* @return if the operation was successful (false meaning out-of-memory) * @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 /** adds a rectangle in src and stores the resulting region in dst
* @param dst destination region * @param dst destination region
@ -101,14 +102,14 @@ BOOL region16_copy(REGION16 *dst, const REGION16 *src);
* @param rect the rectangle to add * @param rect the rectangle to add
* @return if the operation was successful (false meaning out-of-memory) * @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 /** returns if a rectangle intersects the region
* @param src the region * @param src the region
* @param arg2 the rectangle * @param arg2 the rectangle
* @return if region and rectangle intersect * @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 /** computes the intersection between a region and a rectangle
* @param dst destination region * @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 * @param arg2 the rectangle that intersects
* @return if the operation was successful (false meaning out-of-memory) * @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 /** release internal data associated with this region
* @param region the region to release * @param region the region to release
*/ */
void region16_uninit(REGION16 *region); FREERDP_API void region16_uninit(REGION16 *region);
#endif /* __REGION_H___ */ #endif /* __REGION_H___ */

View File

@ -84,7 +84,7 @@ struct rdp_tls
int alertDescription; 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_accept(rdpTls* tls, const char* cert_file, const char* privatekey_file);
FREERDP_API BOOL tls_disconnect(rdpTls* tls); 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 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_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_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); 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 #define CANCELEDBYUSER ERRORSTART + 11
/** /**
* FreeRDP Context Error Codes * 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_AUTHENTICATION_FAILED MAKE_FREERDP_ERROR(CONNECT, 9)
#define FREERDP_ERROR_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(CONNECT, 10) #define FREERDP_ERROR_INSUFFICIENT_PRIVILEGES MAKE_FREERDP_ERROR(CONNECT, 10)
#define FREERDP_ERROR_CONNECT_CANCELLED MAKE_FREERDP_ERROR(CONNECT, 11) #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 #ifdef __cplusplus
} }

View File

@ -87,11 +87,11 @@ struct _BITMAP_PLANAR_CONTEXT
BYTE* rlePlanesBuffer; 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]); FREERDP_API 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); FREERDP_API 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); FREERDP_API 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_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]);
#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */ #endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */

View File

@ -690,7 +690,7 @@ struct UnitaryTest tests[] = {
int TestFreeRDPRegion(int argc, char* argv[]) int TestFreeRDPRegion(int argc, char* argv[])
{ {
int i, testNb; int i, testNb = 0;
int retCode = -1; int retCode = -1;
for (i = 0; tests[i].func; i++) 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]; device = (RDPDR_DEVICE*) settings->DeviceArray[index];
if (NULL == device->Name) if (!device->Name)
continue; continue;
if (strcmp(device->Name, name) == 0) if (strcmp(device->Name, name) == 0)
@ -169,24 +169,27 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
if (device->Type == RDPDR_DTYP_FILESYSTEM) if (device->Type == RDPDR_DTYP_FILESYSTEM)
{ {
RDPDR_DRIVE* drive = (RDPDR_DRIVE*) device; 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) if (!_drive)
return NULL; return NULL;
_drive->Id = drive->Id; _drive->Id = drive->Id;
_drive->Type = drive->Type; _drive->Type = drive->Type;
_drive->Name = _strdup(drive->Name); _drive->Name = _strdup(drive->Name);
if (!_drive->Name) if (!_drive->Name)
goto out_fs_name_error; goto out_fs_name_error;
_drive->Path = _strdup(drive->Path); _drive->Path = _strdup(drive->Path);
if (!_drive->Path) if (!_drive->Path)
goto out_fs_path_error; goto out_fs_path_error;
return (RDPDR_DEVICE*) _drive; return (RDPDR_DEVICE*) _drive;
out_fs_path_error: out_fs_path_error:
free(_drive->Name); free(_drive->Name);
out_fs_name_error: out_fs_name_error:
free(_drive); free(_drive);
return NULL; return NULL;
} }
@ -194,24 +197,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
if (device->Type == RDPDR_DTYP_PRINT) if (device->Type == RDPDR_DTYP_PRINT)
{ {
RDPDR_PRINTER* printer = (RDPDR_PRINTER*) device; 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) if (!_printer)
return NULL; return NULL;
_printer->Id = printer->Id; _printer->Id = printer->Id;
_printer->Type = printer->Type; _printer->Type = printer->Type;
_printer->Name = _strdup(printer->Name);
if (!_printer->Name) if (printer->Name)
goto out_print_name_error; {
_printer->DriverName = _strdup(printer->DriverName); _printer->Name = _strdup(printer->Name);
if(!_printer->DriverName) if (!_printer->Name)
goto out_print_path_error; 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; return (RDPDR_DEVICE*) _printer;
out_print_path_error: out_print_path_error:
free(_printer->Name); free(_printer->Name);
out_print_name_error: out_print_name_error:
free(_printer); free(_printer);
return NULL; return NULL;
} }
@ -219,24 +231,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
if (device->Type == RDPDR_DTYP_SMARTCARD) if (device->Type == RDPDR_DTYP_SMARTCARD)
{ {
RDPDR_SMARTCARD* smartcard = (RDPDR_SMARTCARD*) device; 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) if (!_smartcard)
return NULL; return NULL;
_smartcard->Id = smartcard->Id; _smartcard->Id = smartcard->Id;
_smartcard->Type = smartcard->Type; _smartcard->Type = smartcard->Type;
_smartcard->Name = _strdup(smartcard->Name);
if (!_smartcard->Name) if (smartcard->Name)
goto out_smartc_name_error; {
_smartcard->Path = _strdup(smartcard->Path); _smartcard->Name = _strdup(smartcard->Name);
if (!_smartcard->Path) if (!_smartcard->Name)
goto out_smartc_path_error; 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; return (RDPDR_DEVICE*) _smartcard;
out_smartc_path_error: out_smartc_path_error:
free(_smartcard->Name); free(_smartcard->Name);
out_smartc_name_error: out_smartc_name_error:
free(_smartcard); free(_smartcard);
return NULL; return NULL;
} }
@ -244,24 +265,33 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
if (device->Type == RDPDR_DTYP_SERIAL) if (device->Type == RDPDR_DTYP_SERIAL)
{ {
RDPDR_SERIAL* serial = (RDPDR_SERIAL*) device; 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) if (!_serial)
return NULL; return NULL;
_serial->Id = serial->Id; _serial->Id = serial->Id;
_serial->Type = serial->Type; _serial->Type = serial->Type;
_serial->Name = _strdup(serial->Name);
if (!_serial->Name) if (serial->Name)
goto out_serial_name_error; {
_serial->Path = _strdup(serial->Path); _serial->Name = _strdup(serial->Name);
if (!_serial->Path) if (!_serial->Name)
goto out_serial_path_error; 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; return (RDPDR_DEVICE*) _serial;
out_serial_path_error: out_serial_path_error:
free(_serial->Name); free(_serial->Name);
out_serial_name_error: out_serial_name_error:
free(_serial); free(_serial);
return NULL; return NULL;
} }
@ -269,23 +299,32 @@ RDPDR_DEVICE* freerdp_device_clone(RDPDR_DEVICE* device)
if (device->Type == RDPDR_DTYP_PARALLEL) if (device->Type == RDPDR_DTYP_PARALLEL)
{ {
RDPDR_PARALLEL* parallel = (RDPDR_PARALLEL*) device; 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) if (!_parallel)
return NULL; return NULL;
_parallel->Id = parallel->Id; _parallel->Id = parallel->Id;
_parallel->Type = parallel->Type; _parallel->Type = parallel->Type;
_parallel->Name = _strdup(parallel->Name);
if (!_parallel->Name) if (parallel->Name)
goto out_parallel_name_error; {
_parallel->Path = _strdup(parallel->Path); _parallel->Name = _strdup(parallel->Name);
if (!_parallel->Path) if (!_parallel->Name)
goto out_parallel_path_error; 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; return (RDPDR_DEVICE*) _parallel;
out_parallel_path_error: out_parallel_path_error:
free(_parallel->Name); free(_parallel->Name);
out_parallel_name_error: out_parallel_name_error:
free(_parallel); free(_parallel);
return NULL; return NULL;

View File

@ -251,6 +251,11 @@ BOOL rdp_client_connect(rdpRdp* rdp)
if (!nego_connect(rdp->nego)) 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"); fprintf(stderr, "Error: protocol security negotiation or connection failure\n");
return FALSE; return FALSE;
} }
@ -286,7 +291,14 @@ BOOL rdp_client_connect(rdpRdp* rdp)
while (rdp->state != CONNECTION_STATE_ACTIVE) while (rdp->state != CONNECTION_STATE_ACTIVE)
{ {
if (rdp_check_fds(rdp) < 0) 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 FALSE;
}
} }
return TRUE; return TRUE;

View File

@ -192,11 +192,6 @@ BOOL freerdp_connect(freerdp* instance)
freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES); freerdp_set_last_error(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
} }
if (!connectErrorCode)
{
connectErrorCode = UNDEFINEDCONNECTERROR;
}
SetEvent(rdp->transport->connectedEvent); SetEvent(rdp->transport->connectedEvent);
freerdp_connect_finally: freerdp_connect_finally:

View File

@ -224,6 +224,7 @@ BIO_METHOD* BIO_s_tsg(void)
BOOL transport_connect_tls(rdpTransport* transport) BOOL transport_connect_tls(rdpTransport* transport)
{ {
int tls_status;
freerdp* instance; freerdp* instance;
rdpContext* context; rdpContext* context;
@ -245,13 +246,23 @@ BOOL transport_connect_tls(rdpTransport* transport)
if (transport->TsgTls->port == 0) if (transport->TsgTls->port == 0)
transport->TsgTls->port = 3389; transport->TsgTls->port = 3389;
if (!tls_connect(transport->TsgTls)) tls_status = tls_connect(transport->TsgTls);
{
if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR;
if (!freerdp_get_last_error(context)) if (tls_status < 1)
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); {
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); tls_free(transport->TsgTls);
transport->TsgTls = NULL; transport->TsgTls = NULL;
@ -277,13 +288,23 @@ BOOL transport_connect_tls(rdpTransport* transport)
if (transport->TlsIn->port == 0) if (transport->TlsIn->port == 0)
transport->TlsIn->port = 3389; transport->TlsIn->port = 3389;
if (!tls_connect(transport->TlsIn)) tls_status = tls_connect(transport->TlsIn);
{
if (!connectErrorCode)
connectErrorCode = TLSCONNECTERROR;
if (!freerdp_get_last_error(context)) if (tls_status < 1)
freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); {
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); tls_free(transport->TlsIn);
@ -317,6 +338,7 @@ BOOL transport_connect_nla(rdpTransport* transport)
if (!transport->credssp) if (!transport->credssp)
{ {
transport->credssp = credssp_new(instance, transport, settings); transport->credssp = credssp_new(instance, transport, settings);
transport_set_nla_mode(transport, TRUE);
if (settings->AuthenticationServiceClass) if (settings->AuthenticationServiceClass)
{ {
@ -338,11 +360,14 @@ BOOL transport_connect_nla(rdpTransport* transport)
fprintf(stderr, "Authentication failure, check credentials.\n" fprintf(stderr, "Authentication failure, check credentials.\n"
"If credentials are valid, the NTLMSSP implementation may be to blame.\n"); "If credentials are valid, the NTLMSSP implementation may be to blame.\n");
transport_set_nla_mode(transport, FALSE);
credssp_free(transport->credssp); credssp_free(transport->credssp);
transport->credssp = NULL; transport->credssp = NULL;
return FALSE; return FALSE;
} }
transport_set_nla_mode(transport, FALSE);
credssp_free(transport->credssp); credssp_free(transport->credssp);
transport->credssp = NULL; transport->credssp = NULL;
@ -351,7 +376,15 @@ BOOL transport_connect_nla(rdpTransport* transport)
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port) 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; tsg->transport = transport;
transport->tsg = tsg; transport->tsg = tsg;
@ -377,11 +410,41 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16
if (transport->TlsOut->port == 0) if (transport->TlsOut->port == 0)
transport->TlsOut->port = 443; transport->TlsOut->port = 443;
if (!tls_connect(transport->TlsIn)) tls_status = tls_connect(transport->TlsIn);
return FALSE;
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; 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)) if (!tsg_connect(tsg, hostname, port))
return FALSE; return FALSE;
@ -481,11 +544,16 @@ BOOL transport_accept_nla(rdpTransport* transport)
return TRUE; return TRUE;
if (!transport->credssp) if (!transport->credssp)
{
transport->credssp = credssp_new(instance, transport, settings); transport->credssp = credssp_new(instance, transport, settings);
transport_set_nla_mode(transport, TRUE);
}
if (credssp_authenticate(transport->credssp) < 0) if (credssp_authenticate(transport->credssp) < 0)
{ {
fprintf(stderr, "client authentication failure\n"); fprintf(stderr, "client authentication failure\n");
transport_set_nla_mode(transport, FALSE);
credssp_free(transport->credssp); credssp_free(transport->credssp);
transport->credssp = NULL; 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 */ /* don't free credssp module yet, we need to copy the credentials from it first */
transport_set_nla_mode(transport, FALSE);
return TRUE; return TRUE;
} }
@ -643,49 +712,56 @@ int transport_read(rdpTransport* transport, wStream* s)
CopyMemory(header, Stream_Buffer(s), 4); /* peek at first 4 bytes */ CopyMemory(header, Stream_Buffer(s), 4); /* peek at first 4 bytes */
/* if header is present, read in exactly one PDU */ /* if header is present, read exactly one PDU */
if (header[0] == 0x03)
{
/* TPKT header */
pduLength = (header[2] << 8) | header[3]; if (transport->NlaMode)
}
else if (header[0] == 0x30)
{ {
/* TSRequest (NLA) */ if (header[0] == 0x30)
if (header[1] & 0x80)
{ {
if ((header[1] & ~(0x80)) == 1) /* TSRequest (NLA) */
if (header[1] & 0x80)
{ {
pduLength = header[2]; if ((header[1] & ~(0x80)) == 1)
pduLength += 3; {
} pduLength = header[2];
else if ((header[1] & ~(0x80)) == 2) pduLength += 3;
{ }
pduLength = (header[2] << 8) | header[3]; else if ((header[1] & ~(0x80)) == 2)
pduLength += 4; {
pduLength = (header[2] << 8) | header[3];
pduLength += 4;
}
else
{
fprintf(stderr, "Error reading TSRequest!\n");
return -1;
}
} }
else else
{ {
fprintf(stderr, "Error reading TSRequest!\n"); pduLength = header[1];
return -1; pduLength += 2;
} }
} }
else
{
pduLength = header[1];
pduLength += 2;
}
} }
else else
{ {
/* Fast-Path Header */ if (header[0] == 0x03)
{
/* TPKT header */
if (header[1] & 0x80) pduLength = (header[2] << 8) | header[3];
pduLength = ((header[1] & 0x7F) << 8) | header[2]; }
else 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); 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 * Loop through and read all available PDUs. Since multiple
* PDUs can exist, it's important to deliver them all before * PDUs can exist, it's important to deliver them all before
* returning. Otherwise we run the risk of having a thread * 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). * (which may never happen).
*/ */
for (;;) for (;;)
{ {
status = transport_read_nonblocking(transport); status = transport_read_nonblocking(transport);
if (status < 0 || Stream_GetPosition(transport->ReceiveBuffer) == 0) if ((status <= 0) || (Stream_GetPosition(transport->ReceiveBuffer) < 2))
return status; return status;
while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0) while ((pos = Stream_GetPosition(transport->ReceiveBuffer)) > 0)
{ {
Stream_SetPosition(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 (nla_verify_header(transport->ReceiveBuffer))
if (pos <= 4)
{ {
Stream_SetPosition(transport->ReceiveBuffer, pos); /* TSRequest */
return 0;
}
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 */ if (tpkt_verify_header(transport->ReceiveBuffer)) /* TPKT */
/* Ensure the TSRequest header is available. */
if (pos <= 4)
{ {
Stream_SetPosition(transport->ReceiveBuffer, pos); /* Ensure the TPKT header is available. */
return 0; if (pos <= 4)
{
Stream_SetPosition(transport->ReceiveBuffer, pos);
return 0;
}
length = tpkt_read_header(transport->ReceiveBuffer);
} }
else /* Fast Path */
/* TSRequest header can be 2, 3 or 4 bytes long */
length = nla_header_length(transport->ReceiveBuffer);
if (pos < length)
{ {
Stream_SetPosition(transport->ReceiveBuffer, pos); /* Ensure the Fast Path header is available. */
return 0; 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) if (length == 0)
@ -1039,6 +1121,11 @@ void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled)
transport->GatewayEnabled = GatewayEnabled; transport->GatewayEnabled = GatewayEnabled;
} }
void transport_set_nla_mode(rdpTransport* transport, BOOL NlaMode)
{
transport->NlaMode = NlaMode;
}
static void* transport_client_thread(void* arg) static void* transport_client_thread(void* arg)
{ {
DWORD status; DWORD status;

View File

@ -75,6 +75,7 @@ struct rdp_transport
HANDLE stopEvent; HANDLE stopEvent;
HANDLE thread; HANDLE thread;
BOOL async; BOOL async;
BOOL NlaMode;
BOOL GatewayEnabled; BOOL GatewayEnabled;
CRITICAL_SECTION ReadLock; CRITICAL_SECTION ReadLock;
CRITICAL_SECTION WriteLock; CRITICAL_SECTION WriteLock;
@ -99,6 +100,7 @@ void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount);
int transport_check_fds(rdpTransport* transport); int transport_check_fds(rdpTransport* transport);
BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking); BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking);
void transport_set_gateway_enabled(rdpTransport* transport, BOOL GatewayEnabled); 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); void transport_get_read_handles(rdpTransport* transport, HANDLE* events, DWORD* count);
wStream* transport_receive_pool_take(rdpTransport* transport); 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; CryptoCert cert;
long options = 0; long options = 0;
int verify_status;
int connection_status; int connection_status;
tls->ctx = SSL_CTX_new(TLSv1_client_method()); tls->ctx = SSL_CTX_new(TLSv1_client_method());
@ -116,7 +117,7 @@ BOOL tls_connect(rdpTls* tls)
if (!tls->ctx) if (!tls->ctx)
{ {
fprintf(stderr, "SSL_CTX_new failed\n"); 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); //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) if (!tls->ssl)
{ {
fprintf(stderr, "SSL_new failed\n"); fprintf(stderr, "SSL_new failed\n");
return FALSE; return -1;
} }
if (tls->tsg) if (tls->tsg)
@ -167,7 +168,7 @@ BOOL tls_connect(rdpTls* tls)
if (!tls->bio) if (!tls->bio)
{ {
fprintf(stderr, "BIO_new failed\n"); fprintf(stderr, "BIO_new failed\n");
return FALSE; return -1;
} }
tls->bio->ptr = tls->tsg; tls->bio->ptr = tls->tsg;
@ -181,7 +182,7 @@ BOOL tls_connect(rdpTls* tls)
if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) if (SSL_set_fd(tls->ssl, tls->sockfd) < 1)
{ {
fprintf(stderr, "SSL_set_fd failed\n"); 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)) 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) if (!cert)
{ {
fprintf(stderr, "tls_connect: tls_get_certificate failed to return the server certificate.\n"); 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); 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"); fprintf(stderr, "tls_connect: crypto_cert_get_public_key failed to return the server public key.\n");
tls_free_certificate(cert); 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"); fprintf(stderr, "tls_connect: certificate not trusted, aborting.\n");
tls_disconnect(tls); tls_disconnect(tls);
tls_free_certificate(cert); tls_free_certificate(cert);
return FALSE; return verify_status;
} }
tls_free_certificate(cert); 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) 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; 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 match;
int index; int index;
@ -644,7 +647,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
if (!bio) if (!bio)
{ {
fprintf(stderr, "tls_verify_certificate: BIO_new() failure\n"); fprintf(stderr, "tls_verify_certificate: BIO_new() failure\n");
return FALSE; return -1;
} }
status = PEM_write_bio_X509(bio, cert->px509); 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) if (status < 0)
{ {
fprintf(stderr, "tls_verify_certificate: PEM_write_bio_X509 failure: %d\n", status); fprintf(stderr, "tls_verify_certificate: PEM_write_bio_X509 failure: %d\n", status);
return FALSE; return -1;
} }
offset = 0; offset = 0;
@ -664,7 +667,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
if (status < 0) if (status < 0)
{ {
fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); fprintf(stderr, "tls_verify_certificate: failed to read certificate\n");
return FALSE; return -1;
} }
offset += status; offset += status;
@ -685,7 +688,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
if (status < 0) if (status < 0)
{ {
fprintf(stderr, "tls_verify_certificate: failed to read certificate\n"); fprintf(stderr, "tls_verify_certificate: failed to read certificate\n");
return FALSE; return -1;
} }
length = offset; length = offset;
@ -704,12 +707,15 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
free(pemCert); free(pemCert);
BIO_free(bio); 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) */ /* ignore certificate verification if user explicitly required it (discouraged) */
if (tls->settings->IgnoreCertificate) if (tls->settings->IgnoreCertificate)
return TRUE; /* success! */ return 1; /* success! */
/* if user explicitly specified a certificate name, use it instead of the hostname */ /* if user explicitly specified a certificate name, use it instead of the hostname */
if (tls->settings->CertificateName) if (tls->settings->CertificateName)
@ -727,7 +733,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
/* compare against common name */ /* compare against common name */
if (common_name != NULL) if (common_name)
{ {
if (tls_match_hostname(common_name, common_name_length, hostname)) if (tls_match_hostname(common_name, common_name_length, hostname))
hostname_match = TRUE; hostname_match = TRUE;
@ -735,7 +741,7 @@ BOOL tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int po
/* compare against alternative names */ /* compare against alternative names */
if (alt_names != NULL) if (alt_names)
{ {
for (index = 0; index < alt_names_count; index++) 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, crypto_cert_subject_alt_name_free(alt_names_count, alt_names_lengths,
alt_names); alt_names);
return verification_status; return (verification_status == 0) ? 0 : 1;
} }
void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file) 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/gdi.h>
#include <freerdp/gdi/dc.h> #include <freerdp/gdi/dc.h>
#include <freerdp/gdi/drawing.h>
/** /**
* Set current foreground draw mode.\n * Set current foreground draw mode.\n