Merge branch 'master' of github.com:FreeRDP/FreeRDP into egfx

This commit is contained in:
Marc-André Moreau 2014-07-08 12:29:30 -04:00
commit c16000e67b
96 changed files with 10473 additions and 2066 deletions

3
.gitignore vendored
View File

@ -123,3 +123,6 @@ default.log
*.txt.user
*.autosave
# etags
TAGS

View File

@ -369,6 +369,7 @@ if(UNIX OR CYGWIN)
check_include_files(sys/eventfd.h HAVE_AIO_H)
check_include_files(sys/eventfd.h HAVE_EVENTFD_H)
check_include_files(sys/timerfd.h HAVE_TIMERFD_H)
check_include_files(poll.h HAVE_POLL_H)
set(X11_FEATURE_TYPE "RECOMMENDED")
else()
set(X11_FEATURE_TYPE "DISABLED")

View File

@ -18,9 +18,6 @@
define_channel_client("serial")
set(${MODULE_PREFIX}_SRCS
serial_tty.c
serial_tty.h
serial_constants.h
serial_main.c)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DeviceServiceEntry")
@ -32,6 +29,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-comm)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)

View File

@ -1,154 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Serial Port Device Service Virtual Channel
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SERIAL_CONSTANTS_H
#define __SERIAL_CONSTANTS_H
/* http://www.codeproject.com/KB/system/chaiyasit_t.aspx */
#define SERIAL_TIMEOUT_MAX 4294967295u
/* DR_CONTROL_REQ.IoControlCode */
enum DR_PORT_CONTROL_REQ
{
IOCTL_SERIAL_SET_BAUD_RATE = 0x001B0004,
IOCTL_SERIAL_GET_BAUD_RATE = 0x001B0050,
IOCTL_SERIAL_SET_LINE_CONTROL = 0x001B000C,
IOCTL_SERIAL_GET_LINE_CONTROL = 0x001B0054,
IOCTL_SERIAL_SET_TIMEOUTS = 0x001B001C,
IOCTL_SERIAL_GET_TIMEOUTS = 0x001B0020,
/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */
IOCTL_SERIAL_GET_CHARS = 0x001B0058,
IOCTL_SERIAL_SET_CHARS = 0x001B005C,
IOCTL_SERIAL_SET_DTR = 0x001B0024,
IOCTL_SERIAL_CLR_DTR = 0x001B0028,
IOCTL_SERIAL_RESET_DEVICE = 0x001B002C,
IOCTL_SERIAL_SET_RTS = 0x001B0030,
IOCTL_SERIAL_CLR_RTS = 0x001B0034,
IOCTL_SERIAL_SET_XOFF = 0x001B0038,
IOCTL_SERIAL_SET_XON = 0x001B003C,
IOCTL_SERIAL_SET_BREAK_ON = 0x001B0010,
IOCTL_SERIAL_SET_BREAK_OFF = 0x001B0014,
IOCTL_SERIAL_SET_QUEUE_SIZE = 0x001B0008,
IOCTL_SERIAL_GET_WAIT_MASK = 0x001B0040,
IOCTL_SERIAL_SET_WAIT_MASK = 0x001B0044,
IOCTL_SERIAL_WAIT_ON_MASK = 0x001B0048,
IOCTL_SERIAL_IMMEDIATE_CHAR = 0x001B0018,
IOCTL_SERIAL_PURGE = 0x001B004C,
IOCTL_SERIAL_GET_HANDFLOW = 0x001B0060,
IOCTL_SERIAL_SET_HANDFLOW = 0x001B0064,
IOCTL_SERIAL_GET_MODEMSTATUS = 0x001B0068,
IOCTL_SERIAL_GET_DTRRTS = 0x001B0078,
/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */
IOCTL_SERIAL_GET_COMMSTATUS = 0x001B006C,
IOCTL_SERIAL_GET_PROPERTIES = 0x001B0074,
IOCTL_SERIAL_XOFF_COUNTER = 0x001B0070,
IOCTL_SERIAL_LSRMST_INSERT = 0x001B007C,
IOCTL_SERIAL_CONFIG_SIZE = 0x001B0080,
IOCTL_SERIAL_GET_STATS = 0x001B008C,
IOCTL_SERIAL_CLEAR_STATS = 0x001B0090,
IOCTL_SERIAL_GET_MODEM_CONTROL = 0x001B0094,
IOCTL_SERIAL_SET_MODEM_CONTROL = 0x001B0098,
IOCTL_SERIAL_SET_FIFO_CONTROL = 0x001B009C,
};
enum SERIAL_PURGE_MASK
{
SERIAL_PURGE_TXABORT = 0x00000001,
SERIAL_PURGE_RXABORT = 0x00000002,
SERIAL_PURGE_TXCLEAR = 0x00000004,
SERIAL_PURGE_RXCLEAR = 0x00000008,
};
enum SERIAL_WAIT_MASK
{
SERIAL_EV_RXCHAR = 0x0001, /* Any Character received */
SERIAL_EV_RXFLAG = 0x0002, /* Received certain character */
SERIAL_EV_TXEMPTY = 0x0004, /* Transmitt Queue Empty */
SERIAL_EV_CTS = 0x0008, /* CTS changed state */
SERIAL_EV_DSR = 0x0010, /* DSR changed state */
SERIAL_EV_RLSD = 0x0020, /* RLSD changed state */
SERIAL_EV_BREAK = 0x0040, /* BREAK received */
SERIAL_EV_ERR = 0x0080, /* Line status error occurred */
SERIAL_EV_RING = 0x0100, /* Ring signal detected */
SERIAL_EV_PERR = 0x0200, /* Printer error occured */
SERIAL_EV_RX80FULL = 0x0400,/* Receive buffer is 80 percent full */
SERIAL_EV_EVENT1 = 0x0800, /* Provider specific event 1 */
SERIAL_EV_EVENT2 = 0x1000, /* Provider specific event 2 */
};
enum SERIAL_MODEM_STATUS
{
SERIAL_MS_DTR = 0x01,
SERIAL_MS_RTS = 0x02,
SERIAL_MS_CTS = 0x10,
SERIAL_MS_DSR = 0x20,
SERIAL_MS_RNG = 0x40,
SERIAL_MS_CAR = 0x80,
};
enum SERIAL_HANDFLOW
{
SERIAL_DTR_CONTROL = 0x01,
SERIAL_CTS_HANDSHAKE = 0x08,
SERIAL_ERROR_ABORT = 0x80000000,
};
enum SERIAL_FLOW_CONTROL
{
SERIAL_XON_HANDSHAKE = 0x01,
SERIAL_XOFF_HANDSHAKE = 0x02,
SERIAL_DSR_SENSITIVITY = 0x40,
};
enum SERIAL_CHARS
{
SERIAL_CHAR_EOF = 0,
SERIAL_CHAR_ERROR = 1,
SERIAL_CHAR_BREAK = 2,
SERIAL_CHAR_EVENT = 3,
SERIAL_CHAR_XON = 4,
SERIAL_CHAR_XOFF = 5,
};
enum SERIAL_ABORT_IO
{
SERIAL_ABORT_IO_NONE = 0,
SERIAL_ABORT_IO_WRITE = 1,
SERIAL_ABORT_IO_READ = 2,
};
enum SERIAL_STOP_BITS
{
SERIAL_STOP_BITS_1 = 0,
SERIAL_STOP_BITS_2 = 2,
};
enum SERIAL_PARITY
{
SERIAL_NO_PARITY = 0,
SERIAL_ODD_PARITY = 1,
SERIAL_EVEN_PARITY = 2,
};
#endif

View File

@ -4,6 +4,7 @@
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -23,115 +24,209 @@
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_SYS_MODEM_H
#include <sys/modem.h>
#endif
#ifdef HAVE_SYS_FILIO_H
#include <sys/filio.h>
#endif
#ifdef HAVE_SYS_STRTIO_H
#include <sys/strtio.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "serial_tty.h"
#include "serial_constants.h"
#include <winpr/collections.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/stream.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include <winpr/wlog.h>
#include <freerdp/freerdp.h>
#include <freerdp/channels/rdpdr.h>
/* TODO: all #ifdef __linux__ could be removed once only some generic
* functions will be used. Replace CommReadFile by ReadFile,
* CommWriteFile by WriteFile etc.. */
#if defined __linux__ && !defined ANDROID
#define MAX_IRP_THREADS 5
typedef struct _SERIAL_DEVICE SERIAL_DEVICE;
struct _SERIAL_DEVICE
{
DEVICE device;
char* path;
SERIAL_TTY* tty;
SERIAL_DRIVER_ID ServerSerialDriverId;
HANDLE* hComm;
wLog* log;
HANDLE thread;
wMessageQueue* IrpQueue;
HANDLE MainThread;
wMessageQueue* MainIrpQueue;
/* one thread per pending IRP and indexed according their CompletionId */
wListDictionary *IrpThreads;
UINT32 IrpThreadToBeTerminatedCount;
CRITICAL_SECTION TerminatingIrpThreadsLock;
};
typedef struct _IRP_THREAD_DATA IRP_THREAD_DATA;
struct _IRP_THREAD_DATA
{
SERIAL_DEVICE *serial;
IRP *irp;
};
static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
{
/* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests */
switch(GetLastError())
{
case ERROR_BAD_DEVICE:
return STATUS_INVALID_DEVICE_REQUEST;
case ERROR_CALL_NOT_IMPLEMENTED:
return STATUS_NOT_IMPLEMENTED;
case ERROR_CANCELLED:
return STATUS_CANCELLED;
case ERROR_INSUFFICIENT_BUFFER:
return STATUS_BUFFER_TOO_SMALL; /* NB: STATUS_BUFFER_SIZE_TOO_SMALL not defined */
case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */
return STATUS_INVALID_DEVICE_STATE;
case ERROR_INVALID_HANDLE:
return STATUS_INVALID_DEVICE_REQUEST;
case ERROR_INVALID_PARAMETER:
return STATUS_INVALID_PARAMETER;
case ERROR_IO_DEVICE:
return STATUS_IO_DEVICE_ERROR;
case ERROR_IO_PENDING:
return STATUS_PENDING;
case ERROR_NOT_SUPPORTED:
return STATUS_NOT_SUPPORTED;
case ERROR_TIMEOUT:
return STATUS_TIMEOUT;
/* no default */
}
WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%lx", GetLastError());
return STATUS_UNSUCCESSFUL;
}
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{
int status;
UINT32 FileId;
DWORD DesiredAccess;
DWORD SharedAccess;
DWORD CreateDisposition;
UINT32 PathLength;
char* path = NULL;
SERIAL_TTY* tty;
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, DesiredAccess); /* DesiredAccess (4 bytes) */
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */
Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
Stream_Seek(irp->input, PathLength); /* Path (variable) */
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) Stream_Pointer(irp->input),
PathLength / 2, &path, 0, NULL, NULL);
if (status < 1)
path = (char*) calloc(1, 1);
#ifndef _WIN32
/* Windows 2012 server sends on a first call :
* DesiredAccess = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES
* SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ
* CreateDisposition = 0x00000001: CREATE_NEW
*
* then Windows 2012 sends :
* DesiredAccess = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA
* SharedAccess = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ
* CreateDisposition = 0x00000001: CREATE_NEW
*
* assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE));
* assert(SharedAccess == 0);
* assert(CreateDisposition == OPEN_EXISTING);
*
*/
FileId = irp->devman->id_sequence++;
WLog_Print(serial->log, WLOG_DEBUG, "DesiredAccess: 0x%lX, SharedAccess: 0x%lX, CreateDisposition: 0x%lX", DesiredAccess, SharedAccess, CreateDisposition);
tty = serial_tty_new(serial->path, FileId);
/* FIXME: As of today only the flags below are supported by CommCreateFileA: */
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
SharedAccess = 0;
CreateDisposition = OPEN_EXISTING;
#endif
if (!tty)
serial->hComm = CreateFile(serial->device.name,
DesiredAccess,
SharedAccess,
NULL, /* SecurityAttributes */
CreateDisposition,
0, /* FlagsAndAttributes */
NULL); /* TemplateFile */
if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE))
{
WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: Ox%lX\n", serial->device.name, GetLastError());
irp->IoStatus = STATUS_UNSUCCESSFUL;
FileId = 0;
}
else
{
serial->tty = tty;
goto error_handle;
}
Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
_comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId);
free(path);
/* FIXME: Appeared to be useful to setup some devices. Guess
* the device driver asked to setup some unsupported feature
* that were not eventually used. TODO: collecting more
* details, a command line argument? */
/* _comm_set_permissive(serial->hComm, TRUE); */
irp->Complete(irp);
/* NOTE: binary mode/raw mode required for the redirection. On
* Linux, CommCreateFileA forces this setting.
*/
/* ZeroMemory(&dcb, sizeof(DCB)); */
/* dcb.DCBlength = sizeof(DCB); */
/* GetCommState(serial->hComm, &dcb); */
/* dcb.fBinary = TRUE; */
/* SetCommState(serial->hComm, &dcb); */
assert(irp->FileId == 0);
irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
irp->IoStatus = STATUS_SUCCESS;
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) created.", serial->device.name, irp->device->id, irp->FileId);
error_handle:
Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
}
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{
SERIAL_TTY* tty = serial->tty;
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
if (!tty)
if (!CloseHandle(serial->hComm))
{
WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%d) closed.", serial->device.name, irp->device->id);
irp->IoStatus = STATUS_UNSUCCESSFUL;
}
else
{
serial_tty_free(tty);
serial->tty = NULL;
goto error_handle;
}
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %d, FileId: %d) closed.", serial->device.name, irp->device->id, irp->FileId);
serial->hComm = NULL;
irp->IoStatus = STATUS_SUCCESS;
error_handle:
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
irp->Complete(irp);
}
static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
@ -139,119 +234,175 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
UINT32 Length;
UINT64 Offset;
BYTE* buffer = NULL;
SERIAL_TTY* tty = serial->tty;
DWORD nbRead = 0;
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) */
if (!tty)
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
if (buffer == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
irp->IoStatus = STATUS_NO_MEMORY;
goto error_handle;
}
/* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored
* assert(Offset == 0);
*/
WLog_Print(serial->log, WLOG_DEBUG, "reading %d bytes from %s", Length, serial->device.name);
/* FIXME: CommReadFile to be replaced by ReadFile */
if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL))
{
irp->IoStatus = STATUS_SUCCESS;
}
else
{
buffer = (BYTE*) malloc(Length);
WLog_Print(serial->log, WLOG_DEBUG, "read failure to %s, nbRead=%ld, last-error: 0x%lX", serial->device.name, nbRead, GetLastError());
if (!serial_tty_read(tty, buffer, &Length))
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
free(buffer);
buffer = NULL;
Length = 0;
}
else
{
}
irp->IoStatus = _GetLastErrorToIoStatus(serial);
}
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes read from %s", nbRead, serial->device.name);
if (Length > 0)
error_handle:
Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */
if (nbRead > 0)
{
Stream_EnsureRemainingCapacity(irp->output, Length);
Stream_Write(irp->output, buffer, Length);
Stream_EnsureRemainingCapacity(irp->output, nbRead);
Stream_Write(irp->output, buffer, nbRead); /* ReadData */
}
free(buffer);
irp->Complete(irp);
if (buffer)
free(buffer);
}
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
int status;
UINT32 Length;
UINT64 Offset;
SERIAL_TTY* tty = serial->tty;
DWORD nbWritten = 0;
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) */
if (!tty)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
/* MS-RDPESP 3.2.5.1.5: The Offset field is ignored
* assert(Offset == 0);
*
* Using a serial printer, noticed though this field could be
* set.
*/
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
irp->Complete(irp);
return;
WLog_Print(serial->log, WLOG_DEBUG, "writing %d bytes to %s", Length, serial->device.name);
/* FIXME: CommWriteFile to be replaced by WriteFile */
if (CommWriteFile(serial->hComm, Stream_Pointer(irp->input), Length, &nbWritten, NULL))
{
irp->IoStatus = STATUS_SUCCESS;
}
else
{
WLog_Print(serial->log, WLOG_DEBUG, "write failure to %s, nbWritten=%ld, last-error: 0x%lX", serial->device.name, nbWritten, GetLastError());
irp->IoStatus = _GetLastErrorToIoStatus(serial);
}
status = serial_tty_write(tty, Stream_Pointer(irp->input), Length);
WLog_Print(serial->log, WLOG_DEBUG, "%lu bytes written to %s", nbWritten, serial->device.name);
if (status < 0)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
Length = 0;
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); /* Length (4 bytes) */
Stream_Write_UINT32(irp->output, nbWritten); /* 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)
{
UINT32 IoControlCode;
UINT32 InputBufferLength;
BYTE* InputBuffer = NULL;
UINT32 OutputBufferLength;
UINT32 abortIo = SERIAL_ABORT_IO_NONE;
SERIAL_TTY* tty = serial->tty;
BYTE* OutputBuffer = NULL;
DWORD BytesReturned = 0;
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)
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
if (OutputBuffer == NULL)
{
irp->IoStatus = STATUS_UNSUCCESSFUL;
OutputBufferLength = 0;
irp->IoStatus = STATUS_NO_MEMORY;
goto error_handle;
}
InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE));
if (InputBuffer == NULL)
{
irp->IoStatus = STATUS_NO_MEMORY;
goto error_handle;
}
Stream_Read(irp->input, InputBuffer, InputBufferLength);
WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode));
/* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */
if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned, NULL))
{
/* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%d, IoControlCode=[0x%X] %s done", irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode)); */
irp->IoStatus = STATUS_SUCCESS;
}
else
{
irp->IoStatus = serial_tty_control(tty, IoControlCode, irp->input, irp->output, &abortIo);
WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl failure: IoControlCode=[0x%X] %s, last-error: 0x%lX",
IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError());
irp->IoStatus = _GetLastErrorToIoStatus(serial);
}
irp->Complete(irp);
error_handle:
/* FIXME: find out whether it's required or not to get
* BytesReturned == OutputBufferLength when
* CommDeviceIoControl returns FALSE */
assert(OutputBufferLength == BytesReturned);
Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */
if (BytesReturned > 0)
{
Stream_EnsureRemainingCapacity(irp->output, BytesReturned);
Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
}
/* FIXME: Why at least Windows 2008R2 gets lost with this
* extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The
* extra byte is well required according MS-RDPEFS
* 2.2.1.5.5 */
/* else */
/* { */
/* Stream_Write_UINT8(irp->output, 0); /\* Padding (1 byte) *\/ */
/* } */
if (InputBuffer != NULL)
free(InputBuffer);
if (OutputBuffer != NULL)
free(OutputBuffer);
}
static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
{
WLog_Print(serial->log, WLOG_DEBUG, "IRP MajorFunction: 0x%04X MinorFunction: 0x%04X\n",
irp->MajorFunction, irp->MinorFunction);
irp->MajorFunction, irp->MinorFunction);
switch (irp->MajorFunction)
{
@ -277,92 +428,362 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
default:
irp->IoStatus = STATUS_NOT_SUPPORTED;
irp->Complete(irp);
break;
}
}
static void* irp_thread_func(void* arg)
{
IRP_THREAD_DATA *data = (IRP_THREAD_DATA*)arg;
/* blocks until the end of the request */
serial_process_irp(data->serial, data->irp);
EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
data->serial->IrpThreadToBeTerminatedCount++;
data->irp->Complete(data->irp);
LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock);
/* NB: At this point, the server might already being reusing
* the CompletionId whereas the thread is not yet
* terminated */
free(data);
ExitThread(0);
return NULL;
}
static void create_irp_thread(SERIAL_DEVICE *serial, IRP *irp)
{
IRP_THREAD_DATA *data = NULL;
HANDLE irpThread = INVALID_HANDLE_VALUE;
HANDLE previousIrpThread;
uintptr_t key;
/* for a test/debug purpose, uncomment the code below to get a
* single thread for all IRPs. NB: two IRPs could not be
* processed at the same time, typically two concurent
* Read/Write operations could block each other. */
/* serial_process_irp(serial, irp); */
/* irp->Complete(irp); */
/* return; */
/* NOTE: for good or bad, this implementation relies on the
* server to avoid a flooding of requests. see also _purge().
*/
EnterCriticalSection(&serial->TerminatingIrpThreadsLock);
while (serial->IrpThreadToBeTerminatedCount > 0)
{
/* Cleaning up termitating and pending irp
* threads. See also: irp_thread_func() */
HANDLE irpThread;
ULONG_PTR *ids;
int i, nbIds;
nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
for (i=0; i<nbIds; i++)
{
/* Checking if ids[i] is terminating or pending */
DWORD waitResult;
ULONG_PTR id = ids[i];
irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is stil alived or not */
waitResult = WaitForSingleObject(irpThread, 0);
if (waitResult == WAIT_OBJECT_0)
{
/* terminating thread */
/* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%d naturally died", id); */
CloseHandle(irpThread);
ListDictionary_Remove(serial->IrpThreads, (void*)id);
serial->IrpThreadToBeTerminatedCount--;
}
else if (waitResult != WAIT_TIMEOUT)
{
/* unexpected thread state */
WLog_Print(serial->log, WLOG_WARN, "WaitForSingleObject, got an unexpected result=0x%lX\n", waitResult);
assert(FALSE);
}
/* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */
}
if (serial->IrpThreadToBeTerminatedCount > 0)
{
WLog_Print(serial->log, WLOG_DEBUG, "%d IRP thread(s) not yet terminated", serial->IrpThreadToBeTerminatedCount);
Sleep(1); /* 1 ms */
}
}
LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
/* NB: At this point and thanks to the synchronization we're
* sure that the incoming IRP uses well a recycled
* CompletionId or the server sent again an IRP already posted
* which didn't get yet a response (this later server behavior
* at least observed with IOCTL_SERIAL_WAIT_ON_MASK and
* mstsc.exe).
*
* FIXME: behavior documented somewhere? behavior not yet
* observed with FreeRDP).
*/
key = irp->CompletionId;
previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key);
if (previousIrpThread)
{
/* Thread still alived <=> Request still pending */
WLog_Print(serial->log, WLOG_DEBUG, "IRP recall: IRP with the CompletionId=%d not yet completed!", irp->CompletionId);
assert(FALSE); /* unimplemented */
/* TODO: asserts that previousIrpThread handles well
* the same request by checking more details. Need an
* access to the IRP object used by previousIrpThread
*/
/* TODO: taking over the pending IRP or sending a kind
* of wake up signal to accelerate the pending
* request
*
* To be considered:
* if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) {
* pComm->PendingEvents |= SERIAL_EV_FREERDP_*;
* }
*/
irp->Discard(irp);
return;
}
if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS)
{
WLog_Print(serial->log, WLOG_WARN, "Number of IRP threads threshold reached: %d, keep on anyway", ListDictionary_Count(serial->IrpThreads));
assert(FALSE); /* unimplemented */
/* TODO: MAX_IRP_THREADS has been thought to avoid a
* flooding of pending requests. Use
* WaitForMultipleObjects() when available in winpr
* for threads.
*/
}
/* error_handle to be used ... */
data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA));
if (data == NULL)
{
WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA.");
goto error_handle;
}
data->serial = serial;
data->irp = irp;
/* data freed by irp_thread_func */
irpThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)irp_thread_func,
(void*)data,
0,
NULL);
if (irpThread == INVALID_HANDLE_VALUE)
{
WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread.");
goto error_handle;
}
key = irp->CompletionId;
ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread);
return;
error_handle:
irp->IoStatus = STATUS_NO_MEMORY;
irp->Complete(irp);
if (data)
free(data);
}
static void terminate_pending_irp_threads(SERIAL_DEVICE *serial)
{
ULONG_PTR *ids;
int i, nbIds;
nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
WLog_Print(serial->log, WLOG_DEBUG, "Terminating %d IRP thread(s)", nbIds);
for (i=0; i<nbIds; i++)
{
HANDLE irpThread;
ULONG_PTR id = ids[i];
irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
TerminateThread(irpThread, 0);
WaitForSingleObject(irpThread, INFINITE);
CloseHandle(irpThread);
WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %d", id);
}
ListDictionary_Clear(serial->IrpThreads);
}
static void* serial_thread_func(void* arg)
{
IRP* irp;
wMessage message;
SERIAL_DEVICE* drive = (SERIAL_DEVICE*) arg;
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) arg;
while (1)
{
if (!MessageQueue_Wait(drive->IrpQueue))
if (!MessageQueue_Wait(serial->MainIrpQueue))
break;
if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE))
break;
if (message.id == WMQ_QUIT)
{
terminate_pending_irp_threads(serial);
break;
}
irp = (IRP*) message.wParam;
if (irp)
serial_process_irp(drive, irp);
create_irp_thread(serial, irp);
}
ExitThread(0);
return NULL;
}
static void serial_irp_request(DEVICE* device, IRP* irp)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
MessageQueue_Post(serial->IrpQueue, NULL, 0, (void*) irp, NULL);
assert(irp != NULL);
if (irp == NULL)
return;
/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
* allows the server to send multiple simultaneous read or
* write requests.
*/
MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*) irp, NULL);
}
static void serial_free(DEVICE* device)
{
SERIAL_DEVICE* serial = (SERIAL_DEVICE*) device;
WLog_Print(serial->log, WLOG_DEBUG, "freeing");
MessageQueue_PostQuit(serial->IrpQueue, 0);
WaitForSingleObject(serial->thread, INFINITE);
CloseHandle(serial->thread);
MessageQueue_PostQuit(serial->MainIrpQueue, 0);
WaitForSingleObject(serial->MainThread, INFINITE);
CloseHandle(serial->MainThread);
serial_tty_free(serial->tty);
if (serial->hComm)
CloseHandle(serial->hComm);
/* Clean up resources */
Stream_Free(serial->device.data, TRUE);
MessageQueue_Free(serial->IrpQueue);
MessageQueue_Free(serial->MainIrpQueue);
ListDictionary_Free(serial->IrpThreads);
DeleteCriticalSection(&serial->TerminatingIrpThreadsLock);
free(serial);
}
#endif /* __linux__ */
#ifdef STATIC_CHANNELS
#define DeviceServiceEntry serial_DeviceServiceEntry
#endif
int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
int i, len;
char* name;
char* path;
char* driver;
RDPDR_SERIAL* device;
#if defined __linux__ && !defined ANDROID
int i, len;
SERIAL_DEVICE* serial;
#endif /* __linux__ */
device = (RDPDR_SERIAL*) pEntryPoints->device;
name = device->Name;
path = device->Path;
driver = device->Driver;
if (!name || (name[0] == '*'))
{
/* TODO: implement auto detection of parallel ports */
/* TODO: implement auto detection of serial ports */
return 0;
}
if ((name && name[0]) && (path && path[0]))
{
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
wLog* log;
WLog_Init();
log = WLog_Get("com.freerdp.channel.serial.client");
WLog_Print(log, WLOG_DEBUG, "initializing");
#ifndef __linux__ /* to be removed */
WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
return -1;
#else /* __linux __ */
WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path);
if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
{
return -1;
}
serial = (SERIAL_DEVICE*) calloc(1, sizeof(SERIAL_DEVICE));
if (!serial)
return -1;
serial->log = log;
serial->device.type = RDPDR_DTYP_SERIAL;
serial->device.name = name;
serial->device.IRPRequest = serial_irp_request;
@ -374,17 +795,47 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
for (i = 0; i <= len; i++)
Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);
serial->path = path;
serial->IrpQueue = MessageQueue_New(NULL);
if (driver != NULL)
{
if (_stricmp(driver, "Serial") == 0)
serial->ServerSerialDriverId = SerialDriverSerialSys;
else if (_stricmp(driver, "SerCx") == 0)
serial->ServerSerialDriverId = SerialDriverSerCxSys;
else if (_stricmp(driver, "SerCx2") == 0)
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
else
{
assert(FALSE);
WLog_Init();
serial->log = WLog_Get("com.freerdp.channel.serial.client");
WLog_Print(serial->log, WLOG_DEBUG, "initializing");
WLog_Print(serial->log, WLOG_DEBUG, "Unknown server's serial driver: %s. SerCx2 will be used", driver);
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
}
}
else
{
/* default driver */
serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
}
WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, serial->ServerSerialDriverId);
/* TODO: implement auto detection of the server's serial driver */
serial->MainIrpQueue = MessageQueue_New(NULL);
/* IrpThreads content only modified by create_irp_thread() */
serial->IrpThreads = ListDictionary_New(FALSE);
serial->IrpThreadToBeTerminatedCount = 0;
InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) serial);
serial->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) serial_thread_func, (void*) serial, 0, NULL);
serial->MainThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE) serial_thread_func,
(void*) serial,
0,
NULL);
#endif /* __linux __ */
}
return 0;

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Serial Port Device Service Virtual Channel
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SERIAL_TTY_H
#define __SERIAL_TTY_H
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <dirent.h>
#endif
#include <freerdp/types.h>
#include <winpr/stream.h>
typedef struct _SERIAL_TTY SERIAL_TTY;
struct _SERIAL_TTY
{
UINT32 id;
int fd;
int dtr;
int rts;
UINT32 control;
UINT32 xonoff;
UINT32 onlimit;
UINT32 offlimit;
UINT32 baud_rate;
UINT32 queue_in_size;
UINT32 queue_out_size;
UINT32 wait_mask;
UINT32 read_interval_timeout;
UINT32 read_total_timeout_multiplier;
UINT32 read_total_timeout_constant;
UINT32 write_total_timeout_multiplier;
UINT32 write_total_timeout_constant;
BYTE stop_bits;
BYTE parity;
BYTE word_length;
BYTE chars[6];
struct termios* ptermios;
struct termios* pold_termios;
int event_txempty;
int event_cts;
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);
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);
#endif /* __SERIAL_TTY_H */

View File

@ -11,8 +11,10 @@ package com.freerdp.freerdpcore.presentation;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.IllegalFormatException;
import java.util.Locale;
import com.freerdp.freerdpcore.services.LibFreeRDP;
@ -21,10 +23,12 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
public class AboutActivity extends Activity {
private static final String TAG = "FreeRDPCore.AboutActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -47,6 +51,18 @@ public class AboutActivity extends Activity {
try
{
String filename = ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) ? "about.html" : "about_phone.html";
Locale def = Locale.getDefault();
String prefix = def.getLanguage().toLowerCase(def);
String file = prefix + "_about_page/" + filename;
InputStream is;
try {
is = getAssets().open(file);
is.close();
} catch (IOException e) {
Log.e(TAG, "Missing localized asset " + file, e);
file = "about_page/" + filename;
}
BufferedReader r = new BufferedReader(new InputStreamReader(getAssets().open("about_page/" + filename)));
String line;
while ((line = r.readLine()) != null) {
@ -70,6 +86,22 @@ public class AboutActivity extends Activity {
about_html="Nothing here ;(";
}
webview.getSettings().setJavaScriptEnabled(true);
webview.loadDataWithBaseURL("file:///android_asset/about_page/", about_html, "text/html", null, "about:blank");
Locale def = Locale.getDefault();
String prefix = def.getLanguage().toLowerCase(def);
String base = "file:///android_asset/";
String dir = prefix + "_about_page/";
String file = dir + about_html;
try {
InputStream is = getAssets().open(dir);
is.close();
dir = base + dir;
} catch (IOException e) {
Log.e(TAG, "Missing localized asset " + dir, e);
dir = "file:///android_asset/about_page/";
}
webview.loadDataWithBaseURL(dir, about_html, "text/html", null,
"about:blank");
}
}

View File

@ -12,10 +12,15 @@ package com.freerdp.freerdpcore.presentation;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
public class HelpActivity extends Activity {
private static final String TAG = "FreeRDPCore.HelpActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -23,7 +28,28 @@ public class HelpActivity extends Activity {
WebView webview = new WebView(this);
setContentView(webview);
String filename = ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) ? "gestures.html" : "gestures_phone.html";
webview.loadUrl("file:///android_asset/help_page/" + filename);
String filename;
if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE)
filename = "gestures.html";
else
filename = "gestures_phone.html";
webview.getSettings().setJavaScriptEnabled(true);
Locale def = Locale.getDefault();
String prefix = def.getLanguage().toLowerCase(def);
String base = "file:///android_asset/";
String dir = prefix + "_help_page/"
+ filename;
try {
InputStream is = getAssets().open(dir);
is.close();
dir = base + dir;
} catch (IOException e) {
Log.e(TAG, "Missing localized asset " + dir, e);
dir = "file:///android_asset/help_page/" + filename;
}
webview.loadUrl(dir);
}
}

View File

@ -3,13 +3,16 @@
Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.freerdp.freerdpcore.presentation;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
import com.freerdp.freerdpcore.R;
import com.freerdp.freerdpcore.application.GlobalApp;
@ -48,225 +51,198 @@ import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListView;
public class HomeActivity extends Activity
{
public class HomeActivity extends Activity {
private final static String ADD_BOOKMARK_PLACEHOLDER = "add_bookmark";
private ListView listViewBookmarks;
private WebView webViewGetStarted;
private Button clearTextButton;
private EditText superBarEditText;
private BookmarkArrayAdapter manualBookmarkAdapter;
private SeparatedListAdapter separatedListAdapter;
private PlaceholderBookmark addBookmarkPlaceholder;
private PlaceholderBookmark addBookmarkPlaceholder;
private static final String TAG = "HomeActivity";
private static final String PARAM_SUPERBAR_TEXT = "superbar_text";
private String sectionLabelBookmarks;
@Override
public void onCreate(Bundle savedInstanceState)
{
setTitle(R.string.title_home);
public void onCreate(Bundle savedInstanceState) {
setTitle(R.string.title_home);
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
long heapSize = Runtime.getRuntime().maxMemory();
Log.i(TAG, "Max HeapSize: " + heapSize);
Log.i(TAG, "App data folder: " + getFilesDir().toString());
Log.i(TAG, "App data folder: " + getFilesDir().toString());
// load strings
sectionLabelBookmarks = getResources().getString(R.string.section_bookmarks);
sectionLabelBookmarks = getResources().getString(R.string.section_bookmarks);
// create add bookmark/quick connect bookmark placeholder
addBookmarkPlaceholder = new PlaceholderBookmark();
addBookmarkPlaceholder.setName(ADD_BOOKMARK_PLACEHOLDER);
addBookmarkPlaceholder.setLabel(getResources().getString(R.string.list_placeholder_add_bookmark));
// check for passed .rdp file and open it in a new bookmark
Intent caller = getIntent();
Uri callParameter = caller.getData();
if (Intent.ACTION_VIEW.equals(caller.getAction()) && callParameter != null)
{
if (Intent.ACTION_VIEW.equals(caller.getAction()) && callParameter != null) {
String refStr = ConnectionReference.getFileReference(callParameter.getPath());
Bundle bundle = new Bundle();
bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr);
Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class);
bookmarkIntent.putExtras(bundle);
bookmarkIntent.putExtras(bundle);
startActivity(bookmarkIntent);
}
// load views
clearTextButton = (Button) findViewById(R.id.clear_search_btn);
superBarEditText = (EditText) findViewById(R.id.superBarEditText);
listViewBookmarks = (ListView) findViewById(R.id.listViewBookmarks);
webViewGetStarted = (WebView) findViewById(R.id.webViewWelcome);
superBarEditText = (EditText) findViewById(R.id.superBarEditText);
listViewBookmarks = (ListView) findViewById(R.id.listViewBookmarks);
String filename = ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE) ? "welcome.html" : "welcome_phone.html";
webViewGetStarted.loadUrl("file:///android_asset/welcome_page/" + filename);
// set listeners for the list view
Locale def = Locale.getDefault();
String prefix = def.getLanguage().toLowerCase(def);
String base = "file:///android_asset/";
String dir = prefix + "_help_page/"
+ filename;
try {
InputStream is = getAssets().open(dir);
is.close();
dir = base + dir;
} catch (IOException e) {
Log.e(TAG, "Missing localized asset " + dir, e);
dir = "file:///android_asset/help_page/" + filename;
}
// set listeners for the list view
listViewBookmarks.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String curSection = separatedListAdapter.getSectionForPosition(position);
Log.v(TAG, "Clicked on item id " + separatedListAdapter.getItemId(position) + " in section " + curSection);
if(curSection == sectionLabelBookmarks)
{
String refStr = view.getTag().toString();
if(curSection == sectionLabelBookmarks) {
String refStr = view.getTag().toString();
if (ConnectionReference.isManualBookmarkReference(refStr) ||
ConnectionReference.isHostnameReference(refStr))
{
ConnectionReference.isHostnameReference(refStr)) {
Bundle bundle = new Bundle();
bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr);
bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr);
Intent sessionIntent = new Intent(view.getContext(), SessionActivity.class);
sessionIntent.putExtras(bundle);
startActivity(sessionIntent);
Intent sessionIntent = new Intent(view.getContext(), SessionActivity.class);
sessionIntent.putExtras(bundle);
startActivity(sessionIntent);
// clear any search text
superBarEditText.setText("");
superBarEditText.clearFocus();
}
else if (ConnectionReference.isPlaceholderReference(refStr))
{
} else if (ConnectionReference.isPlaceholderReference(refStr)) {
// is this the add bookmark placeholder?
if (ConnectionReference.getPlaceholder(refStr).equals(ADD_BOOKMARK_PLACEHOLDER))
{
Intent bookmarkIntent = new Intent(view.getContext(), BookmarkActivity.class);
startActivity(bookmarkIntent);
if (ConnectionReference.getPlaceholder(refStr).equals(ADD_BOOKMARK_PLACEHOLDER)) {
Intent bookmarkIntent = new Intent(view.getContext(), BookmarkActivity.class);
startActivity(bookmarkIntent);
}
}
}
}
});
listViewBookmarks.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
listViewBookmarks.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
// if the selected item is not a session item (tag == null) and not a quick connect entry
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
// if the selected item is not a session item (tag == null) and not a quick connect entry
// (not a hostname connection reference) inflate the context menu
View itemView = ((AdapterContextMenuInfo)menuInfo).targetView;
String refStr = itemView.getTag() != null ? itemView.getTag().toString() : null;
if (refStr != null && !ConnectionReference.isHostnameReference(refStr) && !ConnectionReference.isPlaceholderReference(refStr))
{
String refStr = itemView.getTag() != null ? itemView.getTag().toString() : null;
if (refStr != null && !ConnectionReference.isHostnameReference(refStr) && !ConnectionReference.isPlaceholderReference(refStr)) {
getMenuInflater().inflate(R.menu.bookmark_context_menu, menu);
menu.setHeaderTitle(getResources().getString(R.string.menu_title_bookmark));
menu.setHeaderTitle(getResources().getString(R.string.menu_title_bookmark));
}
}
}
});
superBarEditText.addTextChangedListener(new SuperBarTextWatcher());
superBarEditText.addTextChangedListener(new SuperBarTextWatcher());
clearTextButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
superBarEditText.setText("");
}
});
webViewGetStarted.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
if (url.endsWith("new_connection"))
{
Intent bookmarkIntent = new Intent(getApplicationContext(), BookmarkActivity.class);
startActivity(bookmarkIntent);
return true;
}
return false;
superBarEditText.setText("");
}
});
});
}
@Override
public boolean onSearchRequested() {
superBarEditText.requestFocus();
return true;
}
@Override
public boolean onContextItemSelected(MenuItem aItem) {
// get connection reference
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)aItem.getMenuInfo();
String refStr = menuInfo.targetView.getTag().toString();
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)aItem.getMenuInfo();
String refStr = menuInfo.targetView.getTag().toString();
// refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case here ..
int itemId = aItem.getItemId();
if (itemId == R.id.bookmark_connect)
{
if (itemId == R.id.bookmark_connect) {
Bundle bundle = new Bundle();
bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr);
Intent sessionIntent = new Intent(this, SessionActivity.class);
sessionIntent.putExtras(bundle);
bundle.putString(SessionActivity.PARAM_CONNECTION_REFERENCE, refStr);
Intent sessionIntent = new Intent(this, SessionActivity.class);
sessionIntent.putExtras(bundle);
startActivity(sessionIntent);
startActivity(sessionIntent);
return true;
}
else if (itemId == R.id.bookmark_edit)
{
} else if (itemId == R.id.bookmark_edit) {
Bundle bundle = new Bundle();
bundle.putString(BookmarkActivity.PARAM_CONNECTION_REFERENCE, refStr);
Intent bookmarkIntent = new Intent(this.getApplicationContext(), BookmarkActivity.class);
bookmarkIntent.putExtras(bundle);
bookmarkIntent.putExtras(bundle);
startActivity(bookmarkIntent);
return true;
}
else if (itemId == R.id.bookmark_delete)
{
if(ConnectionReference.isManualBookmarkReference(refStr))
{
} else if (itemId == R.id.bookmark_delete) {
if(ConnectionReference.isManualBookmarkReference(refStr)) {
long id = ConnectionReference.getManualBookmarkId(refStr);
GlobalApp.getManualBookmarkGateway().delete(id);
manualBookmarkAdapter.remove(id);
separatedListAdapter.notifyDataSetChanged();
}
else
{
} else {
assert false;
}
showWelcomeScreenOrBookmarkList();
// clear super bar text
superBarEditText.setText("");
return true;
}
return true;
}
return false;
}
}
@Override
protected void onResume() {
super.onResume();
Log.v(TAG, "HomeActivity.onResume");
// create bookmark cursor adapter
manualBookmarkAdapter = new BookmarkArrayAdapter(this, R.layout.bookmark_list_item, GlobalApp.getManualBookmarkGateway().findAll());
// add add bookmark item to manual adapter
manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0);
// attach all adapters to the separatedListView adapter and assign it to the list view
separatedListAdapter = new SeparatedListAdapter(this);
separatedListAdapter.addSection(sectionLabelBookmarks, manualBookmarkAdapter);
listViewBookmarks.setAdapter(separatedListAdapter);
// show welcome screen in case we have a first-time user
showWelcomeScreenOrBookmarkList();
listViewBookmarks.setAdapter(separatedListAdapter);
// if we have a filter text entered cause an update to be caused here
String filter = superBarEditText.getText().toString();
if (filter.length() > 0)
@ -283,54 +259,46 @@ public class HomeActivity extends Activity
separatedListAdapter = null;
manualBookmarkAdapter = null;
}
@Override
public void onBackPressed()
{
// if back was pressed - ask the user if he really wants to exit
if (GlobalSettings.getAskOnExit())
{
public void onBackPressed() {
// if back was pressed - ask the user if he really wants to exit
if (GlobalSettings.getAskOnExit()) {
final CheckBox cb = new CheckBox(this);
cb.setChecked(!GlobalSettings.getAskOnExit());
cb.setText(R.string.dlg_dont_show_again);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.dlg_title_exit)
.setMessage(R.string.dlg_msg_exit)
.setView(cb)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which)
{
GlobalSettings.setAskOnExit(!cb.isChecked());
finish();
}
public void onClick(DialogInterface dialog, int which) {
GlobalSettings.setAskOnExit(!cb.isChecked());
finish();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which)
{
GlobalSettings.setAskOnExit(!cb.isChecked());
dialog.dismiss();
}
public void onClick(DialogInterface dialog, int which) {
GlobalSettings.setAskOnExit(!cb.isChecked());
dialog.dismiss();
}
})
.create()
.show();
}
else
{
.show();
} else {
super.onBackPressed();
}
}
@Override
protected void onSaveInstanceState(Bundle outState)
{
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(PARAM_SUPERBAR_TEXT, superBarEditText.getText().toString());
}
@Override
protected void onRestoreInstanceState(Bundle inState)
{
protected void onRestoreInstanceState(Bundle inState) {
super.onRestoreInstanceState(inState);
superBarEditText.setText(inState.getString(PARAM_SUPERBAR_TEXT));
}
@ -347,45 +315,29 @@ public class HomeActivity extends Activity
// refer to http://tools.android.com/tips/non-constant-fields why we can't use switch/case here ..
int itemId = item.getItemId();
if (itemId == R.id.newBookmark)
{
if (itemId == R.id.newBookmark) {
Intent bookmarkIntent = new Intent(this, BookmarkActivity.class);
startActivity(bookmarkIntent);
}
else if (itemId == R.id.appSettings)
{
startActivity(bookmarkIntent);
} else if (itemId == R.id.appSettings) {
Intent settingsIntent = new Intent(this, ApplicationSettingsActivity.class);
startActivity(settingsIntent);
}
else if (itemId == R.id.help)
{
} else if (itemId == R.id.help) {
Intent helpIntent = new Intent(this, HelpActivity.class);
startActivity(helpIntent);
}
else if (itemId == R.id.about)
{
} else if (itemId == R.id.about) {
Intent aboutIntent = new Intent(this, AboutActivity.class);
startActivity(aboutIntent);
}
return true;
}
private void showWelcomeScreenOrBookmarkList()
{
listViewBookmarks.setVisibility(View.VISIBLE);
webViewGetStarted.setVisibility(View.GONE);
}
private class SuperBarTextWatcher implements TextWatcher
{
private class SuperBarTextWatcher implements TextWatcher {
@Override
public void afterTextChanged(Editable s) {
if(separatedListAdapter != null)
{
if(separatedListAdapter != null) {
String text = s.toString();
if(text.length() > 0)
{
if(text.length() > 0) {
ArrayList<BookmarkBase> computers_list = GlobalApp.getQuickConnectHistoryGateway().findHistory(text);
computers_list.addAll(GlobalApp.getManualBookmarkGateway().findByLabelOrHostnameLike(text));
manualBookmarkAdapter.replaceItems(computers_list);
@ -393,13 +345,11 @@ public class HomeActivity extends Activity
qcBm.setLabel(text);
qcBm.setHostname(text);
manualBookmarkAdapter.insert(qcBm, 0);
}
else
{
} else {
manualBookmarkAdapter.replaceItems(GlobalApp.getManualBookmarkGateway().findAll());
manualBookmarkAdapter.insert(addBookmarkPlaceholder, 0);
}
separatedListAdapter.notifyDataSetChanged();
}
}
@ -410,6 +360,6 @@ public class HomeActivity extends Activity
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
}
}

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -23,7 +23,7 @@ body {
font: 100%%/1.4 Helvetica;
background-color:#E9EBF8;
height: 100%%; width: 100%%; margin: 0;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;
text-align:center;
@ -153,7 +153,7 @@ a:hover, a:active, a:focus { /* this group of selectors will give a keyboard nav
<h2>aFreeRDP </br>Remote Desktop Client</h2>
</div>
<p>
<img src="FreeRDP_Logo.png" width="30%%"></p>
<img src="../FreeRDP_Logo.png" width="30%%"></p>
<div id="introduction">
aFreeRDP is an open source client

View File

@ -23,7 +23,7 @@ body {
font: 100%%/1 Helvetica;
background-color:#E9EBF8;
height: 100%%; width: 100%%; margin: 0;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;
text-align:center;
@ -155,7 +155,7 @@ a:hover, a:active, a:focus { /* this group of selectors will give a keyboard nav
<h2>aFreeRDP</br>Remote Desktop Client</h2>
</div>
<p>
<img src="FreeRDP_Logo.png" width="25%%"></p>
<img src="../FreeRDP_Logo.png" width="25%%"></p>
<div id="introduction">
<b>aFreeRDP</b> is an open source client for Windows Remote Services using Remote Desktop Protocol (RDP) in order to remotely access your Windows desktop.</div>

View File

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 140 KiB

View File

@ -0,0 +1,202 @@
<html>
<head>
<meta name='viewport' content='width=device-width; initial-scale=1.0; maximum-scale=1.0;' />
<script language="javascript">
function toggle() {
var ele = document.getElementById("toggleText");
var text = document.getElementById("displayText");
if(ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "show";
}
else {
ele.style.display = "block";
text.innerHTML = "<b>hide</b>";
}
}
</script>
<style type="text/css">
@charset "utf-8";
body {
font: 100%%/1.4 Helvetica;
background-color:#E9EBF8;
height: 100%%; width: 100%%; margin: 0;
background-image:url(../background.jpg);
background-position:center;
text-align:center;
}
.centered-table {
margin-left: auto;
margin-right: auto;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#footer{
padding-top:10px;
}
#footer img{
padding top:10 px;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%%;
padding-bottom:0.1%%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#introduction_headline{
width:inherit;
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
border-bottom-left-radius:15px;
border-bottom-right-radius:15px;
}
#introduction{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%%;
padding-bottom:0.1%%;
border-radius: 10px;
color:#000;
}
#container
{
margin-left: auto;
margin-right: auto;
width: 50em;
width:420px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method. */
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
alignment: right;}
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
a:link { color:#0000FF; }
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<div id="introduction_headline">
<h2>aFreeRDP </br>Remote Desktop Client</h2>
</div>
<p>
<img src="../FreeRDP_Logo.png" width="30%%"></p>
<div id="introduction">
aFreeRDP ist ein Open Source Programm
mit nativer Unterstützung des Remote Desktop Protocol (RDP) um einen entfernten Zugriff auf Windows Desktops zu ermöglichen.</div>
<div id="article">
<div id="headline"><h3>Versions Information</h3></div>
<p>
<table class="centered-table" border=0 cellspacing=1 cellpadding=3 >
<tr>
<td>aFreeRDP Version</td> <td>%1$s</td> </tr>
<tr> <td>System Version</td> <td>%2$s</td> </tr>
<tr> <td>Model</td> <td>%3$s</td> </tr>
</table>
</p>
</div>
<div id="article">
<div id="headline">
<h3>Credits</h3>
</div>
aFreeRDP ist ein Teil von <a href="http://www.freerdp.com/">FreeRDP</a>
</div>
<div id="article">
<div id="headline">
<h3>Lizenz</h3>
</div>
This program is free software; you can redistribute it and/or modify it under the terms of the Mozilla Public License, v. 2.0.
You can obtain an online version of the License from <a href="http://mozilla.org/MPL/2.0/">http://mozilla.org/MPL/2.0/</a>.
</p>
<p>
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</p>
<p>
A copy of the product's source code can be obtained from the FreeRDP GitHub repository at <a
href="https://github.com/FreeRDP/FreeRDP">https://github.com/FreeRDP/FreeRDP</a>.<br />
</p>
<br></div>
</body>
</html>

View File

@ -0,0 +1,201 @@
<html>
<head>
<meta name='viewport' content='width=device-width; initial-scale=1.0; maximum-scale=1.0;' />
<script language="javascript">
function toggle() {
var ele = document.getElementById("toggleText");
var text = document.getElementById("displayText");
if(ele.style.display == "block") {
ele.style.display = "none";
text.innerHTML = "show";
}
else {
ele.style.display = "block";
text.innerHTML = "<b>hide</b>";
}
}
</script>
<style type="text/css">
@charset "utf-8";
body {
font: 100%%/1 Helvetica;
background-color:#E9EBF8;
height: 100%%; width: 100%%; margin: 0;
background-image:url(../background.jpg);
background-position:center;
text-align:center;
}
.centered-table {
margin-left: auto;
margin-right: auto;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#footer{
padding-top:10px;
}
#footer img{
padding top:10 px;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%%;
padding-bottom:0.1%%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#introduction_headline{
width:inherit;
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
border-bottom-left-radius:15px;
border-bottom-right-radius:15px;
}
#introduction{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%%;
padding-bottom:0.1%%;
border-radius: 10px;
color:#000;
}
#container
{
margin-left: auto;
margin-right: auto;
width:300px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method. */
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
alignment: right;}
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
a:link { color:#0000FF; }
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
}
</style>
</head>
<body>
<div id="container">
<div id="introduction_headline">
<h2>aFreeRDP</br>Remote Desktop Client</h2>
</div>
<p>
<img src="../FreeRDP_Logo.png" width="25%%"></p>
<div id="introduction">
aFreeRDP ist ein Open Source Programm
mit nativer Unterstützung des Remote Desktop Protocol (RDP) um einen entfernten Zugriff auf Windows Desktops zu ermöglichen.</div>
<div id="article">
<div id="headline"><h3>Versions Information</h3></div>
<p>
<table class="centered-table" border=0 cellspacing=1 cellpadding=3 >
<tr>
<td>aFreeRDP Version</td> <td>%1$s</td> </tr>
<tr> <td>System Version</td> <td>%2$s</td> </tr>
<tr> <td>Model</td> <td>%3$s</td> </tr>
</table>
</p>
</div>
<div id="article">
<div id="headline">
<h3>Credits</h3>
</div>
aFreeRDP ist ein Teil von <a href="http://www.freerdp.com/">FreeRDP</a>
</div>
<div id="article">
<div id="headline">
<h3>Lizenz</h3>
</div>
This program is free software; you can redistribute it and/or modify it under the terms of the Mozilla Public License, v. 2.0.
You can obtain an online version of the License from <a href="http://mozilla.org/MPL/2.0/">http://mozilla.org/MPL/2.0/</a>.
</p>
<p>
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</p>
<p>
A copy of the product's source code can be obtained from the FreeRDP GitHub repository at <a
href="https://github.com/FreeRDP/FreeRDP">https://github.com/FreeRDP/FreeRDP</a>.<br />
</p> </div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,159 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
}
body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(../background.jpg);
background-position:center;
color:#000;
}
#headline{
background-color:#353639;
opacity:0.9;
color:#000;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
height:auto;
width:100%;
background-color:#353639;
padding-bottom:5px;
padding-left:5px;
padding-right:5px;
padding-top:10px;
position: fixed;
top: 0;
left: 0;
height:40px;
overflow:visible;
min-width:400px;
z-index:20;
}
#content{
padding-top:70px;
z-index:-20;
max-width:420px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures.html"><img src="nav_gestures.png"></a>
<a href="toolbar.html"><img src="nav_toolbar.png"></a>
<a href="touch_pointer.html"><img src="nav_touch_pointer.png"></a>
</div>
<div id="content">
<h1>Gesten</h1>
<p>
aFreeRDP ist für Touch Geräte entwickelt worden.
Diese Gesten lassen sie die häufigsten Operationen mit ihren Fingern durchführen.</p>
<p> <img src="gestures.png"></p>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -0,0 +1,159 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
color:#000;}
body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(../background.jpg);
background-position:center;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
width:100%;
background-color:#353639;
padding-bottom:1px;
padding-left:5px;
padding-right:5px;
padding-top:5px;
position: fixed;
top: 0;
left: 0;
height:30px;
min-width:250px;
z-index:20;
}
#content{
padding-top:40px;
z-index:-20;
max-width:300px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures_phone.html"><img src="nav_gestures.png" height="90%"></a>
<a href="toolbar_phone.html"><img src="nav_toolbar.png" height="90%"></a>
<a href="touch_pointer_phone.html"><img src="nav_touch_pointer.png" height="90%""></a>
</div>
<div id="content">
<h2>Gesten</h2>
<p>
aFreeRDP ist für Touch Geräte entwickelt worden.
Diese Gesten lassen sie die häufigsten Operationen mit ihren Fingern durchführen.</p>
<p> <img src="gestures_phone.png"></p>
</div>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,178 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
color:#FFFFFF;}
body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(../background.jpg);
background-position:center;
}
#headline{
background-color:#353639;
color:#FFF;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
height:auto;
width:100%;
background-color:#353639;
padding-bottom:5px;
padding-left:5px;
padding-right:5px;
padding-top:10px;
position: fixed;
top: 0;
left: 0;
height:40px;
overflow:visible;
min-width:400px;
z-index:20;
}
#content{
padding-top:70px;
z-index:-20;
max-width:420px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures.html"><img src="nav_gestures.png"></a>
<a href="toolbar.html"><img src="nav_toolbar.png"></a>
<a href="touch_pointer.html"><img src="nav_touch_pointer.png"></a>
</div>
<div id="content">
<h1>Toolbar</h1>
<p>
With the toolbar you'll be able to display and hide the main tools in your session. This allows together with the touch pointer and the gestures an intuitiv workflow for remote computing on touch sensitive screens.
</p>
<p><img src="toolbar.png"></p>
<div id="article">
<div id="headline">
<h3><span style="color:white">Tastatur</span></h3></div>
Zeige/verstecke die standard und die erweiterte Tastatur mit Funktionstasten</div>
<div id="article">
<div id="headline"><h3><span style="color:white">Touch Zeiger</span></h3></div>
Zeige/verstecke den gesten gesteuerten Zeiger</div>
<div id="article">
<div id="headline"><h3><span style="color:white">Beenden</span></h3></div>
Beende die aktuelle Sitzung. Seihen sie sich bewusst, dass das Beenden kein Logout ist.</div>
</div>
</div></center>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,176 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
color:#FFFFFF;}
body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(../background.jpg);
background-position:center;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
width:100%;
background-color:#353639;
padding-bottom:1px;
padding-left:5px;
padding-right:5px;
padding-top:5px;
position: fixed;
top: 0;
left: 0;
height:30px;
min-width:250px;
z-index:20;
}
#content{
padding-top:40px;
z-index:-20;
max-width:300px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures_phone.html"><img src="nav_gestures.png" height="90%"></a>
<a href="toolbar_phone.html"><img src="nav_toolbar.png" height="90%"></a>
<a href="touch_pointer_phone.html"><img src="nav_touch_pointer.png" height="90%""></a>
</div>
<div id="content">
<h2>Toolbar</h2>
<p>
With the toolbar you'll be able to display and hide the main tools in your session. This allows together with the touch pointer and the gestures an intuitiv workflow for remote computing on touch sensitive screens.
</p>
<p><img src="toolbar_phone.png"></p>
<div id="article">
<div id="headline">
<h4><span style="color:white">Tastatur</h4></span></div>
Zeige/verstecke die standard und die erweiterte Tastatur mit Funktionstasten</div>
<div id="article">
<div id="headline"><h4><span style="color:white">Touch Zeiger</h4></div>
Zeige/verstecke den gesten gesteuerten Zeiger</div>
<div id="article">
<div id="headline"><h4><span style="color:white">Beenden</span></h4></div>
Beende die aktuelle Sitzung. Seihen sie sich bewusst, dass das Beenden kein Logout ist.
</div>
</div></center>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -0,0 +1,164 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
color:#FFFFFF;}
body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(../background.jpg);
background-position:center;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
height:auto;
width:100%;
background-color:#353639;
padding-bottom:5px;
padding-left:5px;
padding-right:5px;
padding-top:10px;
position: fixed;
top: 0;
left: 0;
height:40px;
overflow:visible;
min-width:400px;
z-index:20;
}
#content{
padding-top:70px;
z-index:-20;
max-width:420px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures.html"><img src="nav_gestures.png"></a>
<a href="toolbar.html"><img src="nav_toolbar.png"></a>
<a href="touch_pointer.html"><img src="nav_touch_pointer.png"></a>
</div>
<div id="content">
<h1>Touch Pointer</h1>
<p><img src="touch_pointer.png">
</div>
</center>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

View File

@ -0,0 +1,161 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;" />
<title>Help</title>
<style type="text/css">
@charset "utf-8";
#container{
text-align:center;
color:#FFFFFF;}
body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(../background.jpg);
background-position:center;
}
#headline{
background-color:#353639;
opacity:0.9;
color:FFF;
text-align:center;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 15px;
border-top-left-radius:0px;
border-top-right-radius:0px;
color:#000;
margin: 10px auto;
position:relative;
}
#header{
width:100%;
background-color:#353639;
padding-bottom:1px;
padding-left:5px;
padding-right:5px;
padding-top:5px;
position: fixed;
top: 0;
left: 0;
height:30px;
min-width:250px;
z-index:20;
}
#content{
padding-top:40px;
z-index:-20;
max-width:300px;
}
/* ~~ Element/tag selectors ~~ */
ul, ol, dl { /* Due to variations between browsers, it's best practices to zero padding and margin on lists. For consistency, you can either specify the amounts you want here, or on the list items (LI, DT, DD) they contain. Remember that what you do here will cascade to the .nav list unless you write a more specific selector. */
padding: 0;
margin: 0;
}
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method.
*/
color:#000;
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="container">
<center>
<div id="header">
<a href="gestures_phone.html"><img src="nav_gestures.png" height="90%"></a>
<a href="toolbar_phone.html"><img src="nav_toolbar.png" height="90%"></a>
<a href="touch_pointer_phone.html"><img src="nav_touch_pointer.png" height="90%""></a>
</div>
<div id="content">
<h2>Touch Pointer</h2>
<p><img src="touch_pointer_phone.png">
</p>
</div>
</center>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;
color:#000;

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100%/1.4 Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;

View File

@ -21,7 +21,7 @@ body{
margin:0;
padding:<length> 0 0 0;
font: 100% Helvetica;
background-image:url(back.jpg);
background-image:url(../background.jpg);
background-position:center;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,128 +0,0 @@
<html>
<head>
<meta name='viewport' content='width=device-width; initial-scale=1.0; maximum-scale=1.0;' />
<style type="text/css">
@charset "utf-8";
body {
font: 100%/1.4 Helvetica;
background-color:#E9EBF8;
height: 100%; width: 100%; margin: 0;
background-image:url(back.jpg);
}
/* ~~ Element/tag selectors ~~ */
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method. */
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
alignment: right;}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
#number
{
margin-left:0%;
opacity:0.9;
background:#DDD;
}
#content
{
margin-left: auto;
margin-right: auto;
width:420px;
}
#headline{
width:inherit;
background-color:#353639;
border-radius: 15px;
color:FFF;
text-align:center;
border-bottom-left-radius:0px;
border-bottom-right-radius:0px;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 18px;
position:relative;
}
#text{
margin-left:30px;
position:static;
margin-bottom:3%;
margin-top:3%;
}
#button{
padding-top:10px;
padding-bottom:10px;
}
a:link { color:#0000FF; }
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="content">
<div id="article">
<div id="headline">
<h1>New Connection</h1>
</div><div id="text">
You can specify your own connection settings - just hit the button below or choose "New Connection" from the application menu.</div>
<div id="button">
<center><a href="new_connection"><img src="new_connection.png"></a><center></a>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,121 +0,0 @@
<html>
<head>
<meta name='viewport' content='width=device-width; initial-scale=1.0; maximum-scale=1.0;' />
<style type="text/css">
@charset "utf-8";
body {
font: 100%/1 Helvetica;
background-color:#E9EBF8;
height: 100%; width: 100%; margin: 0;
background-image:url(back.jpg);
}
/* ~~ Element/tag selectors ~~ */
h1, h2, h3, h4, h5, h6, p {
margin-top: 0; /* removing the top margin gets around an issue where margins can escape from their containing div. The remaining bottom margin will hold it away from any elements that follow. */
padding-right: 1px;
padding-left: 1px; /* adding the padding to the sides of the elements within the divs, instead of the divs themselves, gets rid of any box model math. A nested div with side padding can also be used as an alternate method. */
}
a img { /* this selector removes the default blue border displayed in some browsers around an image when it is surrounded by a link */
border: none;
alignment: right;}
/* ~~ Styling for your site's links must remain in this order - including the group of selectors that create the hover effect. ~~ */
/*a:link {
color:#414958;
text-decoration: underline; unless you style your links to look extremely unique, it's best to provide underlines for quick visual identification */
a:hover, a:active, a:focus { /* this group of selectors will give a keyboard navigator the same hover experience as the person using a mouse. */
text-decoration: none;}
#number
{
margin-left:0%;
opacity:0.9;
background:#DDD;
}
#content
{
margin-left: auto;
margin-right: auto;
width:300px;
}
#headline{
width:inherit;
background-color:#353639;
border-radius: 15px;
color:FFF;
text-align:center;
border-bottom-left-radius:0px;
border-bottom-right-radius:0px;
}
#article{
background-color:#FFFFFF;
opacity: 0.8;
z-index:0;
margin-bottom:3%;
padding-bottom:0.1%;
border-radius: 18px;
position:relative;
}
#text{
margin-left:30px;
position:static;
margin-bottom:3%;
margin-top:3%;
}
#button{
padding-top:10px;
padding-bottom:10px;
}
a:link { color:#0000FF; }
* {
-webkit-touch-callout: none;
-webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
</head>
<body>
<div id="content">
<div id="article">
<div id="headline">
<h2>New Connection</h2>
</div><div id="text">
You can specify your own connection settings - just hit the button below or choose "New Connection" from the application menu.</div>
<div id="button">
<center><a href="new_connection"><img src="new_connection.png"></a><center></a>
</div>
</div>
</div>
</body>
</html>

View File

@ -148,6 +148,10 @@ set(XRENDER_FEATURE_TYPE "RECOMMENDED")
set(XRENDER_FEATURE_PURPOSE "rendering")
set(XRENDER_FEATURE_DESCRIPTION "X11 render extension")
set(XFIXES_FEATURE_TYPE "RECOMMENDED")
set(XFIXES_FEATURE_PURPOSE "X11 xfixes extension")
set(XFIXES_FEATURE_DESCRIPTION "Useful additions to the X11 core protocol")
find_feature(XShm ${XSHM_FEATURE_TYPE} ${XSHM_FEATURE_PURPOSE} ${XSHM_FEATURE_DESCRIPTION})
find_feature(Xinerama ${XINERAMA_FEATURE_TYPE} ${XINERAMA_FEATURE_PURPOSE} ${XINERAMA_FEATURE_DESCRIPTION})
find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION})
@ -155,6 +159,7 @@ find_feature(Xcursor ${XCURSOR_FEATURE_TYPE} ${XCURSOR_FEATURE_PURPOSE} ${XCURSO
find_feature(Xv ${XV_FEATURE_TYPE} ${XV_FEATURE_PURPOSE} ${XV_FEATURE_DESCRIPTION})
find_feature(Xi ${XI_FEATURE_TYPE} ${XI_FEATURE_PURPOSE} ${XI_FEATURE_DESCRIPTION})
find_feature(Xrender ${XRENDER_FEATURE_TYPE} ${XRENDER_FEATURE_PURPOSE} ${XRENDER_FEATURE_DESCRIPTION})
find_feature(Xfixes ${XFIXES_FEATURE_TYPE} ${XFIXES_FEATURE_PURPOSE} ${XFIXES_FEATURE_DESCRIPTION})
if(WITH_XINERAMA)
add_definitions(-DWITH_XINERAMA)
@ -192,6 +197,12 @@ if(WITH_XRENDER)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XRENDER_LIBRARIES})
endif()
if(WITH_XFIXES)
add_definitions(-DWITH_XFIXES)
include_directories(${XFIXES_INCLUDE_DIRS})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${XFIXES_LIBRARIES})
endif()
include_directories(${CMAKE_SOURCE_DIR}/resources)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client)

View File

@ -25,6 +25,10 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef WITH_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <winpr/crt.h>
#include <winpr/stream.h>
@ -88,6 +92,11 @@ struct clipboard_context
BOOL incr_starts;
BYTE* incr_data;
int incr_data_length;
/* X Fixes extension */
int xfixes_event_base;
int xfixes_error_base;
BOOL xfixes_supported;
};
void xf_cliprdr_init(xfContext* xfc, rdpChannels* channels)
@ -121,6 +130,30 @@ void xf_cliprdr_init(xfContext* xfc, rdpChannels* channels)
XSelectInput(xfc->display, cb->root_window, PropertyChangeMask);
#ifdef WITH_XFIXES
if (XFixesQueryExtension(xfc->display, &cb->xfixes_event_base, &cb->xfixes_error_base))
{
int xfmajor, xfminor;
if (XFixesQueryVersion(xfc->display, &xfmajor, &xfminor))
{
DEBUG_X11_CLIPRDR("Found X Fixes extension version %d.%d", xfmajor, xfminor);
XFixesSelectSelectionInput(xfc->display, cb->root_window,
cb->clipboard_atom, XFixesSetSelectionOwnerNotifyMask);
cb->xfixes_supported = TRUE;
}
else
{
fprintf(stderr, "%s: Error querying X Fixes extension version\n", __FUNCTION__);
}
}
else
{
fprintf(stderr, "%s: Error loading X Fixes extension\n", __FUNCTION__);
}
#else
fprintf(stderr, "Warning: Using clipboard redirection without XFIXES extension is strongly discouraged!\n");
#endif
n = 0;
cb->format_mappings[n].target_format = XInternAtom(xfc->display, "_FREERDP_RAW", FALSE);
cb->format_mappings[n].format_id = CB_FORMAT_RAW;
@ -718,8 +751,11 @@ static void xf_cliprdr_process_requested_data(xfContext* xfc, BOOL has_data, BYT
else
xf_cliprdr_send_null_data_response(xfc);
/* Resend the format list, otherwise the server won't request again for the next paste */
xf_cliprdr_send_format_list(xfc);
if (!cb->xfixes_supported)
{
/* Resend the format list, otherwise the server won't request again for the next paste */
xf_cliprdr_send_format_list(xfc);
}
}
static BOOL xf_cliprdr_get_requested_data(xfContext* xfc, Atom target)
@ -1077,7 +1113,7 @@ void xf_process_cliprdr_event(xfContext* xfc, wMessage* event)
}
}
BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent)
static BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent)
{
clipboardContext* cb = (clipboardContext*) xfc->clipboard_context;
@ -1101,7 +1137,7 @@ BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent)
}
}
BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent)
static BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent)
{
int i;
int fmt;
@ -1218,7 +1254,7 @@ BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent)
return TRUE;
}
BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent)
static BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent)
{
clipboardContext* cb = (clipboardContext*) xfc->clipboard_context;
@ -1230,7 +1266,7 @@ BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent)
return TRUE;
}
BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent)
static BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent)
{
clipboardContext* cb = (clipboardContext*) xfc->clipboard_context;
@ -1257,7 +1293,7 @@ BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent)
return TRUE;
}
void xf_cliprdr_check_owner(xfContext* xfc)
static void xf_cliprdr_check_owner(xfContext* xfc)
{
Window owner;
clipboardContext* cb = (clipboardContext*) xfc->clipboard_context;
@ -1274,3 +1310,53 @@ void xf_cliprdr_check_owner(xfContext* xfc)
}
}
void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event)
{
clipboardContext* cb;
if (!xfc || !event)
return;
if (!(cb = (clipboardContext*) xfc->clipboard_context))
return;
#ifdef WITH_XFIXES
if (cb->xfixes_supported && event->type == XFixesSelectionNotify + cb->xfixes_event_base)
{
XFixesSelectionNotifyEvent* se = (XFixesSelectionNotifyEvent*) event;
if (se->subtype == XFixesSetSelectionOwnerNotify)
{
if (se->selection != cb->clipboard_atom)
return;
if (XGetSelectionOwner(xfc->display, se->selection) == xfc->drawable)
return;
cb->owner = None;
xf_cliprdr_check_owner(xfc);
}
return;
}
#endif
switch (event->type)
{
case SelectionNotify:
xf_cliprdr_process_selection_notify(xfc, event);
break;
case SelectionRequest:
xf_cliprdr_process_selection_request(xfc, event);
break;
case SelectionClear:
xf_cliprdr_process_selection_clear(xfc, event);
break;
case PropertyNotify:
xf_cliprdr_process_property_notify(xfc, event);
break;
case FocusIn:
if (!cb->xfixes_supported)
{
xf_cliprdr_check_owner(xfc);
}
break;
}
}

View File

@ -26,10 +26,5 @@
void xf_cliprdr_init(xfContext* xfc, rdpChannels* channels);
void xf_cliprdr_uninit(xfContext* xfc);
void xf_process_cliprdr_event(xfContext* xfc, wMessage* event);
BOOL xf_cliprdr_process_selection_notify(xfContext* xfc, XEvent* xevent);
BOOL xf_cliprdr_process_selection_request(xfContext* xfc, XEvent* xevent);
BOOL xf_cliprdr_process_selection_clear(xfContext* xfc, XEvent* xevent);
BOOL xf_cliprdr_process_property_notify(xfContext* xfc, XEvent* xevent);
void xf_cliprdr_check_owner(xfContext* xfc);
void xf_cliprdr_handle_xevent(xfContext* xfc, XEvent* event);
#endif /* __XF_CLIPRDR_H */

View File

@ -545,9 +545,6 @@ static BOOL xf_event_FocusIn(xfContext* xfc, XEvent* event, BOOL app)
xf_keyboard_focus_in(xfc);
if (!app)
xf_cliprdr_check_owner(xfc);
return TRUE;
}
@ -793,39 +790,6 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, XEvent* event, BOOL app)
return TRUE;
}
static BOOL xf_event_SelectionNotify(xfContext* xfc, XEvent* event, BOOL app)
{
if (!app)
{
if (xf_cliprdr_process_selection_notify(xfc, event))
return TRUE;
}
return TRUE;
}
static BOOL xf_event_SelectionRequest(xfContext* xfc, XEvent* event, BOOL app)
{
if (!app)
{
if (xf_cliprdr_process_selection_request(xfc, event))
return TRUE;
}
return TRUE;
}
static BOOL xf_event_SelectionClear(xfContext* xfc, XEvent* event, BOOL app)
{
if (!app)
{
if (xf_cliprdr_process_selection_clear(xfc, event))
return TRUE;
}
return TRUE;
}
static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app)
{
/*
@ -922,11 +886,6 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, XEvent* event, BOOL app)
}
}
}
else
{
if (xf_cliprdr_process_property_notify(xfc, event))
return TRUE;
}
return TRUE;
}
@ -1112,24 +1071,17 @@ BOOL xf_event_process(freerdp* instance, XEvent* event)
status = xf_event_ClientMessage(xfc, event, xfc->remote_app);
break;
case SelectionNotify:
status = xf_event_SelectionNotify(xfc, event, xfc->remote_app);
break;
case SelectionRequest:
status = xf_event_SelectionRequest(xfc, event, xfc->remote_app);
break;
case SelectionClear:
status = xf_event_SelectionClear(xfc, event, xfc->remote_app);
break;
case PropertyNotify:
status = xf_event_PropertyNotify(xfc, event, xfc->remote_app);
break;
}
if (!xfc->remote_app)
{
xf_cliprdr_handle_xevent(xfc, event);
}
xf_input_handle_event(xfc, event);
XSync(xfc->display, FALSE);

View File

@ -416,6 +416,9 @@ int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** p
if (count > 2)
serial->Path = _strdup(params[2]);
if (count > 3)
serial->Driver = _strdup(params[3]);
freerdp_device_collection_add(settings, (RDPDR_DEVICE*) serial);
return 1;

View File

@ -24,6 +24,7 @@
#cmakedefine HAVE_TIMERFD_H
#cmakedefine HAVE_TM_GMTOFF
#cmakedefine HAVE_AIO_H
#cmakedefine HAVE_POLL_H
#cmakedefine HAVE_PTHREAD_GNU_EXT
#cmakedefine HAVE_VALGRIND_MEMCHECK_H

View File

@ -466,6 +466,7 @@ struct _RDPDR_SERIAL
UINT32 Type;
char* Name;
char* Path;
char* Driver;
};
typedef struct _RDPDR_SERIAL RDPDR_SERIAL;

View File

@ -287,8 +287,17 @@ out_smartc_name_error:
goto out_serial_path_error;
}
if (serial->Driver)
{
_serial->Driver = _strdup(serial->Driver);
if (!_serial->Driver)
goto out_serial_driver_error;
}
return (RDPDR_DEVICE*) _serial;
out_serial_driver_error:
free(_serial->Path);
out_serial_path_error:
free(_serial->Name);
out_serial_name_error:
@ -360,6 +369,7 @@ void freerdp_device_collection_free(rdpSettings* settings)
else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_SERIAL)
{
free(((RDPDR_SERIAL*) device)->Path);
free(((RDPDR_SERIAL*) device)->Driver);
}
else if (settings->DeviceArray[index]->Type == RDPDR_DTYP_PARALLEL)
{

View File

@ -41,6 +41,13 @@
#include <netinet/tcp.h>
#include <net/if.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#else
#include <time.h>
#include <sys/select.h>
#endif
#ifdef __FreeBSD__
#ifndef SOL_TCP
#define SOL_TCP IPPROTO_TCP
@ -739,6 +746,83 @@ HANDLE tcp_get_event_handle(rdpTcp* tcp)
#endif
}
int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = tcp->sockfd;
pollset.events = POLLIN;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, dwMilliSeconds);
}
while ((status < 0) && (errno == EINTR));
#else
struct timeval tv;
fd_set rset;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
if (dwMilliSeconds)
{
tv.tv_sec = dwMilliSeconds / 1000;
tv.tv_usec = (dwMilliSeconds % 1000) * 1000;
}
do
{
status = select(tcp->sockfd + 1, &rset, NULL, NULL, dwMilliSeconds ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
return status;
}
int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollset;
pollset.fd = tcp->sockfd;
pollset.events = POLLOUT;
pollset.revents = 0;
do
{
status = poll(&pollset, 1, dwMilliSeconds);
}
while ((status < 0) && (errno == EINTR));
#else
struct timeval tv;
fd_set rset;
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
if (dwMilliSeconds)
{
tv.tv_sec = dwMilliSeconds / 1000;
tv.tv_usec = (dwMilliSeconds % 1000) * 1000;
}
do
{
status = select(tcp->sockfd + 1, NULL, &rset, NULL, dwMilliSeconds ? &tv : NULL);
}
while ((status < 0) && (errno == EINTR));
#endif
return status;
}
rdpTcp* tcp_new(rdpSettings* settings)
{
rdpTcp* tcp;

View File

@ -64,8 +64,8 @@ BOOL tcp_connect(rdpTcp* tcp, const char* hostname, int port, int timeout);
BOOL tcp_disconnect(rdpTcp* tcp);
int tcp_read(rdpTcp* tcp, BYTE* data, int length);
int tcp_write(rdpTcp* tcp, BYTE* data, int length);
int tcp_wait_read(rdpTcp* tcp);
int tcp_wait_write(rdpTcp* tcp);
int tcp_wait_read(rdpTcp* tcp, DWORD dwMilliSeconds);
int tcp_wait_write(rdpTcp* tcp, DWORD dwMilliSeconds);
BOOL tcp_set_blocking_mode(rdpTcp* tcp, BOOL blocking);
BOOL tcp_set_keep_alive_mode(rdpTcp* tcp);
int tcp_attach(rdpTcp* tcp, int sockfd);

View File

@ -43,9 +43,7 @@
#ifndef _WIN32
#include <netdb.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#endif
#endif /* _WIN32 */
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
@ -642,69 +640,37 @@ UINT32 nla_header_length(wStream* s)
static int transport_wait_for_read(rdpTransport* transport)
{
struct timeval tv;
fd_set rset, wset;
fd_set *rsetPtr = NULL, *wsetPtr = NULL;
rdpTcp *tcpIn;
tcpIn = transport->TcpIn;
rdpTcp *tcpIn = transport->TcpIn;
if (tcpIn->readBlocked)
{
rsetPtr = &rset;
FD_ZERO(rsetPtr);
FD_SET(tcpIn->sockfd, rsetPtr);
return tcp_wait_read(tcpIn, 10);
}
else if (tcpIn->writeBlocked)
{
wsetPtr = &wset;
FD_ZERO(wsetPtr);
FD_SET(tcpIn->sockfd, wsetPtr);
return tcp_wait_write(tcpIn, 10);
}
if (!wsetPtr && !rsetPtr)
{
USleep(1000);
return 0;
}
tv.tv_sec = 0;
tv.tv_usec = 1000;
return select(tcpIn->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
USleep(1000);
return 0;
}
static int transport_wait_for_write(rdpTransport* transport)
{
struct timeval tv;
fd_set rset, wset;
fd_set *rsetPtr = NULL, *wsetPtr = NULL;
rdpTcp *tcpOut;
tcpOut = transport->SplitInputOutput ? transport->TcpOut : transport->TcpIn;
if (tcpOut->writeBlocked)
{
wsetPtr = &wset;
FD_ZERO(wsetPtr);
FD_SET(tcpOut->sockfd, wsetPtr);
return tcp_wait_write(tcpOut, 10);
}
else if (tcpOut->readBlocked)
{
rsetPtr = &rset;
FD_ZERO(rsetPtr);
FD_SET(tcpOut->sockfd, rsetPtr);
return tcp_wait_read(tcpOut, 10);
}
if (!wsetPtr && !rsetPtr)
{
USleep(1000);
return 0;
}
tv.tv_sec = 0;
tv.tv_usec = 1000;
return select(tcpOut->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
USleep(1000);
return 0;
}
int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)

View File

@ -33,6 +33,11 @@
#include <freerdp/crypto/tls.h>
#include "../core/tcp.h"
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
struct _BIO_RDP_TLS
{
SSL* ssl;
@ -586,8 +591,12 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
do
{
#ifdef HAVE_POLL_H
struct pollfd pollfds;
#else
struct timeval tv;
fd_set rset;
#endif
int fd;
status = BIO_do_handshake(tls->bio);
@ -600,8 +609,6 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
/* we select() only for read even if we should test both read and write
* depending of what have blocked */
FD_ZERO(&rset);
fd = BIO_get_fd(tls->bio, NULL);
if (fd < 0)
@ -610,12 +617,24 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode)
return -1;
}
#ifdef HAVE_POLL_H
pollfds.fd = fd;
pollfds.events = POLLIN;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, 10 * 1000);
}
while ((status < 0) && (errno == EINTR));
#else
FD_ZERO(&rset);
FD_SET(fd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 10 * 1000; /* 10ms */
status = select(fd + 1, &rset, NULL, NULL, &tv);
status = _select(fd + 1, &rset, NULL, NULL, &tv);
#endif
if (status < 0)
{
fprintf(stderr, "%s: error during select()\n", __FUNCTION__);
@ -830,9 +849,13 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
{
int status, nchunks, commitedBytes;
rdpTcp *tcp;
#ifdef HAVE_POLL_H
struct pollfd pollfds;
#else
fd_set rset, wset;
fd_set *rsetPtr, *wsetPtr;
struct timeval tv;
#endif
BIO* bio = tls->bio;
DataChunk chunks[2];
@ -855,9 +878,34 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
if (!BIO_should_retry(bio))
return -1;
#ifdef HAVE_POLL_H
pollfds.fd = tcp->sockfd;
pollfds.revents = 0;
pollfds.events = 0;
if (tcp->writeBlocked)
{
pollfds.events |= POLLOUT;
}
else if (tcp->readBlocked)
{
pollfds.events |= POLLIN;
}
else
{
fprintf(stderr, "%s: weird we're blocked but the underlying is not read or write blocked !\n", __FUNCTION__);
USleep(10);
continue;
}
do
{
status = poll(&pollfds, 1, 100);
}
while ((status < 0) && (errno == EINTR));
#else
/* we try to handle SSL want_read and want_write nicely */
rsetPtr = wsetPtr = 0;
rsetPtr = wsetPtr = NULL;
if (tcp->writeBlocked)
{
@ -881,8 +929,8 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
status = select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
status = _select(tcp->sockfd + 1, rsetPtr, wsetPtr, NULL, &tv);
#endif
if (status < 0)
return -1;
}
@ -911,13 +959,24 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
if (!BIO_should_retry(tcp->socketBio))
goto out_fail;
#ifdef HAVE_POLL_H
pollfds.fd = tcp->sockfd;
pollfds.events = POLLIN;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, 100);
}
while ((status < 0) && (errno == EINTR));
#else
FD_ZERO(&rset);
FD_SET(tcp->sockfd, &rset);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
status = select(tcp->sockfd + 1, &rset, NULL, NULL, &tv);
status = _select(tcp->sockfd + 1, &rset, NULL, NULL, &tv);
#endif
if (status < 0)
goto out_fail;
}

View File

@ -59,7 +59,7 @@ endif()
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-synch winpr-thread winpr-utils winpr-path)
MODULES winpr-crt winpr-synch winpr-thread winpr-utils winpr-path winpr-winsock)
if(MONOLITHIC_BUILD)
set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)

View File

@ -24,6 +24,7 @@
#include <winpr/windows.h>
#include <winpr/crt.h>
#include <winpr/winsock.h>
#include <freerdp/utils/tcp.h>
@ -41,11 +42,16 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <net/if.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#else
#include <sys/select.h>
#endif
#ifdef __APPLE__
#ifndef TCP_KEEPIDLE
#define TCP_KEEPIDLE TCP_KEEPALIVE
@ -186,8 +192,14 @@ int freerdp_tcp_write(int sockfd, BYTE* data, int length)
int freerdp_tcp_wait_read(int sockfd)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollfds;
#else
fd_set fds;
struct timeval timeout;
#endif
if (sockfd < 1)
{
@ -195,37 +207,61 @@ int freerdp_tcp_wait_read(int sockfd)
return 0 ;
}
#ifdef HAVE_POLL_H
pollfds.fd = sockfd;
pollfds.events = POLLIN;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, 5 * 1000);
}
while ((status < 0) && (errno == EINTR));
#else
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
select(sockfd+1, &fds, NULL, NULL, &timeout);
if (!FD_ISSET(sockfd, &fds))
return -1;
status = _select(sockfd+1, &fds, NULL, NULL, &timeout);
#endif
return 0;
return status > 0 ? 1 : 0;
}
int freerdp_tcp_wait_write(int sockfd)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollfds;
#else
fd_set fds;
struct timeval timeout;
#endif
if (sockfd < 1)
{
fprintf(stderr, "Invalid socket to watch: %d\n", sockfd);
return 0;
return 0 ;
}
#ifdef HAVE_POLL_H
pollfds.fd = sockfd;
pollfds.events = POLLOUT;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, 5 * 1000);
}
while ((status < 0) && (errno == EINTR));
#else
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
timeout.tv_sec = 5;
timeout.tv_usec = 0;
select(sockfd+1, NULL, &fds, NULL, &timeout);
if (!FD_ISSET(sockfd, &fds))
return -1;
status = _select(sockfd+1, NULL, &fds, NULL, &timeout);
#endif
return 0;
return status > 0 ? 1 : 0;
}
int freerdp_tcp_disconnect(int sockfd)

View File

@ -12,10 +12,19 @@
# android_setup_build_env.sh <source root>
OPENSSL_SCM=https://github.com/akallabeth/openssl-android.git
OPENSSL_TAG=1.0.1h-fips-2.0.7
NDK_PROFILER_SCM=https://github.com/richq/android-ndk-profiler.git
JPEG_LIBRARY_SCM=https://github.com/akallabeth/jpeg8d.git
SCRIPT_NAME=`basename $0`
SCRIPT_NAME=$(basename $0)
if [ -x $ANDROID_NDK/ndk-build ]; then
NDK_BUILD=$ANDROID_NDK/ndk-build
else
echo "ndk-build not found in NDK directory $ANDROID_NDK"
echo "assuming ndk-build is in path..."
NDK_BUILD=ndk-build
fi
if [ $# -ne 1 ]; then
@ -47,6 +56,10 @@ if [ $RETVAL -ne 0 ]; then
exit -3
fi
cd $OPENSSL_SRC
# We want to build a specific TAG
git checkout $OPENSSL_TAG
make clean
# The makefile has a bug, which aborts during
# first compilation. Rerun make to build the whole lib.
@ -86,11 +99,11 @@ if [ $RETVAL -ne 0 ]; then
exit -5
fi
cd $NDK_PROFILER_SRC
ndk-build V=1 APP_ABI=armeabi-v7a clean
ndk-build V=1 APP_ABI=armeabi-v7a
$NDK_BUILD V=1 APP_ABI=armeabi-v7a clean
$NDK_BUILD V=1 APP_ABI=armeabi-v7a
RETVAL=$?
if [ $RETVAL -ne 0 ]; then
echo "Failed to execute ndk-build command [$RETVAL]"
echo "Failed to execute $NDK_BUILD command [$RETVAL]"
exit -6
fi
@ -109,11 +122,11 @@ if [ $RETVAL -ne 0 ]; then
exit -6
fi
cd $JPEG_LIBRARY_SRC
ndk-build V=1 APP_ABI=armeabi-v7a clean
ndk-build V=1 APP_ABI=armeabi-v7a
$NDK_BUILD V=1 APP_ABI=armeabi-v7a clean
$NDK_BUILD V=1 APP_ABI=armeabi-v7a
RETVAL=$?
if [ $RETVAL -ne 0 ]; then
echo "Failed to execute ndk-build command [$RETVAL]"
echo "Failed to execute $NDK_BUILD command [$RETVAL]"
exit -7
fi
mkdir -p $JPEG_LIBRARY_SRC/lib

589
winpr/include/winpr/comm.h Normal file
View File

@ -0,0 +1,589 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_COMM_H
#define WINPR_COMM_H
#include <winpr/collections.h>
#include <winpr/file.h>
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#if defined __linux__ && !defined ANDROID
#define NOPARITY 0
#define ODDPARITY 1
#define EVENPARITY 2
#define MARKPARITY 3
#define SPACEPARITY 4
#define ONESTOPBIT 0
#define ONE5STOPBITS 1
#define TWOSTOPBITS 2
#ifndef IGNORE
#define IGNORE 0
#endif
#define CBR_110 110
#define CBR_300 300
#define CBR_600 600
#define CBR_1200 1200
#define CBR_2400 2400
#define CBR_4800 4800
#define CBR_9600 9600
#define CBR_14400 14400
#define CBR_19200 19200
#define CBR_38400 38400
#define CBR_56000 56000
#define CBR_57600 57600
#define CBR_115200 115200
#define CBR_128000 128000
#define CBR_256000 256000
#define CE_RXOVER 0x0001
#define CE_OVERRUN 0x0002
#define CE_RXPARITY 0x0004
#define CE_FRAME 0x0008
#define CE_BREAK 0x0010
#define CE_TXFULL 0x0100
#define CE_PTO 0x0200
#define CE_IOE 0x0400
#define CE_DNS 0x0800
#define CE_OOP 0x1000
#define CE_MODE 0x8000
#define IE_BADID (-1)
#define IE_OPEN (-2)
#define IE_NOPEN (-3)
#define IE_MEMORY (-4)
#define IE_DEFAULT (-5)
#define IE_HARDWARE (-10)
#define IE_BYTESIZE (-11)
#define IE_BAUDRATE (-12)
#define EV_RXCHAR 0x0001
#define EV_RXFLAG 0x0002
#define EV_TXEMPTY 0x0004
#define EV_CTS 0x0008
#define EV_DSR 0x0010
#define EV_RLSD 0x0020
#define EV_BREAK 0x0040
#define EV_ERR 0x0080
#define EV_RING 0x0100
#define EV_PERR 0x0200
#define EV_RX80FULL 0x0400
#define EV_EVENT1 0x0800
#define EV_EVENT2 0x1000
#define SETXOFF 1
#define SETXON 2
#define SETRTS 3
#define CLRRTS 4
#define SETDTR 5
#define CLRDTR 6
#define RESETDEV 7
#define SETBREAK 8
#define CLRBREAK 9
#define PURGE_TXABORT 0x0001
#define PURGE_RXABORT 0x0002
#define PURGE_TXCLEAR 0x0004
#define PURGE_RXCLEAR 0x0008
#define LPTx 0x80
#define MS_CTS_ON ((DWORD)0x0010)
#define MS_DSR_ON ((DWORD)0x0020)
#define MS_RING_ON ((DWORD)0x0040)
#define MS_RLSD_ON ((DWORD)0x0080)
#define SP_SERIALCOMM ((DWORD)0x00000001)
#define PST_UNSPECIFIED ((DWORD)0x00000000)
#define PST_RS232 ((DWORD)0x00000001)
#define PST_PARALLELPORT ((DWORD)0x00000002)
#define PST_RS422 ((DWORD)0x00000003)
#define PST_RS423 ((DWORD)0x00000004)
#define PST_RS449 ((DWORD)0x00000005)
#define PST_MODEM ((DWORD)0x00000006)
#define PST_FAX ((DWORD)0x00000021)
#define PST_SCANNER ((DWORD)0x00000022)
#define PST_NETWORK_BRIDGE ((DWORD)0x00000100)
#define PST_LAT ((DWORD)0x00000101)
#define PST_TCPIP_TELNET ((DWORD)0x00000102)
#define PST_X25 ((DWORD)0x00000103)
#define PCF_DTRDSR ((DWORD)0x0001)
#define PCF_RTSCTS ((DWORD)0x0002)
#define PCF_RLSD ((DWORD)0x0004)
#define PCF_PARITY_CHECK ((DWORD)0x0008)
#define PCF_XONXOFF ((DWORD)0x0010)
#define PCF_SETXCHAR ((DWORD)0x0020)
#define PCF_TOTALTIMEOUTS ((DWORD)0x0040)
#define PCF_INTTIMEOUTS ((DWORD)0x0080)
#define PCF_SPECIALCHARS ((DWORD)0x0100)
#define PCF_16BITMODE ((DWORD)0x0200)
#define SP_PARITY ((DWORD)0x0001)
#define SP_BAUD ((DWORD)0x0002)
#define SP_DATABITS ((DWORD)0x0004)
#define SP_STOPBITS ((DWORD)0x0008)
#define SP_HANDSHAKING ((DWORD)0x0010)
#define SP_PARITY_CHECK ((DWORD)0x0020)
#define SP_RLSD ((DWORD)0x0040)
#define BAUD_075 ((DWORD)0x00000001)
#define BAUD_110 ((DWORD)0x00000002)
#define BAUD_134_5 ((DWORD)0x00000004)
#define BAUD_150 ((DWORD)0x00000008)
#define BAUD_300 ((DWORD)0x00000010)
#define BAUD_600 ((DWORD)0x00000020)
#define BAUD_1200 ((DWORD)0x00000040)
#define BAUD_1800 ((DWORD)0x00000080)
#define BAUD_2400 ((DWORD)0x00000100)
#define BAUD_4800 ((DWORD)0x00000200)
#define BAUD_7200 ((DWORD)0x00000400)
#define BAUD_9600 ((DWORD)0x00000800)
#define BAUD_14400 ((DWORD)0x00001000)
#define BAUD_19200 ((DWORD)0x00002000)
#define BAUD_38400 ((DWORD)0x00004000)
#define BAUD_56K ((DWORD)0x00008000)
#define BAUD_128K ((DWORD)0x00010000)
#define BAUD_115200 ((DWORD)0x00020000)
#define BAUD_57600 ((DWORD)0x00040000)
#define BAUD_USER ((DWORD)0x10000000)
/* Ntddser.h: http://msdn.microsoft.com/en-us/cc308432.aspx */
#define SERIAL_BAUD_075 ((ULONG)0x00000001)
#define SERIAL_BAUD_110 ((ULONG)0x00000002)
#define SERIAL_BAUD_134_5 ((ULONG)0x00000004)
#define SERIAL_BAUD_150 ((ULONG)0x00000008)
#define SERIAL_BAUD_300 ((ULONG)0x00000010)
#define SERIAL_BAUD_600 ((ULONG)0x00000020)
#define SERIAL_BAUD_1200 ((ULONG)0x00000040)
#define SERIAL_BAUD_1800 ((ULONG)0x00000080)
#define SERIAL_BAUD_2400 ((ULONG)0x00000100)
#define SERIAL_BAUD_4800 ((ULONG)0x00000200)
#define SERIAL_BAUD_7200 ((ULONG)0x00000400)
#define SERIAL_BAUD_9600 ((ULONG)0x00000800)
#define SERIAL_BAUD_14400 ((ULONG)0x00001000)
#define SERIAL_BAUD_19200 ((ULONG)0x00002000)
#define SERIAL_BAUD_38400 ((ULONG)0x00004000)
#define SERIAL_BAUD_56K ((ULONG)0x00008000)
#define SERIAL_BAUD_128K ((ULONG)0x00010000)
#define SERIAL_BAUD_115200 ((ULONG)0x00020000)
#define SERIAL_BAUD_57600 ((ULONG)0x00040000)
#define SERIAL_BAUD_USER ((ULONG)0x10000000)
#define DATABITS_5 ((WORD)0x0001)
#define DATABITS_6 ((WORD)0x0002)
#define DATABITS_7 ((WORD)0x0004)
#define DATABITS_8 ((WORD)0x0008)
#define DATABITS_16 ((WORD)0x0010)
#define DATABITS_16X ((WORD)0x0020)
#define STOPBITS_10 ((WORD)0x0001)
#define STOPBITS_15 ((WORD)0x0002)
#define STOPBITS_20 ((WORD)0x0004)
#define PARITY_NONE ((WORD)0x0100)
#define PARITY_ODD ((WORD)0x0200)
#define PARITY_EVEN ((WORD)0x0400)
#define PARITY_MARK ((WORD)0x0800)
#define PARITY_SPACE ((WORD)0x1000)
#define COMMPROP_INITIALIZED ((DWORD)0xE73CF52E)
#define DTR_CONTROL_DISABLE 0x00
#define DTR_CONTROL_ENABLE 0x01
#define DTR_CONTROL_HANDSHAKE 0x02
#define RTS_CONTROL_DISABLE 0x00
#define RTS_CONTROL_ENABLE 0x01
#define RTS_CONTROL_HANDSHAKE 0x02
#define RTS_CONTROL_TOGGLE 0x03
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214%28v=vs.85%29.aspx
typedef struct _DCB
{
DWORD DCBlength;
DWORD BaudRate;
DWORD fBinary:1;
DWORD fParity:1;
DWORD fOutxCtsFlow:1;
DWORD fOutxDsrFlow:1;
DWORD fDtrControl:2;
DWORD fDsrSensitivity:1;
DWORD fTXContinueOnXoff:1;
DWORD fOutX:1;
DWORD fInX:1;
DWORD fErrorChar:1;
DWORD fNull:1;
DWORD fRtsControl:2;
DWORD fAbortOnError:1;
DWORD fDummy2:17;
WORD wReserved;
WORD XonLim;
WORD XoffLim;
BYTE ByteSize;
BYTE Parity;
BYTE StopBits;
char XonChar;
char XoffChar;
char ErrorChar;
char EofChar;
char EvtChar;
WORD wReserved1;
} DCB, *LPDCB;
typedef struct _COMM_CONFIG
{
DWORD dwSize;
WORD wVersion;
WORD wReserved;
DCB dcb;
DWORD dwProviderSubType;
DWORD dwProviderOffset;
DWORD dwProviderSize;
WCHAR wcProviderData[1];
} COMMCONFIG, *LPCOMMCONFIG;
typedef struct _COMMPROP
{
WORD wPacketLength;
WORD wPacketVersion;
DWORD dwServiceMask;
DWORD dwReserved1;
DWORD dwMaxTxQueue;
DWORD dwMaxRxQueue;
DWORD dwMaxBaud;
DWORD dwProvSubType;
DWORD dwProvCapabilities;
DWORD dwSettableParams;
DWORD dwSettableBaud;
WORD wSettableData;
WORD wSettableStopParity;
DWORD dwCurrentTxQueue;
DWORD dwCurrentRxQueue;
DWORD dwProvSpec1;
DWORD dwProvSpec2;
WCHAR wcProvChar[1];
} COMMPROP, *LPCOMMPROP;
typedef struct _COMMTIMEOUTS
{
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} COMMTIMEOUTS, *LPCOMMTIMEOUTS;
typedef struct _COMSTAT
{
DWORD fCtsHold:1;
DWORD fDsrHold:1;
DWORD fRlsdHold:1;
DWORD fXoffHold:1;
DWORD fXoffSent:1;
DWORD fEof:1;
DWORD fTxim:1;
DWORD fReserved:25;
DWORD cbInQue;
DWORD cbOutQue;
} COMSTAT, *LPCOMSTAT;
#ifdef __cplusplus
extern "C" {
#endif
WINPR_API BOOL BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB);
WINPR_API BOOL BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB);
WINPR_API BOOL BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts);
WINPR_API BOOL BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts);
WINPR_API BOOL CommConfigDialogA(LPCSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC);
WINPR_API BOOL CommConfigDialogW(LPCWSTR lpszName, HWND hWnd, LPCOMMCONFIG lpCC);
WINPR_API BOOL GetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, LPDWORD lpdwSize);
WINPR_API BOOL SetCommConfig(HANDLE hCommDev, LPCOMMCONFIG lpCC, DWORD dwSize);
WINPR_API BOOL GetCommMask(HANDLE hFile, PDWORD lpEvtMask);
WINPR_API BOOL SetCommMask(HANDLE hFile, DWORD dwEvtMask);
WINPR_API BOOL GetCommModemStatus(HANDLE hFile, PDWORD lpModemStat);
WINPR_API BOOL GetCommProperties(HANDLE hFile, LPCOMMPROP lpCommProp);
WINPR_API BOOL GetCommState(HANDLE hFile, LPDCB lpDCB);
WINPR_API BOOL SetCommState(HANDLE hFile, LPDCB lpDCB);
WINPR_API BOOL GetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
WINPR_API BOOL SetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
WINPR_API BOOL GetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize);
WINPR_API BOOL GetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, LPDWORD lpdwSize);
WINPR_API BOOL SetDefaultCommConfigA(LPCSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize);
WINPR_API BOOL SetDefaultCommConfigW(LPCWSTR lpszName, LPCOMMCONFIG lpCC, DWORD dwSize);
WINPR_API BOOL SetCommBreak(HANDLE hFile);
WINPR_API BOOL ClearCommBreak(HANDLE hFile);
WINPR_API BOOL ClearCommError(HANDLE hFile, PDWORD lpErrors, LPCOMSTAT lpStat);
WINPR_API BOOL PurgeComm(HANDLE hFile, DWORD dwFlags);
WINPR_API BOOL SetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
WINPR_API BOOL EscapeCommFunction(HANDLE hFile, DWORD dwFunc);
WINPR_API BOOL TransmitCommChar(HANDLE hFile, char cChar);
WINPR_API BOOL WaitCommEvent(HANDLE hFile, PDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
#ifdef UNICODE
#define BuildCommDCB BuildCommDCBW
#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsW
#define CommConfigDialog CommConfigDialogW
#define GetDefaultCommConfig GetDefaultCommConfigW
#define SetDefaultCommConfig SetDefaultCommConfigW
#else
#define BuildCommDCB BuildCommDCBA
#define BuildCommDCBAndTimeouts BuildCommDCBAndTimeoutsA
#define CommConfigDialog CommConfigDialogA
#define GetDefaultCommConfig GetDefaultCommConfigA
#define SetDefaultCommConfig SetDefaultCommConfigA
#endif
/* Extended API */
/* FIXME: MAXULONG should be defined arround winpr/limits.h */
#ifndef MAXULONG
#define MAXULONG (4294967295UL)
#endif
/**
* IOCTLs table according the server's serial driver:
* http://msdn.microsoft.com/en-us/library/windows/hardware/dn265347%28v=vs.85%29.aspx
*/
typedef enum _SERIAL_DRIVER_ID
{
SerialDriverUnknown = 0,
SerialDriverSerialSys,
SerialDriverSerCxSys,
SerialDriverSerCx2Sys /* default fallback, see also CommDeviceIoControl() */
} SERIAL_DRIVER_ID;
/*
* About DefineCommDevice() / QueryDosDevice()
*
* Did something close to QueryDosDevice() and DefineDosDevice() but with
* folowing constraints:
* - mappings are stored in a static array.
* - QueryCommDevice returns only the mappings that have been defined through DefineCommDevice()
*/
WINPR_API BOOL DefineCommDevice(/* DWORD dwFlags,*/ LPCTSTR lpDeviceName, LPCTSTR lpTargetPath);
WINPR_API DWORD QueryCommDevice(LPCTSTR lpDeviceName, LPTSTR lpTargetPath, DWORD ucchMax);
WINPR_API BOOL IsCommDevice(LPCTSTR lpDeviceName);
/**
* A handle can only be created on defined devices with DefineCommDevice(). This
* also ensures that CommCreateFileA() has been registered through
* RegisterHandleCreator().
*/
WINPR_API HANDLE CommCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
#define IOCTL_SERIAL_SET_BAUD_RATE 0x001B0004
#define IOCTL_SERIAL_GET_BAUD_RATE 0x001B0050
#define IOCTL_SERIAL_SET_LINE_CONTROL 0x001B000C
#define IOCTL_SERIAL_GET_LINE_CONTROL 0x001B0054
#define IOCTL_SERIAL_SET_TIMEOUTS 0x001B001C
#define IOCTL_SERIAL_GET_TIMEOUTS 0x001B0020
/* GET_CHARS and SET_CHARS are swapped in the RDP docs [MS-RDPESP] */
#define IOCTL_SERIAL_GET_CHARS 0x001B0058
#define IOCTL_SERIAL_SET_CHARS 0x001B005C
#define IOCTL_SERIAL_SET_DTR 0x001B0024
#define IOCTL_SERIAL_CLR_DTR 0x001B0028
#define IOCTL_SERIAL_RESET_DEVICE 0x001B002C
#define IOCTL_SERIAL_SET_RTS 0x001B0030
#define IOCTL_SERIAL_CLR_RTS 0x001B0034
#define IOCTL_SERIAL_SET_XOFF 0x001B0038
#define IOCTL_SERIAL_SET_XON 0x001B003C
#define IOCTL_SERIAL_SET_BREAK_ON 0x001B0010
#define IOCTL_SERIAL_SET_BREAK_OFF 0x001B0014
#define IOCTL_SERIAL_SET_QUEUE_SIZE 0x001B0008
#define IOCTL_SERIAL_GET_WAIT_MASK 0x001B0040
#define IOCTL_SERIAL_SET_WAIT_MASK 0x001B0044
#define IOCTL_SERIAL_WAIT_ON_MASK 0x001B0048
#define IOCTL_SERIAL_IMMEDIATE_CHAR 0x001B0018
#define IOCTL_SERIAL_PURGE 0x001B004C
#define IOCTL_SERIAL_GET_HANDFLOW 0x001B0060
#define IOCTL_SERIAL_SET_HANDFLOW 0x001B0064
#define IOCTL_SERIAL_GET_MODEMSTATUS 0x001B0068
#define IOCTL_SERIAL_GET_DTRRTS 0x001B0078
/* according to [MS-RDPESP] it should be 0x001B0084, but servers send 0x001B006C */
#define IOCTL_SERIAL_GET_COMMSTATUS 0x001B006C
#define IOCTL_SERIAL_GET_PROPERTIES 0x001B0074
/* IOCTL_SERIAL_XOFF_COUNTER 0x001B0070 */
/* IOCTL_SERIAL_LSRMST_INSERT 0x001B007C */
#define IOCTL_SERIAL_CONFIG_SIZE 0x001B0080
/* IOCTL_SERIAL_GET_STATS 0x001B008C */
/* IOCTL_SERIAL_CLEAR_STATS 0x001B0090 */
/* IOCTL_SERIAL_GET_MODEM_CONTROL 0x001B0094 */
/* IOCTL_SERIAL_SET_MODEM_CONTROL 0x001B0098 */
/* IOCTL_SERIAL_SET_FIFO_CONTROL 0x001B009C */
/* IOCTL_PAR_QUERY_INFORMATION 0x00160004 */
/* IOCTL_PAR_SET_INFORMATION 0x00160008 */
/* IOCTL_PAR_QUERY_DEVICE_ID 0x0016000C */
/* IOCTL_PAR_QUERY_DEVICE_ID_SIZE 0x00160010 */
/* IOCTL_IEEE1284_GET_MODE 0x00160014 */
/* IOCTL_IEEE1284_NEGOTIATE 0x00160018 */
/* IOCTL_PAR_SET_WRITE_ADDRESS 0x0016001C */
/* IOCTL_PAR_SET_READ_ADDRESS 0x00160020 */
/* IOCTL_PAR_GET_DEVICE_CAPS 0x00160024 */
/* IOCTL_PAR_GET_DEFAULT_MODES 0x00160028 */
/* IOCTL_PAR_QUERY_RAW_DEVICE_ID 0x00160030 */
/* IOCTL_PAR_IS_PORT_FREE 0x00160054 */
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */
#define IOCTL_USBPRINT_GET_1284_ID 0x220034
typedef struct __SERIAL_IOCTL_NAME
{
ULONG number;
const char* name;
} _SERIAL_IOCTL_NAME;
static const _SERIAL_IOCTL_NAME _SERIAL_IOCTL_NAMES[] =
{
{IOCTL_SERIAL_SET_BAUD_RATE, "IOCTL_SERIAL_SET_BAUD_RATE"},
{IOCTL_SERIAL_GET_BAUD_RATE, "IOCTL_SERIAL_GET_BAUD_RATE"},
{IOCTL_SERIAL_SET_LINE_CONTROL, "IOCTL_SERIAL_SET_LINE_CONTROL"},
{IOCTL_SERIAL_GET_LINE_CONTROL, "IOCTL_SERIAL_GET_LINE_CONTROL"},
{IOCTL_SERIAL_SET_TIMEOUTS, "IOCTL_SERIAL_SET_TIMEOUTS"},
{IOCTL_SERIAL_GET_TIMEOUTS, "IOCTL_SERIAL_GET_TIMEOUTS"},
{IOCTL_SERIAL_GET_CHARS, "IOCTL_SERIAL_GET_CHARS"},
{IOCTL_SERIAL_SET_CHARS, "IOCTL_SERIAL_SET_CHARS"},
{IOCTL_SERIAL_SET_DTR, "IOCTL_SERIAL_SET_DTR"},
{IOCTL_SERIAL_CLR_DTR, "IOCTL_SERIAL_CLR_DTR"},
{IOCTL_SERIAL_RESET_DEVICE, "IOCTL_SERIAL_RESET_DEVICE"},
{IOCTL_SERIAL_SET_RTS, "IOCTL_SERIAL_SET_RTS"},
{IOCTL_SERIAL_CLR_RTS, "IOCTL_SERIAL_CLR_RTS"},
{IOCTL_SERIAL_SET_XOFF, "IOCTL_SERIAL_SET_XOFF"},
{IOCTL_SERIAL_SET_XON, "IOCTL_SERIAL_SET_XON"},
{IOCTL_SERIAL_SET_BREAK_ON, "IOCTL_SERIAL_SET_BREAK_ON"},
{IOCTL_SERIAL_SET_BREAK_OFF, "IOCTL_SERIAL_SET_BREAK_OFF"},
{IOCTL_SERIAL_SET_QUEUE_SIZE, "IOCTL_SERIAL_SET_QUEUE_SIZE"},
{IOCTL_SERIAL_GET_WAIT_MASK, "IOCTL_SERIAL_GET_WAIT_MASK"},
{IOCTL_SERIAL_SET_WAIT_MASK, "IOCTL_SERIAL_SET_WAIT_MASK"},
{IOCTL_SERIAL_WAIT_ON_MASK, "IOCTL_SERIAL_WAIT_ON_MASK"},
{IOCTL_SERIAL_IMMEDIATE_CHAR, "IOCTL_SERIAL_IMMEDIATE_CHAR"},
{IOCTL_SERIAL_PURGE, "IOCTL_SERIAL_PURGE"},
{IOCTL_SERIAL_GET_HANDFLOW, "IOCTL_SERIAL_GET_HANDFLOW"},
{IOCTL_SERIAL_SET_HANDFLOW, "IOCTL_SERIAL_SET_HANDFLOW"},
{IOCTL_SERIAL_GET_MODEMSTATUS, "IOCTL_SERIAL_GET_MODEMSTATUS"},
{IOCTL_SERIAL_GET_DTRRTS, "IOCTL_SERIAL_GET_DTRRTS"},
{IOCTL_SERIAL_GET_COMMSTATUS, "IOCTL_SERIAL_GET_COMMSTATUS"},
{IOCTL_SERIAL_GET_PROPERTIES, "IOCTL_SERIAL_GET_PROPERTIES"},
// {IOCTL_SERIAL_XOFF_COUNTER, "IOCTL_SERIAL_XOFF_COUNTER"},
// {IOCTL_SERIAL_LSRMST_INSERT, "IOCTL_SERIAL_LSRMST_INSERT"},
{IOCTL_SERIAL_CONFIG_SIZE, "IOCTL_SERIAL_CONFIG_SIZE"},
// {IOCTL_SERIAL_GET_STATS, "IOCTL_SERIAL_GET_STATS"},
// {IOCTL_SERIAL_CLEAR_STATS, "IOCTL_SERIAL_CLEAR_STATS"},
// {IOCTL_SERIAL_GET_MODEM_CONTROL,"IOCTL_SERIAL_GET_MODEM_CONTROL"},
// {IOCTL_SERIAL_SET_MODEM_CONTROL,"IOCTL_SERIAL_SET_MODEM_CONTROL"},
// {IOCTL_SERIAL_SET_FIFO_CONTROL, "IOCTL_SERIAL_SET_FIFO_CONTROL"},
// {IOCTL_PAR_QUERY_INFORMATION, "IOCTL_PAR_QUERY_INFORMATION"},
// {IOCTL_PAR_SET_INFORMATION, "IOCTL_PAR_SET_INFORMATION"},
// {IOCTL_PAR_QUERY_DEVICE_ID, "IOCTL_PAR_QUERY_DEVICE_ID"},
// {IOCTL_PAR_QUERY_DEVICE_ID_SIZE,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE"},
// {IOCTL_IEEE1284_GET_MODE, "IOCTL_IEEE1284_GET_MODE"},
// {IOCTL_IEEE1284_NEGOTIATE, "IOCTL_IEEE1284_NEGOTIATE"},
// {IOCTL_PAR_SET_WRITE_ADDRESS, "IOCTL_PAR_SET_WRITE_ADDRESS"},
// {IOCTL_PAR_SET_READ_ADDRESS, "IOCTL_PAR_SET_READ_ADDRESS"},
// {IOCTL_PAR_GET_DEVICE_CAPS, "IOCTL_PAR_GET_DEVICE_CAPS"},
// {IOCTL_PAR_GET_DEFAULT_MODES, "IOCTL_PAR_GET_DEFAULT_MODES"},
// {IOCTL_PAR_QUERY_RAW_DEVICE_ID, "IOCTL_PAR_QUERY_RAW_DEVICE_ID"},
// {IOCTL_PAR_IS_PORT_FREE, "IOCTL_PAR_IS_PORT_FREE"},
{IOCTL_USBPRINT_GET_1284_ID, "IOCTL_USBPRINT_GET_1284_ID"},
{0, NULL}
};
/**
* FIXME: got a proper function name and place
*/
const char* _comm_serial_ioctl_name(ULONG number);
/**
* FIXME: got a proper function name and place
*/
void _comm_setServerSerialDriver(HANDLE hComm, SERIAL_DRIVER_ID);
/**
* FIXME: got a proper function name and place
*
* permissive mode is disabled by default.
*/
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive);
/**
* FIXME: to be moved in comm_ioctl.h
*/
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
/**
* FIXME: to be moved in comm_io.h
*/
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
/**
* FIXME: to be moved in comm_io.h
*/
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
#ifdef __cplusplus
}
#endif
#endif /* __linux__ */
#endif /* WINPR_COMM_H */

View File

@ -311,10 +311,23 @@ WINPR_API BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecu
#define CreateDirectory CreateDirectoryA
#endif
#endif
/* Extra Functions */
typedef BOOL (*pcIsFileHandled)(LPCSTR lpFileName);
typedef HANDLE (*pcCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
typedef struct _HANDLE_CREATOR
{
pcIsFileHandled IsHandled;
pcCreateFileA CreateFileA;
} HANDLE_CREATOR, *PHANDLE_CREATOR, *LPHANDLE_CREATOR;
BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator);
#endif /* _WIN32 */
#define WILDCARD_STAR 0x00000001
#define WILDCARD_QM 0x00000002
#define WILDCARD_DOS 0x00000100
@ -331,6 +344,7 @@ WINPR_API LPSTR FilePatternFindNextWildcardA(LPCSTR lpPattern, DWORD* pFlags);
WINPR_API int UnixChangeFileMode(const char* filename, int flags);
WINPR_API BOOL IsNamedPipeFileNameA(LPCSTR lpName);
WINPR_API char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName);
WINPR_API char* GetNamedPipeUnixDomainSocketBaseFilePathA(void);
WINPR_API char* GetNamedPipeUnixDomainSocketFilePathA(LPCSTR lpName);
@ -342,4 +356,3 @@ WINPR_API int GetNamePipeFileDescriptor(HANDLE hNamedPipe);
#endif
#endif /* WINPR_FILE_H */

View File

@ -40,6 +40,7 @@ typedef CHAR TCHAR;
#define _tcslen _wcslen
#define _tcsdup _wcsdup
#define _tcscmp wcscmp
#define _tcsncmp wcsncmp
#define _tcscpy wcscpy
#define _tcscat wcscat
#define _tcschr wcschr
@ -51,6 +52,7 @@ typedef CHAR TCHAR;
#define _tcslen strlen
#define _tcsdup _strdup
#define _tcscmp strcmp
#define _tcsncmp strncmp
#define _tcscpy strcpy
#define _tcscat strcat
#define _tcschr strchr

View File

@ -25,6 +25,7 @@ extern "C" {
#endif
#include <stdio.h>
#include <stdarg.h>
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
@ -210,6 +211,7 @@ struct _wLog
};
WINPR_API void WLog_PrintMessage(wLog* log, wLogMessage* message, ...);
WINPR_API int WLog_PrintMessageVA(wLog* log, wLogMessage* message, va_list args);
#define WLog_Print(_log, _log_level, _fmt, ...) \
if (_log_level >= WLog_GetLogLevel(_log)) { \
@ -223,6 +225,18 @@ WINPR_API void WLog_PrintMessage(wLog* log, wLogMessage* message, ...);
WLog_PrintMessage(_log, &(_log_message), ## __VA_ARGS__ ); \
}
#define WLog_PrintVA(_log, _log_level, _fmt, _args) \
if (_log_level >= WLog_GetLogLevel(_log)) { \
wLogMessage _log_message; \
_log_message.Type = WLOG_MESSAGE_TEXT; \
_log_message.Level = _log_level; \
_log_message.FormatString = _fmt; \
_log_message.LineNumber = __LINE__; \
_log_message.FileName = __FILE__; \
_log_message.FunctionName = __FUNCTION__; \
WLog_PrintMessageVA(_log, &(_log_message), _args); \
}
#define WLog_Data(_log, _log_level, ...) \
if (_log_level >= WLog_GetLogLevel(_log)) { \
wLogMessage _log_message; \

View File

@ -0,0 +1,61 @@
# WinPR: Windows Portable Runtime
# libwinpr-comm cmake build script
#
# Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set(MODULE_NAME "winpr-comm")
set(MODULE_PREFIX "WINPR_COMM")
set(${MODULE_PREFIX}_SRCS
comm.c
comm.h
comm_io.c
comm_ioctl.c
comm_ioctl.h
comm_serial_sys.c
comm_serial_sys.h
comm_sercx_sys.c
comm_sercx_sys.h
comm_sercx2_sys.c
comm_sercx2_sys.h)
if(MSVC AND (NOT MONOLITHIC_BUILD))
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
endif()
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
MONOLITHIC ${MONOLITHIC_BUILD}
SOURCES ${${MODULE_PREFIX}_SRCS})
set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SOVERSION ${WINPR_VERSION} PREFIX "lib")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
MODULE winpr
MODULES winpr-crt winpr-file winpr-utils)
if(MONOLITHIC_BUILD)
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
else()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets)
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,9 @@
set(MINWIN_LAYER "1")
set(MINWIN_GROUP "core")
set(MINWIN_MAJOR_VERSION "1")
set(MINWIN_MINOR_VERSION "0")
set(MINWIN_SHORT_NAME "comm")
set(MINWIN_LONG_NAME "Serial Communication API")
set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}")

1499
winpr/libwinpr/comm/comm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,97 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_COMM_PRIVATE_H
#define WINPR_COMM_PRIVATE_H
#if defined __linux__ && !defined ANDROID
#include <linux/serial.h>
#include <sys/eventfd.h>
#include <winpr/comm.h>
#include "../handle/handle.h"
struct winpr_comm
{
WINPR_HANDLE_DEF();
int fd;
int fd_read;
int fd_read_event; /* as of today, only used by _purge() */
CRITICAL_SECTION ReadLock;
int fd_write;
int fd_write_event; /* as of today, only used by _purge() */
CRITICAL_SECTION WriteLock;
/* permissive mode on errors if TRUE (default is FALSE).
*
* Since not all features are supported, some devices and applications
* can still be functional on such errors.
*
* TODO: command line switch or getting rid of it.
*/
BOOL permissive;
SERIAL_DRIVER_ID serverSerialDriverId;
COMMTIMEOUTS timeouts;
CRITICAL_SECTION EventsLock; /* protects counters, WaitEventMask and PendingEvents */
struct serial_icounter_struct counters;
ULONG WaitEventMask;
ULONG PendingEvents;
/* NB: CloseHandle() has to free resources */
};
typedef struct winpr_comm WINPR_COMM;
#define SERIAL_EV_RXCHAR 0x0001
#define SERIAL_EV_RXFLAG 0x0002
#define SERIAL_EV_TXEMPTY 0x0004
#define SERIAL_EV_CTS 0x0008
#define SERIAL_EV_DSR 0x0010
#define SERIAL_EV_RLSD 0x0020
#define SERIAL_EV_BREAK 0x0040
#define SERIAL_EV_ERR 0x0080
#define SERIAL_EV_RING 0x0100
#define SERIAL_EV_PERR 0x0200
#define SERIAL_EV_RX80FULL 0x0400
#define SERIAL_EV_EVENT1 0x0800
#define SERIAL_EV_EVENT2 0x1000
#define SERIAL_EV_FREERDP_WAITING 0x4000 /* bit today unused by other SERIAL_EV_* */
#define SERIAL_EV_FREERDP_STOP 0x8000 /* bit today unused by other SERIAL_EV_* */
#define FREERDP_PURGE_TXABORT 0x00000001 /* abort pending transmission */
#define FREERDP_PURGE_RXABORT 0x00000002 /* abort pending reception */
void CommLog_Print(int wlog_level, char *fmt, ...);
BOOL CommIsHandled(HANDLE handle);
BOOL CommCloseHandle(HANDLE handle);
#endif /* __linux__ */
#endif /* WINPR_COMM_PRIVATE_H */

View File

@ -0,0 +1,550 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined __linux__ && !defined ANDROID
#include <assert.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <winpr/io.h>
#include <winpr/wlog.h>
#include <winpr/wtypes.h>
#include "comm.h"
BOOL _comm_set_permissive(HANDLE hDevice, BOOL permissive)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
pComm->permissive = permissive;
return TRUE;
}
/* Computes VMIN in deciseconds from Ti in milliseconds */
static UCHAR _vtime(ULONG Ti)
{
/* FIXME: look for an equivalent math function otherwise let
* do the compiler do the optimization */
if (Ti == 0)
return 0;
else if (Ti < 100)
return 1;
else if (Ti > 25500)
return 255; /* 0xFF */
else
return Ti/100;
}
/**
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_NOT_SUPPORTED
* ERROR_INVALID_PARAMETER
* ERROR_TIMEOUT
* ERROR_IO_DEVICE
* ERROR_BAD_DEVICE
*/
BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
int biggestFd = -1;
fd_set read_set;
int nbFds;
COMMTIMEOUTS *pTimeouts;
UCHAR vmin = 0;
UCHAR vtime = 0;
ULONGLONG Tmax = 0;
struct timeval tmaxTimeout, *pTmaxTimeout;
struct termios currentTermios;
EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
goto return_false;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
goto return_false;
}
if (lpOverlapped != NULL)
{
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
if (lpNumberOfBytesRead == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */
goto return_false;
}
*lpNumberOfBytesRead = 0; /* will be ajusted if required ... */
if (nNumberOfBytesToRead <= 0) /* N */
{
goto return_true; /* FIXME: or FALSE? */
}
if (tcgetattr(pComm->fd, &currentTermios) < 0)
{
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (currentTermios.c_lflag & ICANON)
{
CommLog_Print(WLOG_WARN, "Canonical mode not supported"); /* the timeout could not be set */
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
/* http://msdn.microsoft.com/en-us/library/hh439614%28v=vs.85%29.aspx
* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
*
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME | TMAX |
* 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | 0 | Block on first byte, then use Ti between bytes.
* MAXULONG | 0 | 0 | 0 | 0 | 0 | Returns immediately with bytes available (don't block)
* MAXULONG | MAXULONG | 0< Tc <MAXULONG | N | 0 | Tc | Blocks on first byte during Tc or returns immediately whith bytes available
* MAXULONG | m | MAXULONG | | Invalid
* 0 | m | 0< Tc <MAXULONG | N | 0 | Tmax | Block on first byte during Tmax or returns immediately whith bytes available
* 0< Ti <MAXULONG | m | 0< Tc <MAXULONG | N | Ti | Tmax | Block on first byte, then use Ti between bytes. Tmax is use for the whole system call.
*/
/* NB: timeouts are in milliseconds, VTIME are in deciseconds and is an unsigned char */
/* FIXME: double check whether open(pComm->fd_read_event, O_NONBLOCK) doesn't conflict with above use cases */
pTimeouts = &(pComm->timeouts);
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutConstant == MAXULONG))
{
CommLog_Print(WLOG_WARN, "ReadIntervalTimeout and ReadTotalTimeoutConstant cannot be both set to MAXULONG");
SetLastError(ERROR_INVALID_PARAMETER);
goto return_false;
}
/* VMIN */
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0) && (pTimeouts->ReadTotalTimeoutConstant == 0))
{
vmin = 0;
}
else
{
/* N */
/* vmin = nNumberOfBytesToRead < 256 ? nNumberOfBytesToRead : 255;*/ /* 0xFF */
/* NB: we might wait endlessly with vmin=N, prefer to
* force vmin=1 and return with bytes
* available. FIXME: is a feature disarded here? */
vmin = 1;
}
/* VTIME */
if ((pTimeouts->ReadIntervalTimeout > 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG))
{
/* Ti */
vtime = _vtime(pTimeouts->ReadIntervalTimeout);
}
/* TMAX */
if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG))
{
/* Tc */
Tmax = pTimeouts->ReadTotalTimeoutConstant;
}
else
{
/* Tmax */
Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant;
}
if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime))
{
currentTermios.c_cc[VMIN] = vmin;
currentTermios.c_cc[VTIME] = vtime;
if (tcsetattr(pComm->fd, TCSANOW, &currentTermios) < 0)
{
CommLog_Print(WLOG_WARN, "CommReadFile failure, could not apply new timeout values: VMIN=%u, VTIME=%u", vmin, vtime);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */
if (Tmax > 0)
{
ZeroMemory(&tmaxTimeout, sizeof(struct timeval));
tmaxTimeout.tv_sec = Tmax / 1000; /* s */
tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */
pTmaxTimeout = &tmaxTimeout;
}
/* FIXME: had expected eventfd_write() to return EAGAIN when
* there is no eventfd_read() but this not the case. */
/* discard a possible and no more relevant event */
eventfd_read(pComm->fd_read_event, NULL);
biggestFd = pComm->fd_read;
if (pComm->fd_read_event > biggestFd)
biggestFd = pComm->fd_read_event;
FD_ZERO(&read_set);
assert(pComm->fd_read_event < FD_SETSIZE);
assert(pComm->fd_read < FD_SETSIZE);
FD_SET(pComm->fd_read_event, &read_set);
FD_SET(pComm->fd_read, &read_set);
nbFds = select(biggestFd+1, &read_set, NULL, NULL, pTmaxTimeout);
if (nbFds < 0)
{
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (nbFds == 0)
{
/* timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
/* read_set */
if (FD_ISSET(pComm->fd_read_event, &read_set))
{
eventfd_t event = 0;
if (eventfd_read(pComm->fd_read_event, &event) < 0)
{
if (errno == EAGAIN)
{
assert(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
CommLog_Print(WLOG_WARN, "unexpected error on reading fd_read_event, errno=[%d] %s\n", errno, strerror(errno));
/* FIXME: goto return_false ? */
}
assert(errno == EAGAIN);
}
if (event == FREERDP_PURGE_RXABORT)
{
SetLastError(ERROR_CANCELLED);
goto return_false;
}
assert(event == FREERDP_PURGE_RXABORT); /* no other expected event so far */
}
if (FD_ISSET(pComm->fd_read, &read_set))
{
ssize_t nbRead = 0;
nbRead = read(pComm->fd_read, lpBuffer, nNumberOfBytesToRead);
if (nbRead < 0)
{
CommLog_Print(WLOG_WARN, "CommReadFile failed, ReadIntervalTimeout=%lu, ReadTotalTimeoutMultiplier=%lu, ReadTotalTimeoutConstant=%lu VMIN=%u, VTIME=%u",
pTimeouts->ReadIntervalTimeout, pTimeouts->ReadTotalTimeoutMultiplier, pTimeouts->ReadTotalTimeoutConstant,
currentTermios.c_cc[VMIN], currentTermios.c_cc[VTIME]);
CommLog_Print(WLOG_WARN, "CommReadFile failed, nNumberOfBytesToRead=%lu, errno=[%d] %s", nNumberOfBytesToRead, errno, strerror(errno));
if (errno == EAGAIN)
{
/* keep on */
goto return_true; /* expect a read-loop to be implemented on the server side */
}
else if (errno == EBADF)
{
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
goto return_false;
}
else
{
assert(FALSE);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
if (nbRead == 0)
{
/* termios timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
*lpNumberOfBytesRead = nbRead;
goto return_true;
}
assert(FALSE);
*lpNumberOfBytesRead = 0;
return_false:
LeaveCriticalSection(&pComm->ReadLock);
return FALSE;
return_true:
LeaveCriticalSection(&pComm->ReadLock);
return TRUE;
}
/**
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_NOT_SUPPORTED
* ERROR_INVALID_PARAMETER
* ERROR_BAD_DEVICE
*/
BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
struct timeval tmaxTimeout, *pTmaxTimeout;
EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
goto return_false;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM)
{
SetLastError(ERROR_INVALID_HANDLE);
goto return_false;
}
if (lpOverlapped != NULL)
{
SetLastError(ERROR_NOT_SUPPORTED);
goto return_false;
}
if (lpNumberOfBytesWritten == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */
goto return_false;
}
*lpNumberOfBytesWritten = 0; /* will be ajusted if required ... */
if (nNumberOfBytesToWrite <= 0)
{
goto return_true; /* FIXME: or FALSE? */
}
/* FIXME: had expected eventfd_write() to return EAGAIN when
* there is no eventfd_read() but this not the case. */
/* discard a possible and no more relevant event */
eventfd_read(pComm->fd_write_event, NULL);
/* ms */
ULONGLONG Tmax = nNumberOfBytesToWrite * pComm->timeouts.WriteTotalTimeoutMultiplier + pComm->timeouts.WriteTotalTimeoutConstant;
/* NB: select() may update the timeout argument to indicate
* how much time was left. Keep the timeout variable out of
* the while() */
pTmaxTimeout = NULL; /* no timeout if Tmax == 0 */
if (Tmax > 0)
{
ZeroMemory(&tmaxTimeout, sizeof(struct timeval));
tmaxTimeout.tv_sec = Tmax / 1000; /* s */
tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */
pTmaxTimeout = &tmaxTimeout;
}
while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite)
{
int biggestFd = -1;
fd_set event_set, write_set;
int nbFds;
biggestFd = pComm->fd_write;
if (pComm->fd_write_event > biggestFd)
biggestFd = pComm->fd_write_event;
FD_ZERO(&event_set);
FD_ZERO(&write_set);
assert(pComm->fd_write_event < FD_SETSIZE);
assert(pComm->fd_write < FD_SETSIZE);
FD_SET(pComm->fd_write_event, &event_set);
FD_SET(pComm->fd_write, &write_set);
nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTmaxTimeout);
if (nbFds < 0)
{
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno));
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
if (nbFds == 0)
{
/* timeout */
SetLastError(ERROR_TIMEOUT);
goto return_false;
}
/* event_set */
if (FD_ISSET(pComm->fd_write_event, &event_set))
{
eventfd_t event = 0;
if (eventfd_read(pComm->fd_write_event, &event) < 0)
{
if (errno == EAGAIN)
{
assert(FALSE); /* not quite sure this should ever happen */
/* keep on */
}
else
{
CommLog_Print(WLOG_WARN, "unexpected error on reading fd_write_event, errno=[%d] %s\n", errno, strerror(errno));
/* FIXME: goto return_false ? */
}
assert(errno == EAGAIN);
}
if (event == FREERDP_PURGE_TXABORT)
{
SetLastError(ERROR_CANCELLED);
goto return_false;
}
assert(event == FREERDP_PURGE_TXABORT); /* no other expected event so far */
}
/* write_set */
if (FD_ISSET(pComm->fd_write, &write_set))
{
ssize_t nbWritten;
nbWritten = write(pComm->fd_write,
lpBuffer + (*lpNumberOfBytesWritten),
nNumberOfBytesToWrite - (*lpNumberOfBytesWritten));
if (nbWritten < 0)
{
CommLog_Print(WLOG_WARN, "CommWriteFile failed after %lu bytes written, errno=[%d] %s\n", *lpNumberOfBytesWritten, errno, strerror(errno));
if (errno == EAGAIN)
{
/* keep on */
continue;
}
else if (errno == EBADF)
{
SetLastError(ERROR_BAD_DEVICE); /* STATUS_INVALID_DEVICE_REQUEST */
goto return_false;
}
else
{
assert(FALSE);
SetLastError(ERROR_IO_DEVICE);
goto return_false;
}
}
*lpNumberOfBytesWritten += nbWritten;
}
} /* while */
/* FIXME: this call to tcdrain() doesn't look correct and
* might hide a bug but was required while testing a serial
* printer. Its driver was expecting the modem line status
* SERIAL_MSR_DSR true after the sending which was never
* happenning otherwise. A purge was also done before each
* Write operation. The serial port was oppened with:
* DesiredAccess=0x0012019F. The printer worked fine with
* mstsc. */
tcdrain(pComm->fd_write);
return_true:
LeaveCriticalSection(&pComm->WriteLock);
return TRUE;
return_false:
LeaveCriticalSection(&pComm->WriteLock);
return FALSE;
}
#endif /* __linux__ */

View File

@ -0,0 +1,739 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#if defined __linux__ && !defined ANDROID
#include <assert.h>
#include <errno.h>
#include <winpr/wlog.h>
#include "comm.h"
#include "comm_ioctl.h"
#include "comm_serial_sys.h"
#include "comm_sercx_sys.h"
#include "comm_sercx2_sys.h"
/* NB: MS-RDPESP's recommendation:
*
* <2> Section 3.2.5.1.6: Windows Implementations use IOCTL constants
* for IoControlCode values. The content and values of the IOCTLs are
* opaque to the protocol. On the server side, the data contained in
* an IOCTL is simply packaged and sent to the client side. For
* maximum compatibility between the different versions of the Windows
* operating system, the client implementation only singles out
* critical IOCTLs and invokes the applicable Win32 port API. The
* other IOCTLS are passed directly to the client-side driver, and the
* processing of this value depends on the drivers installed on the
* client side. The values and parameters for these IOCTLS can be
* found in [MSFT-W2KDDK] Volume 2, Part 2Serial and Parallel
* Drivers, and in [MSDN-PORTS].
*/
const char* _comm_serial_ioctl_name(ULONG number)
{
int i;
for (i=0; _SERIAL_IOCTL_NAMES[i].number != 0; i++)
{
if (_SERIAL_IOCTL_NAMES[i].number == number)
{
return _SERIAL_IOCTL_NAMES[i].name;
}
}
return "(unknown ioctl name)";
}
static BOOL _CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
SERIAL_DRIVER* pServerSerialDriver = NULL;
/* clear any previous last error */
SetLastError(ERROR_SUCCESS);
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (lpOverlapped != NULL)
{
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
if (lpBytesReturned == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER); /* since we doesn't suppport lpOverlapped != NULL */
return FALSE;
}
*lpBytesReturned = 0; /* will be ajusted if required ... */
CommLog_Print(WLOG_DEBUG, "CommDeviceIoControl: IoControlCode: 0x%0.8x", dwIoControlCode);
/* remoteSerialDriver to be use ...
*
* FIXME: might prefer to use an automatic rather than static structure
*/
switch (pComm->serverSerialDriverId)
{
case SerialDriverSerialSys:
pServerSerialDriver = SerialSys_s();
break;
case SerialDriverSerCxSys:
pServerSerialDriver = SerCxSys_s();
break;
case SerialDriverSerCx2Sys:
pServerSerialDriver = SerCx2Sys_s();
break;
case SerialDriverUnknown:
default:
CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%d), using SerCx2.sys", pComm->serverSerialDriverId);
pServerSerialDriver = SerCx2Sys_s();
break;
}
assert(pServerSerialDriver != NULL);
switch (dwIoControlCode)
{
case IOCTL_USBPRINT_GET_1284_ID:
{
/* FIXME: http://msdn.microsoft.com/en-us/library/windows/hardware/ff551803(v=vs.85).aspx */
*lpBytesReturned = nOutBufferSize; /* an empty OutputBuffer will be returned */
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
case IOCTL_SERIAL_SET_BAUD_RATE:
{
if (pServerSerialDriver->set_baud_rate)
{
SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nInBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_baud_rate(pComm, pBaudRate);
}
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE:
{
if (pServerSerialDriver->get_baud_rate)
{
SERIAL_BAUD_RATE *pBaudRate = (SERIAL_BAUD_RATE*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_BAUD_RATE));
if (nOutBufferSize < sizeof(SERIAL_BAUD_RATE))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_baud_rate(pComm, pBaudRate))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_BAUD_RATE);
return TRUE;
}
break;
}
case IOCTL_SERIAL_GET_PROPERTIES:
{
if (pServerSerialDriver->get_properties)
{
COMMPROP *pProperties = (COMMPROP*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(COMMPROP));
if (nOutBufferSize < sizeof(COMMPROP))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_properties(pComm, pProperties))
return FALSE;
*lpBytesReturned = sizeof(COMMPROP);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_CHARS:
{
if (pServerSerialDriver->set_serial_chars)
{
SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_CHARS));
if (nInBufferSize < sizeof(SERIAL_CHARS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_serial_chars(pComm, pSerialChars);
}
break;
}
case IOCTL_SERIAL_GET_CHARS:
{
if (pServerSerialDriver->get_serial_chars)
{
SERIAL_CHARS *pSerialChars = (SERIAL_CHARS*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_CHARS));
if (nOutBufferSize < sizeof(SERIAL_CHARS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_serial_chars(pComm, pSerialChars))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_CHARS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_LINE_CONTROL:
{
if (pServerSerialDriver->set_line_control)
{
SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_LINE_CONTROL));
if (nInBufferSize < sizeof(SERIAL_LINE_CONTROL))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_line_control(pComm, pLineControl);
}
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL:
{
if (pServerSerialDriver->get_line_control)
{
SERIAL_LINE_CONTROL *pLineControl = (SERIAL_LINE_CONTROL*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_LINE_CONTROL));
if (nOutBufferSize < sizeof(SERIAL_LINE_CONTROL))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_line_control(pComm, pLineControl))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_LINE_CONTROL);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_HANDFLOW:
{
if (pServerSerialDriver->set_handflow)
{
SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nInBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_handflow(pComm, pHandflow);
}
break;
}
case IOCTL_SERIAL_GET_HANDFLOW:
{
if (pServerSerialDriver->get_handflow)
{
SERIAL_HANDFLOW *pHandflow = (SERIAL_HANDFLOW*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_HANDFLOW));
if (nOutBufferSize < sizeof(SERIAL_HANDFLOW))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_handflow(pComm, pHandflow))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_HANDFLOW);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_TIMEOUTS:
{
if (pServerSerialDriver->set_timeouts)
{
SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_TIMEOUTS));
if (nInBufferSize < sizeof(SERIAL_TIMEOUTS))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_timeouts(pComm, pHandflow);
}
break;
}
case IOCTL_SERIAL_GET_TIMEOUTS:
{
if (pServerSerialDriver->get_timeouts)
{
SERIAL_TIMEOUTS *pHandflow = (SERIAL_TIMEOUTS*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_TIMEOUTS));
if (nOutBufferSize < sizeof(SERIAL_TIMEOUTS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_timeouts(pComm, pHandflow))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_TIMEOUTS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_DTR:
{
if (pServerSerialDriver->set_dtr)
{
return pServerSerialDriver->set_dtr(pComm);
}
break;
}
case IOCTL_SERIAL_CLR_DTR:
{
if (pServerSerialDriver->clear_dtr)
{
return pServerSerialDriver->clear_dtr(pComm);
}
break;
}
case IOCTL_SERIAL_SET_RTS:
{
if (pServerSerialDriver->set_rts)
{
return pServerSerialDriver->set_rts(pComm);
}
break;
}
case IOCTL_SERIAL_CLR_RTS:
{
if (pServerSerialDriver->clear_rts)
{
return pServerSerialDriver->clear_rts(pComm);
}
break;
}
case IOCTL_SERIAL_GET_MODEMSTATUS:
{
if (pServerSerialDriver->get_modemstatus)
{
ULONG *pRegister = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_modemstatus(pComm, pRegister))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_WAIT_MASK:
{
if (pServerSerialDriver->set_wait_mask)
{
ULONG *pWaitMask = (ULONG*)lpInBuffer;
assert(nInBufferSize >= sizeof(ULONG));
if (nInBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_wait_mask(pComm, pWaitMask);
}
break;
}
case IOCTL_SERIAL_GET_WAIT_MASK:
{
if (pServerSerialDriver->get_wait_mask)
{
ULONG *pWaitMask = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_wait_mask(pComm, pWaitMask))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_WAIT_ON_MASK:
{
if (pServerSerialDriver->wait_on_mask)
{
ULONG *pOutputMask = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->wait_on_mask(pComm, pOutputMask))
{
*lpBytesReturned = sizeof(ULONG);
return FALSE;
}
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_QUEUE_SIZE:
{
if (pServerSerialDriver->set_queue_size)
{
SERIAL_QUEUE_SIZE *pQueueSize = (SERIAL_QUEUE_SIZE*)lpInBuffer;
assert(nInBufferSize >= sizeof(SERIAL_QUEUE_SIZE));
if (nInBufferSize < sizeof(SERIAL_QUEUE_SIZE))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->set_queue_size(pComm, pQueueSize);
}
break;
}
case IOCTL_SERIAL_PURGE:
{
if (pServerSerialDriver->purge)
{
ULONG *pPurgeMask = (ULONG*)lpInBuffer;
assert(nInBufferSize >= sizeof(ULONG));
if (nInBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->purge(pComm, pPurgeMask);
}
break;
}
case IOCTL_SERIAL_GET_COMMSTATUS:
{
if (pServerSerialDriver->get_commstatus)
{
SERIAL_STATUS *pCommstatus = (SERIAL_STATUS*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(SERIAL_STATUS));
if (nOutBufferSize < sizeof(SERIAL_STATUS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_commstatus(pComm, pCommstatus))
return FALSE;
*lpBytesReturned = sizeof(SERIAL_STATUS);
return TRUE;
}
break;
}
case IOCTL_SERIAL_SET_BREAK_ON:
{
if (pServerSerialDriver->set_break_on)
{
return pServerSerialDriver->set_break_on(pComm);
}
break;
}
case IOCTL_SERIAL_SET_BREAK_OFF:
{
if (pServerSerialDriver->set_break_off)
{
return pServerSerialDriver->set_break_off(pComm);
}
break;
}
case IOCTL_SERIAL_SET_XOFF:
{
if (pServerSerialDriver->set_xoff)
{
return pServerSerialDriver->set_xoff(pComm);
}
break;
}
case IOCTL_SERIAL_SET_XON:
{
if (pServerSerialDriver->set_xon)
{
return pServerSerialDriver->set_xon(pComm);
}
break;
}
case IOCTL_SERIAL_GET_DTRRTS:
{
if (pServerSerialDriver->get_dtrrts)
{
ULONG *pMask = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->get_dtrrts(pComm, pMask))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_CONFIG_SIZE:
{
if (pServerSerialDriver->config_size)
{
ULONG *pSize = (ULONG*)lpOutBuffer;
assert(nOutBufferSize >= sizeof(ULONG));
if (nOutBufferSize < sizeof(ULONG))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if (!pServerSerialDriver->config_size(pComm, pSize))
return FALSE;
*lpBytesReturned = sizeof(ULONG);
return TRUE;
}
break;
}
case IOCTL_SERIAL_IMMEDIATE_CHAR:
{
if (pServerSerialDriver->immediate_char)
{
UCHAR *pChar = (UCHAR*)lpInBuffer;
assert(nInBufferSize >= sizeof(UCHAR));
if (nInBufferSize < sizeof(UCHAR))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
return pServerSerialDriver->immediate_char(pComm, pChar);
}
break;
}
case IOCTL_SERIAL_RESET_DEVICE:
{
if (pServerSerialDriver->reset_device)
{
return pServerSerialDriver->reset_device(pComm);
}
break;
}
}
CommLog_Print(WLOG_WARN, _T("unsupported IoControlCode=[0x%lX] %s (remote serial driver: %s)"),
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), pServerSerialDriver->name);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED); /* => STATUS_NOT_IMPLEMENTED */
return FALSE;
}
/**
* FIXME: to be used through winpr-io's DeviceIoControl
*
* Any previous error as returned by GetLastError is cleared.
*
* ERRORS:
* ERROR_INVALID_HANDLE
* ERROR_INVALID_PARAMETER
* ERROR_NOT_SUPPORTED lpOverlapped is not supported
* ERROR_INSUFFICIENT_BUFFER
* ERROR_CALL_NOT_IMPLEMENTED unimplemented ioctl
*/
BOOL CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
BOOL result;
if (hDevice == INVALID_HANDLE_VALUE)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!pComm || pComm->Type != HANDLE_TYPE_COMM || !pComm->fd )
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
result = _CommDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize,
lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped);
if (lpBytesReturned && *lpBytesReturned != nOutBufferSize)
{
/* This might be a hint for a bug, especially when result==TRUE */
CommLog_Print(WLOG_WARN, "lpBytesReturned=%ld and nOutBufferSize=%ld are different!", *lpBytesReturned, nOutBufferSize);
}
if (pComm->permissive)
{
if (!result)
{
CommLog_Print(WLOG_WARN, "[permissive]: whereas it failed, made to succeed IoControlCode=[0x%lX] %s, last-error: 0x%lX",
dwIoControlCode, _comm_serial_ioctl_name(dwIoControlCode), GetLastError());
}
return TRUE; /* always! */
}
return result;
}
int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
{
int result;
struct termios currentState;
if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
{
CommLog_Print(WLOG_WARN, "tcsetattr failure, errno: %d", errno);
return result;
}
/* NB: tcsetattr() can succeed even if not all changes have been applied. */
ZeroMemory(&currentState, sizeof(struct termios));
if ((result = tcgetattr(fd, &currentState)) < 0)
{
CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno);
return result;
}
if (memcmp(&currentState, &termios_p, sizeof(struct termios)) != 0)
{
CommLog_Print(WLOG_DEBUG, "all termios parameters are not set yet, doing a second attempt...");
if ((result = tcsetattr(fd, optional_actions, termios_p)) < 0)
{
CommLog_Print(WLOG_WARN, "2nd tcsetattr failure, errno: %d", errno);
return result;
}
ZeroMemory(&currentState, sizeof(struct termios));
if ((result = tcgetattr(fd, &currentState)) < 0)
{
CommLog_Print(WLOG_WARN, "tcgetattr failure, errno: %d", errno);
return result;
}
if (memcmp(&currentState, termios_p, sizeof(struct termios)) != 0)
{
CommLog_Print(WLOG_WARN, "Failure: all termios parameters are still not set on a second attempt");
return -1;
}
}
return 0;
}
#endif /* __linux__ */

View File

@ -0,0 +1,244 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_COMM_IOCTL_H_
#define WINPR_COMM_IOCTL_H_
#if defined __linux__ && !defined ANDROID
#include <termios.h>
#include <winpr/io.h>
#include <winpr/tchar.h>
#include <winpr/wtypes.h>
#include "comm.h"
/* Serial I/O Request Interface: http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
* Ntddser.h http://msdn.microsoft.com/en-us/cc308432.aspx
* Ntddpar.h http://msdn.microsoft.com/en-us/cc308431.aspx
*/
#ifdef __cplusplus
extern "C" {
#endif
/* TODO: defines and types below are very similar to those in comm.h, keep only
* those that differ more than the names */
#define STOP_BIT_1 0
#define STOP_BITS_1_5 1
#define STOP_BITS_2 2
#define NO_PARITY 0
#define ODD_PARITY 1
#define EVEN_PARITY 2
#define MARK_PARITY 3
#define SPACE_PARITY 4
typedef struct _SERIAL_BAUD_RATE
{
ULONG BaudRate;
} SERIAL_BAUD_RATE, *PSERIAL_BAUD_RATE;
typedef struct _SERIAL_CHARS
{
UCHAR EofChar;
UCHAR ErrorChar;
UCHAR BreakChar;
UCHAR EventChar;
UCHAR XonChar;
UCHAR XoffChar;
} SERIAL_CHARS, *PSERIAL_CHARS;
typedef struct _SERIAL_LINE_CONTROL
{
UCHAR StopBits;
UCHAR Parity;
UCHAR WordLength;
} SERIAL_LINE_CONTROL, *PSERIAL_LINE_CONTROL;
typedef struct _SERIAL_HANDFLOW
{
ULONG ControlHandShake;
ULONG FlowReplace;
LONG XonLimit;
LONG XoffLimit;
} SERIAL_HANDFLOW, *PSERIAL_HANDFLOW;
#define SERIAL_DTR_MASK ((ULONG)0x03)
#define SERIAL_DTR_CONTROL ((ULONG)0x01)
#define SERIAL_DTR_HANDSHAKE ((ULONG)0x02)
#define SERIAL_CTS_HANDSHAKE ((ULONG)0x08)
#define SERIAL_DSR_HANDSHAKE ((ULONG)0x10)
#define SERIAL_DCD_HANDSHAKE ((ULONG)0x20)
#define SERIAL_OUT_HANDSHAKEMASK ((ULONG)0x38)
#define SERIAL_DSR_SENSITIVITY ((ULONG)0x40)
#define SERIAL_ERROR_ABORT ((ULONG)0x80000000)
#define SERIAL_CONTROL_INVALID ((ULONG)0x7fffff84)
#define SERIAL_AUTO_TRANSMIT ((ULONG)0x01)
#define SERIAL_AUTO_RECEIVE ((ULONG)0x02)
#define SERIAL_ERROR_CHAR ((ULONG)0x04)
#define SERIAL_NULL_STRIPPING ((ULONG)0x08)
#define SERIAL_BREAK_CHAR ((ULONG)0x10)
#define SERIAL_RTS_MASK ((ULONG)0xc0)
#define SERIAL_RTS_CONTROL ((ULONG)0x40)
#define SERIAL_RTS_HANDSHAKE ((ULONG)0x80)
#define SERIAL_TRANSMIT_TOGGLE ((ULONG)0xc0)
#define SERIAL_XOFF_CONTINUE ((ULONG)0x80000000)
#define SERIAL_FLOW_INVALID ((ULONG)0x7fffff20)
#define SERIAL_SP_SERIALCOMM ((ULONG)0x00000001)
#define SERIAL_SP_UNSPECIFIED ((ULONG)0x00000000)
#define SERIAL_SP_RS232 ((ULONG)0x00000001)
#define SERIAL_SP_PARALLEL ((ULONG)0x00000002)
#define SERIAL_SP_RS422 ((ULONG)0x00000003)
#define SERIAL_SP_RS423 ((ULONG)0x00000004)
#define SERIAL_SP_RS449 ((ULONG)0x00000005)
#define SERIAL_SP_MODEM ((ULONG)0X00000006)
#define SERIAL_SP_FAX ((ULONG)0x00000021)
#define SERIAL_SP_SCANNER ((ULONG)0x00000022)
#define SERIAL_SP_BRIDGE ((ULONG)0x00000100)
#define SERIAL_SP_LAT ((ULONG)0x00000101)
#define SERIAL_SP_TELNET ((ULONG)0x00000102)
#define SERIAL_SP_X25 ((ULONG)0x00000103)
typedef struct _SERIAL_TIMEOUTS
{
ULONG ReadIntervalTimeout;
ULONG ReadTotalTimeoutMultiplier;
ULONG ReadTotalTimeoutConstant;
ULONG WriteTotalTimeoutMultiplier;
ULONG WriteTotalTimeoutConstant;
} SERIAL_TIMEOUTS,*PSERIAL_TIMEOUTS;
#define SERIAL_MSR_DCTS 0x01
#define SERIAL_MSR_DDSR 0x02
#define SERIAL_MSR_TERI 0x04
#define SERIAL_MSR_DDCD 0x08
#define SERIAL_MSR_CTS 0x10
#define SERIAL_MSR_DSR 0x20
#define SERIAL_MSR_RI 0x40
#define SERIAL_MSR_DCD 0x80
typedef struct _SERIAL_QUEUE_SIZE
{
ULONG InSize;
ULONG OutSize;
} SERIAL_QUEUE_SIZE, *PSERIAL_QUEUE_SIZE;
#define SERIAL_PURGE_TXABORT 0x00000001
#define SERIAL_PURGE_RXABORT 0x00000002
#define SERIAL_PURGE_TXCLEAR 0x00000004
#define SERIAL_PURGE_RXCLEAR 0x00000008
typedef struct _SERIAL_STATUS
{
ULONG Errors;
ULONG HoldReasons;
ULONG AmountInInQueue;
ULONG AmountInOutQueue;
BOOLEAN EofReceived;
BOOLEAN WaitForImmediate;
} SERIAL_STATUS, *PSERIAL_STATUS;
#define SERIAL_TX_WAITING_FOR_CTS ((ULONG)0x00000001)
#define SERIAL_TX_WAITING_FOR_DSR ((ULONG)0x00000002)
#define SERIAL_TX_WAITING_FOR_DCD ((ULONG)0x00000004)
#define SERIAL_TX_WAITING_FOR_XON ((ULONG)0x00000008)
#define SERIAL_TX_WAITING_XOFF_SENT ((ULONG)0x00000010)
#define SERIAL_TX_WAITING_ON_BREAK ((ULONG)0x00000020)
#define SERIAL_RX_WAITING_FOR_DSR ((ULONG)0x00000040)
#define SERIAL_ERROR_BREAK ((ULONG)0x00000001)
#define SERIAL_ERROR_FRAMING ((ULONG)0x00000002)
#define SERIAL_ERROR_OVERRUN ((ULONG)0x00000004)
#define SERIAL_ERROR_QUEUEOVERRUN ((ULONG)0x00000008)
#define SERIAL_ERROR_PARITY ((ULONG)0x00000010)
#define SERIAL_DTR_STATE ((ULONG)0x00000001)
#define SERIAL_RTS_STATE ((ULONG)0x00000002)
#define SERIAL_CTS_STATE ((ULONG)0x00000010)
#define SERIAL_DSR_STATE ((ULONG)0x00000020)
#define SERIAL_RI_STATE ((ULONG)0x00000040)
#define SERIAL_DCD_STATE ((ULONG)0x00000080)
/**
* A function might be NULL if not supported by the underlying driver.
*
* FIXME: better have to use input and output buffers for all functions?
*/
typedef struct _SERIAL_DRIVER
{
SERIAL_DRIVER_ID id;
TCHAR *name;
BOOL (*set_baud_rate)(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate);
BOOL (*get_baud_rate)(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate);
BOOL (*get_properties)(WINPR_COMM *pComm, COMMPROP *pProperties);
BOOL (*set_serial_chars)(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChars);
BOOL (*get_serial_chars)(WINPR_COMM *pComm, SERIAL_CHARS *pSerialChars);
BOOL (*set_line_control)(WINPR_COMM *pComm, const SERIAL_LINE_CONTROL *pLineControl);
BOOL (*get_line_control)(WINPR_COMM *pComm, SERIAL_LINE_CONTROL *pLineControl);
BOOL (*set_handflow)(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow);
BOOL (*get_handflow)(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow);
BOOL (*set_timeouts)(WINPR_COMM *pComm, const SERIAL_TIMEOUTS *pTimeouts);
BOOL (*get_timeouts)(WINPR_COMM *pComm, SERIAL_TIMEOUTS *pTimeouts);
BOOL (*set_dtr)(WINPR_COMM *pComm);
BOOL (*clear_dtr)(WINPR_COMM *pComm);
BOOL (*set_rts)(WINPR_COMM *pComm);
BOOL (*clear_rts)(WINPR_COMM *pComm);
BOOL (*get_modemstatus)(WINPR_COMM *pComm, ULONG *pRegister);
BOOL (*set_wait_mask)(WINPR_COMM *pComm, const ULONG *pWaitMask);
BOOL (*get_wait_mask)(WINPR_COMM *pComm, ULONG *pWaitMask);
BOOL (*wait_on_mask)(WINPR_COMM *pComm, ULONG *pOutputMask);
BOOL (*set_queue_size)(WINPR_COMM *pComm, const SERIAL_QUEUE_SIZE *pQueueSize);
BOOL (*purge)(WINPR_COMM *pComm, const ULONG *pPurgeMask);
BOOL (*get_commstatus)(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus);
BOOL (*set_break_on)(WINPR_COMM *pComm);
BOOL (*set_break_off)(WINPR_COMM *pComm);
BOOL (*set_xoff)(WINPR_COMM *pComm);
BOOL (*set_xon)(WINPR_COMM *pComm);
BOOL (*get_dtrrts)(WINPR_COMM *pComm, ULONG *pMask);
BOOL (*config_size)(WINPR_COMM *pComm, ULONG *pSize);
BOOL (*immediate_char)(WINPR_COMM *pComm, const UCHAR *pChar);
BOOL (*reset_device)(WINPR_COMM *pComm);
} SERIAL_DRIVER;
int _comm_ioctl_tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
#ifdef __cplusplus
}
#endif
#endif /* __linux__ */
#endif /* WINPR_COMM_IOCTL_H_ */

View File

@ -0,0 +1,207 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined __linux__ && !defined ANDROID
#include <winpr/wlog.h>
#include "comm_serial_sys.h"
#include "comm_sercx_sys.h"
#include "comm_sercx2_sys.h"
/* http://msdn.microsoft.com/en-us/library/dn265347%28v=vs.85%29.aspx
*
* SerCx2 does not support special characters. SerCx2 always completes
* an IOCTL_SERIAL_SET_CHARS request with a STATUS_SUCCESS status
* code, but does not set any special characters or perform any other
* operation in response to this request. For an
* IOCTL_SERIAL_GET_CHARS request, SerCx2 sets all the character
* values in the SERIAL_CHARS structure to null, and completes the
* request with a STATUS_SUCCESS status code.
*/
static BOOL _set_serial_chars(WINPR_COMM* pComm, const SERIAL_CHARS* pSerialChars)
{
return TRUE;
}
static BOOL _get_serial_chars(WINPR_COMM* pComm, SERIAL_CHARS* pSerialChars)
{
ZeroMemory(pSerialChars, sizeof(SERIAL_CHARS));
return TRUE;
}
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
/* FIXME: only using the Serial.sys' events, complete the support of the remaining events */
static const ULONG _SERCX2_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING |
/* SERIAL_EV_PERR | */
SERIAL_EV_RX80FULL /*|
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/;
/* use Serial.sys for basis (not SerCx.sys) */
static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
{
ULONG possibleMask;
SERIAL_DRIVER* pSerialSys = SerialSys_s();
possibleMask = *pWaitMask & _SERCX2_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
CommLog_Print(WLOG_WARN, "Not all wait events supported (SerCx2.sys), requested events= 0X%lX, possible events= 0X%lX", *pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->WaitEventMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
static BOOL _purge(WINPR_COMM *pComm, const ULONG *pPurgeMask)
{
SERIAL_DRIVER* pSerialSys = SerialSys_s();
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546655%28v=vs.85%29.aspx */
if ((*pPurgeMask & SERIAL_PURGE_RXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_RXABORT))
{
CommLog_Print(WLOG_WARN, "Expecting SERIAL_PURGE_RXABORT since SERIAL_PURGE_RXCLEAR is set");
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
return FALSE;
}
if ((*pPurgeMask & SERIAL_PURGE_TXCLEAR) && !(*pPurgeMask & SERIAL_PURGE_TXABORT))
{
CommLog_Print(WLOG_WARN, "Expecting SERIAL_PURGE_TXABORT since SERIAL_PURGE_TXCLEAR is set");
SetLastError(ERROR_INVALID_DEVICE_OBJECT_PARAMETER);
return FALSE;
}
return pSerialSys->purge(pComm, pPurgeMask);
}
/* specific functions only */
static SERIAL_DRIVER _SerCx2Sys =
{
.id = SerialDriverSerCx2Sys,
.name = _T("SerCx2.sys"),
.set_baud_rate = NULL,
.get_baud_rate = NULL,
.get_properties = NULL,
.set_serial_chars = _set_serial_chars,
.get_serial_chars = _get_serial_chars,
.set_line_control = NULL,
.get_line_control = NULL,
.set_handflow = NULL,
.get_handflow = NULL,
.set_timeouts = NULL,
.get_timeouts = NULL,
.set_dtr = NULL,
.clear_dtr = NULL,
.set_rts = NULL,
.clear_rts = NULL,
.get_modemstatus = NULL,
.set_wait_mask = _set_wait_mask,
.get_wait_mask = NULL,
.wait_on_mask = NULL,
.set_queue_size = NULL,
.purge = _purge,
.get_commstatus = NULL,
.set_break_on = NULL,
.set_break_off = NULL,
.set_xoff = NULL, /* not supported by SerCx2.sys */
.set_xon = NULL, /* not supported by SerCx2.sys */
.get_dtrrts = NULL,
.config_size = NULL, /* not supported by SerCx2.sys */
.immediate_char = NULL, /* not supported by SerCx2.sys */
.reset_device = NULL, /* not supported by SerCx2.sys */
};
SERIAL_DRIVER* SerCx2Sys_s()
{
/* _SerCx2Sys completed with inherited functions from SerialSys or SerCxSys */
SERIAL_DRIVER* pSerialSys = SerialSys_s();
SERIAL_DRIVER* pSerCxSys = SerCxSys_s();
_SerCx2Sys.set_baud_rate = pSerCxSys->set_baud_rate;
_SerCx2Sys.get_baud_rate = pSerCxSys->get_baud_rate;
_SerCx2Sys.get_properties = pSerCxSys->get_properties;
_SerCx2Sys.set_line_control = pSerCxSys->set_line_control;
_SerCx2Sys.get_line_control = pSerCxSys->get_line_control;
/* Only SERIAL_CTS_HANDSHAKE, SERIAL_RTS_CONTROL and SERIAL_RTS_HANDSHAKE flags are really required by SerCx2.sys
* http://msdn.microsoft.com/en-us/library/jj680685%28v=vs.85%29.aspx
*/
_SerCx2Sys.set_handflow = pSerialSys->set_handflow;
_SerCx2Sys.get_handflow = pSerialSys->get_handflow;
_SerCx2Sys.set_timeouts = pSerialSys->set_timeouts;
_SerCx2Sys.get_timeouts = pSerialSys->get_timeouts;
_SerCx2Sys.set_dtr = pSerialSys->set_dtr;
_SerCx2Sys.clear_dtr = pSerialSys->clear_dtr;
_SerCx2Sys.set_rts = pSerialSys->set_rts;
_SerCx2Sys.clear_rts = pSerialSys->clear_rts;
_SerCx2Sys.get_modemstatus = pSerialSys->get_modemstatus;
_SerCx2Sys.set_wait_mask = pSerialSys->set_wait_mask;
_SerCx2Sys.get_wait_mask = pSerialSys->get_wait_mask;
_SerCx2Sys.wait_on_mask = pSerialSys->wait_on_mask;
_SerCx2Sys.set_queue_size = pSerialSys->set_queue_size;
_SerCx2Sys.get_commstatus = pSerialSys->get_commstatus;
_SerCx2Sys.set_break_on = pSerialSys->set_break_on;
_SerCx2Sys.set_break_off = pSerialSys->set_break_off;
_SerCx2Sys.get_dtrrts = pSerialSys->get_dtrrts;
return &_SerCx2Sys;
}
#endif /* __linux__ */

View File

@ -0,0 +1,39 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERCX2_SYS_H
#define COMM_SERCX2_SYS_H
#if defined __linux__ && !defined ANDROID
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C" {
#endif
SERIAL_DRIVER* SerCx2Sys_s();
#ifdef __cplusplus
}
#endif
#endif /* __linux__ */
#endif /* COMM_SERCX2_SYS_H */

View File

@ -0,0 +1,455 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2011 O.S. Systems Software Ltda.
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined __linux__ && !defined ANDROID
#include <assert.h>
#include <termios.h>
#include <winpr/wlog.h>
#include "comm_serial_sys.h"
/* 0: B* (Linux termios)
* 1: CBR_* or actual baud rate
* 2: BAUD_* (similar to SERIAL_BAUD_*)
*/
static const speed_t _SERCX_SYS_BAUD_TABLE[][3] = {
#ifdef B0
{B0, 0, 0}, /* hang up */
#endif
#ifdef B50
{B50, 50, 0},
#endif
#ifdef B75
{B75, 75, BAUD_075},
#endif
#ifdef B110
{B110, CBR_110, BAUD_110},
#endif
#ifdef B134
{B134, 134, 0 /*BAUD_134_5*/},
#endif
#ifdef B150
{B150, 150, BAUD_150},
#endif
#ifdef B200
{B200, 200, 0},
#endif
#ifdef B300
{B300, CBR_300, BAUD_300},
#endif
#ifdef B600
{B600, CBR_600, BAUD_600},
#endif
#ifdef B1200
{B1200, CBR_1200, BAUD_1200},
#endif
#ifdef B1800
{B1800, 1800, BAUD_1800},
#endif
#ifdef B2400
{B2400, CBR_2400, BAUD_2400},
#endif
#ifdef B4800
{B4800, CBR_4800, BAUD_4800},
#endif
/* {, ,BAUD_7200} */
#ifdef B9600
{B9600, CBR_9600, BAUD_9600},
#endif
/* {, CBR_14400, BAUD_14400}, /\* unsupported on Linux *\/ */
#ifdef B19200
{B19200, CBR_19200, BAUD_19200},
#endif
#ifdef B38400
{B38400, CBR_38400, BAUD_38400},
#endif
/* {, CBR_56000, BAUD_56K}, /\* unsupported on Linux *\/ */
#ifdef B57600
{B57600, CBR_57600, BAUD_57600},
#endif
#ifdef B115200
{B115200, CBR_115200, BAUD_115200},
#endif
/* {, CBR_128000, BAUD_128K}, /\* unsupported on Linux *\/ */
/* {, CBR_256000, BAUD_USER}, /\* unsupported on Linux *\/ */
#ifdef B230400
{B230400, 230400, BAUD_USER},
#endif
#ifdef B460800
{B460800, 460800, BAUD_USER},
#endif
#ifdef B500000
{B500000, 500000, BAUD_USER},
#endif
#ifdef B576000
{B576000, 576000, BAUD_USER},
#endif
#ifdef B921600
{B921600, 921600, BAUD_USER},
#endif
#ifdef B1000000
{B1000000, 1000000, BAUD_USER},
#endif
#ifdef B1152000
{B1152000, 1152000, BAUD_USER},
#endif
#ifdef B1500000
{B1500000, 1500000, BAUD_USER},
#endif
#ifdef B2000000
{B2000000, 2000000, BAUD_USER},
#endif
#ifdef B2500000
{B2500000, 2500000, BAUD_USER},
#endif
#ifdef B3000000
{B3000000, 3000000, BAUD_USER},
#endif
#ifdef B3500000
{B3500000, 3500000, BAUD_USER},
#endif
#ifdef B4000000
{B4000000, 4000000, BAUD_USER}, /* __MAX_BAUD */
#endif
};
static BOOL _get_properties(WINPR_COMM *pComm, COMMPROP *pProperties)
{
int i;
SERIAL_DRIVER* pSerialSys = SerialSys_s();
if (!pSerialSys->get_properties(pComm, pProperties))
{
return FALSE;
}
/* override some of the inherited properties from SerialSys ... */
pProperties->dwMaxBaud = BAUD_USER;
pProperties->dwSettableBaud = 0;
for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++)
{
pProperties->dwSettableBaud |= _SERCX_SYS_BAUD_TABLE[i][2];
}
return TRUE;
}
static BOOL _set_baud_rate(WINPR_COMM *pComm, const SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t newSpeed;
struct termios futureState;
ZeroMemory(&futureState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &futureState) < 0) /* NB: preserves current settings not directly handled by the Communication Functions */
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SERCX_SYS_BAUD_TABLE[i][1] == pBaudRate->BaudRate)
{
newSpeed = _SERCX_SYS_BAUD_TABLE[i][0];
if (cfsetspeed(&futureState, newSpeed) < 0)
{
CommLog_Print(WLOG_WARN, "failed to set speed 0x%x (%lu)", newSpeed, pBaudRate->BaudRate);
return FALSE;
}
assert(cfgetispeed(&futureState) == newSpeed);
if (_comm_ioctl_tcsetattr(pComm->fd, TCSANOW, &futureState) < 0)
{
CommLog_Print(WLOG_WARN, "_comm_ioctl_tcsetattr failure: last-error: 0x%lX", GetLastError());
return FALSE;
}
return TRUE;
}
}
CommLog_Print(WLOG_WARN, "could not find a matching speed for the baud rate %lu", pBaudRate->BaudRate);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
static BOOL _get_baud_rate(WINPR_COMM *pComm, SERIAL_BAUD_RATE *pBaudRate)
{
int i;
speed_t currentSpeed;
struct termios currentState;
ZeroMemory(&currentState, sizeof(struct termios));
if (tcgetattr(pComm->fd, &currentState) < 0)
{
SetLastError(ERROR_IO_DEVICE);
return FALSE;
}
currentSpeed = cfgetispeed(&currentState);
for (i=0; _SERCX_SYS_BAUD_TABLE[i][0]<=__MAX_BAUD; i++)
{
if (_SERCX_SYS_BAUD_TABLE[i][0] == currentSpeed)
{
pBaudRate->BaudRate = _SERCX_SYS_BAUD_TABLE[i][1];
return TRUE;
}
}
CommLog_Print(WLOG_WARN, "could not find a matching baud rate for the speed 0x%x", currentSpeed);
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
static BOOL _set_handflow(WINPR_COMM *pComm, const SERIAL_HANDFLOW *pHandflow)
{
SERIAL_HANDFLOW SerCxHandflow;
BOOL result = TRUE;
SERIAL_DRIVER* pSerialSys = SerialSys_s();
memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW));
/* filter out unsupported bits by SerCx.sys
*
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
*/
SerCxHandflow.ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
SerCxHandflow.FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake)
{
if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
{
CommLog_Print(WLOG_WARN, "SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
{
CommLog_Print(WLOG_WARN, "SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
{
CommLog_Print(WLOG_WARN, "SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys");
}
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE;
}
if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace)
{
if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT)
{
CommLog_Print(WLOG_WARN, "SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE)
{
CommLog_Print(WLOG_WARN, "SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR)
{
CommLog_Print(WLOG_WARN, "SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING)
{
CommLog_Print(WLOG_WARN, "SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR)
{
CommLog_Print(WLOG_WARN, "SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys");
}
if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE)
{
CommLog_Print(WLOG_WARN, "SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys");
}
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
result = FALSE;
}
if (!pSerialSys->set_handflow(pComm, &SerCxHandflow))
return FALSE;
return result;
}
static BOOL _get_handflow(WINPR_COMM *pComm, SERIAL_HANDFLOW *pHandflow)
{
BOOL result;
SERIAL_DRIVER* pSerialSys = SerialSys_s();
result = pSerialSys->get_handflow(pComm, pHandflow);
/* filter out unsupported bits by SerCx.sys
*
* http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
*/
pHandflow->ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
return result;
}
/* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK =
SERIAL_EV_RXCHAR |
/* SERIAL_EV_RXFLAG | */
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING /* |
SERIAL_EV_PERR |
SERIAL_EV_RX80FULL |
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2*/;
static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
{
ULONG possibleMask;
SERIAL_DRIVER* pSerialSys = SerialSys_s();
possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK;
if (possibleMask != *pWaitMask)
{
CommLog_Print(WLOG_WARN, "Not all wait events supported (SerCx.sys), requested events= 0x%lX, possible events= 0x%lX", *pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->WaitEventMask = possibleMask;
return FALSE;
}
/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
return pSerialSys->set_wait_mask(pComm, pWaitMask);
}
/* specific functions only */
static SERIAL_DRIVER _SerCxSys =
{
.id = SerialDriverSerCxSys,
.name = _T("SerCx.sys"),
.set_baud_rate = _set_baud_rate,
.get_baud_rate = _get_baud_rate,
.get_properties = _get_properties,
.set_serial_chars = NULL,
.get_serial_chars = NULL,
.set_line_control = NULL,
.get_line_control = NULL,
.set_handflow = _set_handflow,
.get_handflow = _get_handflow,
.set_timeouts = NULL,
.get_timeouts = NULL,
.set_dtr = NULL,
.clear_dtr = NULL,
.set_rts = NULL,
.clear_rts = NULL,
.get_modemstatus = NULL,
.set_wait_mask = _set_wait_mask,
.get_wait_mask = NULL,
.wait_on_mask = NULL,
.set_queue_size = NULL,
.purge = NULL,
.get_commstatus = NULL,
.set_break_on = NULL,
.set_break_off = NULL,
.set_xoff = NULL,
.set_xon = NULL,
.get_dtrrts = NULL,
.config_size = NULL, /* not supported by SerCx.sys */
.immediate_char = NULL,
.reset_device = NULL, /* not supported by SerCx.sys */
};
SERIAL_DRIVER* SerCxSys_s()
{
/* _SerCxSys completed with inherited functions from SerialSys */
SERIAL_DRIVER* pSerialSys = SerialSys_s();
_SerCxSys.set_serial_chars = pSerialSys->set_serial_chars;
_SerCxSys.get_serial_chars = pSerialSys->get_serial_chars;
_SerCxSys.set_line_control = pSerialSys->set_line_control;
_SerCxSys.get_line_control = pSerialSys->get_line_control;
_SerCxSys.set_timeouts = pSerialSys->set_timeouts;
_SerCxSys.get_timeouts = pSerialSys->get_timeouts;
_SerCxSys.set_dtr = pSerialSys->set_dtr;
_SerCxSys.clear_dtr = pSerialSys->clear_dtr;
_SerCxSys.set_rts = pSerialSys->set_rts;
_SerCxSys.clear_rts = pSerialSys->clear_rts;
_SerCxSys.get_modemstatus = pSerialSys->get_modemstatus;
_SerCxSys.set_wait_mask = pSerialSys->set_wait_mask;
_SerCxSys.get_wait_mask = pSerialSys->get_wait_mask;
_SerCxSys.wait_on_mask = pSerialSys->wait_on_mask;
_SerCxSys.set_queue_size = pSerialSys->set_queue_size;
_SerCxSys.purge = pSerialSys->purge;
_SerCxSys.get_commstatus = pSerialSys->get_commstatus;
_SerCxSys.set_break_on = pSerialSys->set_break_on;
_SerCxSys.set_break_off = pSerialSys->set_break_off;
_SerCxSys.set_xoff = pSerialSys->set_xoff;
_SerCxSys.set_xon = pSerialSys->set_xon;
_SerCxSys.get_dtrrts = pSerialSys->get_dtrrts;
_SerCxSys.immediate_char = pSerialSys->immediate_char;
return &_SerCxSys;
}
#endif /* __linux__ */

View File

@ -0,0 +1,41 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERCX_SYS_H
#define COMM_SERCX_SYS_H
#if defined __linux__ && !defined ANDROID
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C" {
#endif
SERIAL_DRIVER* SerCxSys_s();
#ifdef __cplusplus
}
#endif
#endif /* __linux__ */
#endif /* COMM_SERCX_SYS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMM_SERIAL_SYS_H
#define COMM_SERIAL_SYS_H
#if defined __linux__ && !defined ANDROID
#include "comm_ioctl.h"
#ifdef __cplusplus
extern "C" {
#endif
SERIAL_DRIVER* SerialSys_s();
#ifdef __cplusplus
}
#endif
#endif /* __linux__ */
#endif /* COMM_SERIAL_SYS_H */

View File

@ -0,0 +1,3 @@
LIBRARY "libwinpr-comm"
EXPORTS

2
winpr/libwinpr/comm/test/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
TestComm
TestComm.c

View File

@ -0,0 +1,39 @@
set(MODULE_NAME "TestComm")
set(MODULE_PREFIX "TEST_COMM")
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS
TestCommDevice.c
TestCommConfig.c
TestGetCommState.c
TestSetCommState.c
TestSerialChars.c
TestControlSettings.c
TestHandflow.c
TestTimeouts.c
TestCommMonitor.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS
${${MODULE_PREFIX}_DRIVER}
${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-comm winpr-crt winpr-file)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@ -0,0 +1,149 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/stat.h>
#include <winpr/crt.h>
#include <winpr/comm.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
int TestCommConfig(int argc, char* argv[])
{
DCB dcb;
HANDLE hComm;
BOOL success;
LPCSTR lpFileName = "\\\\.\\COM1";
COMMPROP commProp;
struct stat statbuf;
hComm = CreateFileA(lpFileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm && (hComm != INVALID_HANDLE_VALUE))
{
fprintf(stderr, "CreateFileA failure: could create a handle on a not yet defined device: %s\n", lpFileName);
return EXIT_FAILURE;
}
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
success = DefineCommDevice(lpFileName, "/dev/ttyS0");
if(!success)
{
fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName);
return EXIT_FAILURE;
}
hComm = CreateFileA(lpFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, /* invalid parmaeter */
NULL,
CREATE_NEW, /* invalid parameter */
0,
(HANDLE)1234); /* invalid parmaeter */
if (hComm != INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: could create a handle with some invalid parameters %s\n", lpFileName);
return EXIT_FAILURE;
}
hComm = CreateFileA(lpFileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%0.8x\n", lpFileName, GetLastError());
return EXIT_FAILURE;
}
/* TODO: a second call to CreateFileA should failed and
* GetLastError should return ERROR_SHARING_VIOLATION */
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
success = GetCommState(hComm, &dcb);
if (!success)
{
fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", (int) GetLastError());
return EXIT_FAILURE;
}
fprintf(stderr, "BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n",
(int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits);
ZeroMemory(&commProp, sizeof(COMMPROP));
if (!GetCommProperties(hComm, &commProp))
{
fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x0.8x\n", GetLastError());
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_57600) <= 0)
{
fprintf(stderr, "BAUD_57600 unsupported!\n");
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_14400) > 0)
{
fprintf(stderr, "BAUD_14400 supported!\n");
return EXIT_FAILURE;
}
dcb.BaudRate = CBR_57600;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
success = SetCommState(hComm, &dcb);
if (!success)
{
fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError());
return EXIT_FAILURE;
}
success = GetCommState(hComm, &dcb);
if (!success)
{
fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", (int) GetLastError());
return 0;
}
if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) || (dcb.StopBits != ONESTOPBIT))
{
fprintf(stderr, "Got an unexpeted value among: BaudRate: %d ByteSize: %d Parity: %d StopBits: %d\n",
(int) dcb.BaudRate, (int) dcb.ByteSize, (int) dcb.Parity, (int) dcb.StopBits);
}
CloseHandle(hComm);
return 0;
}

View File

@ -0,0 +1,115 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <winpr/comm.h>
#include <winpr/tchar.h>
static int test_CommDevice(LPCTSTR lpDeviceName, BOOL expectedResult)
{
BOOL result;
TCHAR lpTargetPath[MAX_PATH];
DWORD tcslen;
result = DefineCommDevice(lpDeviceName, _T("/dev/test"));
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
{
_tprintf(_T("DefineCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName,
(expectedResult ? "TRUE" : "FALSE"),
(result ? "TRUE" : "FALSE"));
return FALSE;
}
result = IsCommDevice(lpDeviceName);
if ((!expectedResult && result) || (expectedResult && !result)) /* logical XOR */
{
_tprintf(_T("IsCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName,
(expectedResult ? "TRUE" : "FALSE"),
(result ? "TRUE" : "FALSE"));
return FALSE;
}
tcslen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH);
if (expectedResult)
{
if (tcslen <= _tcslen(lpTargetPath)) /* at least 2 more TCHAR are expected */
{
_tprintf(_T("QueryCommDevice failure: didn't found the device name: %s\n"), lpDeviceName);
return FALSE;
}
if (_tcscmp(_T("/dev/test"), lpTargetPath) != 0)
{
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName, _T("/dev/test"), lpTargetPath);
return FALSE;
}
if (lpTargetPath[_tcslen(lpTargetPath) + 1] != 0)
{
_tprintf(_T("QueryCommDevice failure: device name: %s, the second NULL character is missing at the end of the buffer\n"), lpDeviceName);
return FALSE;
}
}
else
{
if (tcslen > 0)
{
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: <none>, result: %d %s\n"),
lpDeviceName, tcslen, lpTargetPath);
return FALSE;
}
}
return TRUE;
}
int TestCommDevice(int argc, char* argv[])
{
if (!test_CommDevice(_T("COM0"), FALSE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM1"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM1"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("COM10"), FALSE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.\\COM5"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.\\COM10"), TRUE))
return EXIT_FAILURE;
if (!test_CommDevice(_T("\\\\.COM10"), FALSE))
return EXIT_FAILURE;
return 0;
}

View File

@ -0,0 +1,69 @@
#include <winpr/crt.h>
#include <winpr/comm.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#include <winpr/handle.h>
int TestCommMonitor(int argc, char* argv[])
{
HANDLE hComm;
DWORD dwError;
BOOL fSuccess;
DWORD dwEvtMask;
OVERLAPPED overlapped;
LPCSTR lpFileName = "\\\\.\\COM1";
hComm = CreateFileA(lpFileName,
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
printf("CreateFileA failure: %s\n", lpFileName);
return 0;
}
fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR);
if (!fSuccess)
{
printf("SetCommMask failure: GetLastError() = %d\n", (int) GetLastError());
return 0;
}
ZeroMemory(&overlapped, sizeof(OVERLAPPED));
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (WaitCommEvent(hComm, &dwEvtMask, &overlapped))
{
if (dwEvtMask & EV_DSR)
{
printf("EV_DSR\n");
}
if (dwEvtMask & EV_CTS)
{
printf("EV_CTS\n");
}
}
else
{
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
printf("ERROR_IO_PENDING\n");
}
else
{
printf("WaitCommEvent failure: GetLastError() = %d\n", (int) dwError);
return 0;
}
}
CloseHandle(hComm);
return 0;
}

View File

@ -0,0 +1,129 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
int TestControlSettings(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
DCB dcb;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.ByteSize = 5;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = MARKPARITY;
if (!SetCommState(hComm, &dcb))
{
fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY))
{
fprintf(stderr, "test1 failed.\n");
return FALSE;
}
/* Test 2 */
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if (!SetCommState(hComm, &dcb))
{
fprintf(stderr, "SetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY))
{
fprintf(stderr, "test2 failed.\n");
return FALSE;
}
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,136 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_generic(HANDLE hComm)
{
DCB dcb, *pDcb;
BOOL result;
ZeroMemory(&dcb, sizeof(DCB));
result = GetCommState(hComm, &dcb);
if (result)
{
printf("GetCommState failure, should have returned false because dcb.DCBlength has been let uninitialized\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB) / 2; /* improper value */
result = GetCommState(hComm, &dcb);
if (result)
{
printf("GetCommState failure, should have return false because dcb.DCBlength was not correctly initialized\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
result = GetCommState(hComm, &dcb);
if (!result)
{
printf("GetCommState failure: Ox%x, with adjusted DCBlength\n", GetLastError());
return FALSE;
}
pDcb = (DCB*)calloc(1, sizeof(DCB) * 2);
pDcb->DCBlength = sizeof(DCB) * 2;
result = GetCommState(hComm, pDcb);
result = result && (pDcb->DCBlength == sizeof(DCB) * 2);
free(pDcb);
if (!result)
{
printf("GetCommState failure: 0x%x, with bigger DCBlength\n", GetLastError());
return FALSE;
}
return TRUE;
}
int TestGetCommState(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
printf("DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
printf("CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverUnknown)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerialSys)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerCxSys)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
printf("test_generic failure (SerialDriverSerCx2Sys)\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,93 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <termios.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerialSys(HANDLE hComm)
{
// TMP: TODO:
return TRUE;
}
int TestHandflow(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_SerialSys(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */
/* if (!test_SerCxSys(hComm)) */
/* { */
/* fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */
/* if (!test_SerCx2Sys(hComm)) */
/* { */
/* fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,180 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <termios.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerCxSys(HANDLE hComm)
{
DCB dcb;
UCHAR XonChar, XoffChar;
struct termios currentTermios;
ZeroMemory(&currentTermios, sizeof(struct termios));
if (tcgetattr(((WINPR_COMM*)hComm)->fd, &currentTermios) < 0)
{
fprintf(stderr, "tcgetattr failure.\n");
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0'))
{
fprintf(stderr, "test_SerCxSys failure, expected XonChar and XoffChar to be set\n");
return FALSE;
}
/* retrieve Xon/Xoff chars */
if ((dcb.XonChar != currentTermios.c_cc[VSTART]) || (dcb.XoffChar != currentTermios.c_cc[VSTOP]))
{
fprintf(stderr, "test_SerCxSys failure, could not retrieve XonChar and XoffChar\n");
return FALSE;
}
/* swap XonChar/XoffChar */
XonChar = dcb.XonChar;
XoffChar = dcb.XoffChar;
dcb.XonChar = XoffChar;
dcb.XoffChar = XonChar;
if (!SetCommState(hComm, &dcb))
{
fprintf(stderr, "SetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure, GetLastError(): 0x%0.8x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar))
{
fprintf(stderr, "test_SerCxSys, expected XonChar and XoffChar to be swapped\n");
return FALSE;
}
/* same XonChar / XoffChar */
dcb.XonChar = dcb.XoffChar;
if (SetCommState(hComm, &dcb))
{
fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed because XonChar and XoffChar are the same\n");
return FALSE;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
fprintf(stderr, "test_SerCxSys failure, SetCommState() was supposed to failed with GetLastError()=ERROR_INVALID_PARAMETER\n");
return FALSE;
}
return TRUE;
}
static BOOL test_SerCx2Sys(HANDLE hComm)
{
DCB dcb;
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
fprintf(stderr, "GetCommState failure; GetLastError(): %0.8x\n", GetLastError());
return FALSE;
}
if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') || (dcb.XonChar != '\0') || (dcb.XoffChar != '\0'))
{
fprintf(stderr, "test_SerCx2Sys failure, expected all characters to be: '\\0'\n");
return FALSE;
}
return TRUE;
}
int TestSerialChars(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_SerCxSys(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_SerCx2Sys(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,397 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static void init_empty_dcb(DCB *pDcb)
{
ZeroMemory(pDcb, sizeof(DCB));
pDcb->DCBlength = sizeof(DCB);
pDcb->XonChar = 1;
pDcb->XoffChar = 2;
}
static BOOL test_fParity(HANDLE hComm)
{
DCB dcb;
BOOL result;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* test 1 */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity);
return FALSE;
}
/* test 2 */
dcb.fParity = FALSE;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.fParity)
{
fprintf(stderr, "unexpected fParity: %d instead of FALSE\n", dcb.fParity);
return FALSE;
}
/* test 3 (redo test 1) */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
fprintf(stderr, "unexpected fParity: %d instead of TRUE\n", dcb.fParity);
return FALSE;
}
return TRUE;
}
static BOOL test_SerialSys(HANDLE hComm)
{
DCB dcb;
BOOL result;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.BaudRate = SERIAL_BAUD_115200;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != SERIAL_BAUD_115200)
{
fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (SERIAL_BAUD_115200)\n", SERIAL_BAUD_115200);
return FALSE;
}
/* Test 2 using a defferent baud rate */
dcb.BaudRate = SERIAL_BAUD_57600;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != SERIAL_BAUD_57600)
{
fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (SERIAL_BAUD_57600)\n", SERIAL_BAUD_57600);
return FALSE;
}
/* Test 3 using an unsupported baud rate on Linux */
dcb.BaudRate = SERIAL_BAUD_128K;
result = SetCommState(hComm, &dcb);
if (result)
{
fprintf(stderr, "SetCommState failure: unexpected support of BaudRate=%d (SERIAL_BAUD_128K)\n", SERIAL_BAUD_128K);
return FALSE;
}
return TRUE;
}
static BOOL test_SerCxSys(HANDLE hComm)
{
DCB dcb;
BOOL result;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.BaudRate = CBR_115200;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_115200)
{
fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n", CBR_115200);
return FALSE;
}
/* Test 2 using a defferent baud rate */
dcb.BaudRate = CBR_57600;
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_57600)
{
fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_57600)\n", CBR_57600);
return FALSE;
}
/* Test 3 using an unsupported baud rate on Linux */
dcb.BaudRate = CBR_128000;
result = SetCommState(hComm, &dcb);
if (result)
{
fprintf(stderr, "SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n", CBR_128000);
return FALSE;
}
return TRUE;
}
static BOOL test_SerCx2Sys(HANDLE hComm)
{
/* as of today there is no difference */
return test_SerCxSys(hComm);
}
static BOOL test_generic(HANDLE hComm)
{
DCB dcb, dcb2;
BOOL result;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Checks whether we get the same information before and after SetCommState */
memcpy(&dcb2, &dcb, sizeof(DCB));
result = SetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "SetCommState failure: 0x%0.8x\n", GetLastError());
return FALSE;
}
result = GetCommState(hComm, &dcb);
if (!result)
{
fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0)
{
fprintf(stderr, "DCB is different after SetCommState() whereas it should have not changed\n");
return FALSE;
}
// TODO: a more complete and generic test using GetCommProperties()
/* TMP: TODO: fBinary tests */
/* fParity tests */
if (!test_fParity(hComm))
{
fprintf(stderr, "test_fParity failure\n");
return FALSE;
}
return TRUE;
}
int TestSetCommState(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
if (!test_generic(hComm))
{
fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n");
return EXIT_FAILURE;
}
if (!test_SerialSys(hComm))
{
fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n");
return EXIT_FAILURE;
}
if (!test_SerCxSys(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n");
return EXIT_FAILURE;
}
if (!test_SerCx2Sys(hComm))
{
fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,133 @@
/**
* WinPR: Windows Portable Runtime
* Serial Communication API
*
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <sys/stat.h>
#include <termios.h>
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_generic(HANDLE hComm)
{
COMMTIMEOUTS timeouts, timeouts2;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 2;
timeouts.ReadTotalTimeoutConstant = 3;
timeouts.WriteTotalTimeoutMultiplier = 4;
timeouts.WriteTotalTimeoutConstant = 5;
if (!SetCommTimeouts(hComm, &timeouts))
{
fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%0.8x\n", GetLastError());
return FALSE;
}
ZeroMemory(&timeouts2, sizeof(COMMTIMEOUTS));
if (!GetCommTimeouts(hComm, &timeouts2))
{
fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%0.8x\n", GetLastError());
return FALSE;
}
if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0)
{
fprintf(stderr, "TestTimeouts failure, didn't get back the same timeouts.\n");
return FALSE;
}
/* not supported combination */
timeouts.ReadIntervalTimeout = MAXULONG;
timeouts.ReadTotalTimeoutConstant = MAXULONG;
if (SetCommTimeouts(hComm, &timeouts))
{
fprintf(stderr, "SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant set to MAXULONG. GetLastError: 0x%0.8x\n", GetLastError());
return FALSE;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
fprintf(stderr, "SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER and got: 0x%0.8x\n", GetLastError());
return FALSE;
}
return TRUE;
}
int TestTimeouts(int argc, char* argv[])
{
struct stat statbuf;
BOOL result;
HANDLE hComm;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1",
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (hComm == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
fprintf(stderr, "CloseHandle failure, GetLastError()=%0.8x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -3,6 +3,7 @@
* File Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,6 +28,7 @@
#include <winpr/error.h>
#include <winpr/handle.h>
#include <winpr/platform.h>
#include <winpr/collections.h>
#include <winpr/file.h>
@ -40,7 +42,7 @@
/**
* api-ms-win-core-file-l1-2-0.dll:
*
*
* CreateFileA
* CreateFileW
* CreateFile2
@ -148,8 +150,10 @@
#include <unistd.h>
#endif
#include <assert.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -184,6 +188,74 @@
#include "../pipe/pipe.h"
/* TODO: FIXME: use of a wArrayList and split winpr-utils with
* winpr-collections to avoid a circular dependency
* _HandleCreators = ArrayList_New(TRUE);
*/
/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */
#define HANDLE_CREATOR_MAX 128
static HANDLE_CREATOR **_HandleCreators = NULL;
static CRITICAL_SECTION _HandleCreatorsLock;
static pthread_once_t _HandleCreatorsInitialized = PTHREAD_ONCE_INIT;
static void _HandleCreatorsInit()
{
/* NB: error management to be done outside of this function */
assert(_HandleCreators == NULL);
_HandleCreators = (HANDLE_CREATOR**)calloc(HANDLE_CREATOR_MAX+1, sizeof(HANDLE_CREATOR*));
InitializeCriticalSection(&_HandleCreatorsLock);
assert(_HandleCreators != NULL);
}
/**
* Returns TRUE on success, FALSE otherwise.
*
* ERRORS:
* ERROR_DLL_INIT_FAILED
* ERROR_INSUFFICIENT_BUFFER _HandleCreators full
*/
BOOL RegisterHandleCreator(PHANDLE_CREATOR pHandleCreator)
{
int i;
if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
if (_HandleCreators == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return FALSE;
}
EnterCriticalSection(&_HandleCreatorsLock);
for (i=0; i<HANDLE_CREATOR_MAX; i++)
{
if (_HandleCreators[i] == NULL)
{
_HandleCreators[i] = pHandleCreator;
LeaveCriticalSection(&_HandleCreatorsLock);
return TRUE;
}
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
LeaveCriticalSection(&_HandleCreatorsLock);
return FALSE;
}
#ifdef HAVE_AIO_H
static BOOL g_AioSignalHandlerInstalled = FALSE;
@ -213,11 +285,12 @@ int InstallAioSignalHandler()
return 0;
}
#endif
#endif /* HAVE_AIO_H */
HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
int i;
char* name;
int status;
HANDLE hNamedPipe;
@ -227,6 +300,40 @@ HANDLE CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
if (!lpFileName)
return INVALID_HANDLE_VALUE;
if (pthread_once(&_HandleCreatorsInitialized, _HandleCreatorsInit) != 0)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return INVALID_HANDLE_VALUE;
}
if (_HandleCreators == NULL)
{
SetLastError(ERROR_DLL_INIT_FAILED);
return INVALID_HANDLE_VALUE;
}
EnterCriticalSection(&_HandleCreatorsLock);
for (i=0; _HandleCreators[i] != NULL; i++)
{
HANDLE_CREATOR *creator = (HANDLE_CREATOR*)_HandleCreators[i];
if (creator && creator->IsHandled(lpFileName))
{
HANDLE newHandle = creator->CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
LeaveCriticalSection(&_HandleCreatorsLock);
return newHandle;
}
}
LeaveCriticalSection(&_HandleCreatorsLock);
/* TODO: use of a HANDLE_CREATOR for named pipes as well */
if (!IsNamedPipeFileNameA(lpFileName))
return INVALID_HANDLE_VALUE;
name = GetNamedPipeNameWithoutPrefixA(lpFileName);
if (!name)
@ -821,6 +928,14 @@ BOOL CreateDirectoryW(LPCWSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttrib
#define NAMED_PIPE_PREFIX_PATH "\\\\.\\pipe\\"
BOOL IsNamedPipeFileNameA(LPCSTR lpName)
{
if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
return FALSE;
return TRUE;
}
char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
{
char* lpFileName;
@ -828,7 +943,7 @@ char* GetNamedPipeNameWithoutPrefixA(LPCSTR lpName)
if (!lpName)
return NULL;
if (strncmp(lpName, NAMED_PIPE_PREFIX_PATH, sizeof(NAMED_PIPE_PREFIX_PATH) - 1) != 0)
if (!IsNamedPipeFileNameA(lpName))
return NULL;
lpFileName = _strdup(&lpName[strlen(NAMED_PIPE_PREFIX_PATH)]);

View File

@ -25,9 +25,13 @@
#ifndef _WIN32
#include <assert.h>
#include <pthread.h>
#include "../synch/synch.h"
#include "../thread/thread.h"
#include "../pipe/pipe.h"
#include "../comm/comm.h"
#include "../security/security.h"
#ifdef HAVE_UNISTD_H
@ -38,14 +42,98 @@
#include "../handle/handle.h"
/* _HandleCreators is a NULL-terminated array with a maximun of HANDLE_CREATOR_MAX HANDLE_CREATOR */
#define HANDLE_CLOSE_CB_MAX 128
static HANDLE_CLOSE_CB **_HandleCloseCbs = NULL;
static CRITICAL_SECTION _HandleCloseCbsLock;
static pthread_once_t _HandleCloseCbsInitialized = PTHREAD_ONCE_INIT;
static void _HandleCloseCbsInit()
{
/* NB: error management to be done outside of this function */
assert(_HandleCloseCbs == NULL);
_HandleCloseCbs = (HANDLE_CLOSE_CB**)calloc(HANDLE_CLOSE_CB_MAX+1, sizeof(HANDLE_CLOSE_CB*));
InitializeCriticalSection(&_HandleCloseCbsLock);
assert(_HandleCloseCbs != NULL);
}
/**
* Returns TRUE on success, FALSE otherwise.
*/
BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleCloseCb)
{
int i;
if (pthread_once(&_HandleCloseCbsInitialized, _HandleCloseCbsInit) != 0)
{
return FALSE;
}
if (_HandleCloseCbs == NULL)
{
return FALSE;
}
EnterCriticalSection(&_HandleCloseCbsLock);
for (i=0; i<HANDLE_CLOSE_CB_MAX; i++)
{
if (_HandleCloseCbs[i] == NULL)
{
_HandleCloseCbs[i] = pHandleCloseCb;
LeaveCriticalSection(&_HandleCloseCbsLock);
return TRUE;
}
}
LeaveCriticalSection(&_HandleCloseCbsLock);
return FALSE;
}
BOOL CloseHandle(HANDLE hObject)
{
int i;
ULONG Type;
PVOID Object;
if (!winpr_Handle_GetInfo(hObject, &Type, &Object))
return FALSE;
if (pthread_once(&_HandleCloseCbsInitialized, _HandleCloseCbsInit) != 0)
{
return FALSE;
}
if (_HandleCloseCbs == NULL)
{
return FALSE;
}
EnterCriticalSection(&_HandleCloseCbsLock);
for (i=0; _HandleCloseCbs[i] != NULL; i++)
{
HANDLE_CLOSE_CB *close_cb = (HANDLE_CLOSE_CB*)_HandleCloseCbs[i];
if (close_cb && close_cb->IsHandled(hObject))
{
BOOL result = close_cb->CloseHandle(hObject);
LeaveCriticalSection(&_HandleCloseCbsLock);
return result;
}
}
LeaveCriticalSection(&_HandleCloseCbsLock);
if (Type == HANDLE_TYPE_THREAD)
{
WINPR_THREAD* thread;
@ -199,6 +287,8 @@ BOOL CloseHandle(HANDLE hObject)
free(token->Domain);
free(token);
return TRUE;
}
return FALSE;

View File

@ -36,6 +36,7 @@
#define HANDLE_TYPE_FILE 10
#define HANDLE_TYPE_TIMER_QUEUE 11
#define HANDLE_TYPE_TIMER_QUEUE_TIMER 12
#define HANDLE_TYPE_COMM 13
#define WINPR_HANDLE_DEF() \
ULONG Type
@ -64,4 +65,16 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj
return TRUE;
}
typedef BOOL (*pcIsHandled)(HANDLE handle);
typedef BOOL (*pcCloseHandle)(HANDLE handle);
typedef struct _HANDLE_CLOSE_CB
{
pcIsHandled IsHandled;
pcCloseHandle CloseHandle;
} HANDLE_CLOSE_CB;
BOOL RegisterHandleCloseCb(HANDLE_CLOSE_CB *pHandleClose);
#endif /* WINPR_HANDLE_PRIVATE_H */

View File

@ -18,7 +18,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-interlocked)
MODULES winpr-interlocked winpr-synch)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})

View File

@ -3,6 +3,7 @@
* Synchronization Functions
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Hardening <contact@hardening-consulting.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,6 +26,14 @@
#include <unistd.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else
#ifndef _WIN32
#include <sys/select.h>
#endif
#endif
#include <assert.h>
#include <errno.h>
@ -164,6 +173,47 @@ static void ts_add_ms(struct timespec *ts, DWORD dwMilliseconds)
ts->tv_nsec = ts->tv_nsec % 1000000000L;
}
static int waitOnFd(int fd, DWORD dwMilliseconds)
{
int status;
#ifdef HAVE_POLL_H
struct pollfd pollfds;
pollfds.fd = fd;
pollfds.events = POLLIN;
pollfds.revents = 0;
do
{
status = poll(&pollfds, 1, dwMilliseconds);
}
while ((status < 0) && (errno == EINTR));
#else
struct timeval timeout;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
do
{
status = select(fd + 1, &rfds, NULL, NULL, (dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && (errno == EINTR));
#endif
return status;
}
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{
ULONG Type;
@ -256,29 +306,11 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
else if (Type == HANDLE_TYPE_EVENT)
{
int status;
fd_set rfds;
WINPR_EVENT* event;
struct timeval timeout;
event = (WINPR_EVENT*) Object;
FD_ZERO(&rfds);
FD_SET(event->pipe_fd[0], &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
do
{
status = select(event->pipe_fd[0] + 1, &rfds, NULL, NULL,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && (errno == EINTR));
status = waitOnFd(event->pipe_fd[0], dwMilliseconds);
if (status < 0)
{
fprintf(stderr, "WaitForSingleObject: event select() failure [%d] %s\n", errno, strerror(errno));
@ -299,26 +331,8 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{
int status;
int length;
fd_set rfds;
struct timeval timeout;
FD_ZERO(&rfds);
FD_SET(semaphore->pipe_fd[0], &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
do
{
status = select(semaphore->pipe_fd[0] + 1, &rfds, 0, 0,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && (errno == EINTR));
status = waitOnFd(semaphore->pipe_fd[0], dwMilliseconds);
if (status < 0)
{
fprintf(stderr, "WaitForSingleObject: semaphore select() failure [%d] %s\n", errno, strerror(errno));
@ -356,27 +370,9 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
if (timer->fd != -1)
{
int status;
fd_set rfds;
UINT64 expirations;
struct timeval timeout;
FD_ZERO(&rfds);
FD_SET(timer->fd, &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
do
{
status = select(timer->fd + 1, &rfds, 0, 0,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && (errno == EINTR));
status = waitOnFd(timer->fd, dwMilliseconds);
if (status < 0)
{
fprintf(stderr, "WaitForSingleObject: timer select() failure [%d] %s\n", errno, strerror(errno));
@ -420,8 +416,6 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{
int fd;
int status;
fd_set rfds;
struct timeval timeout;
WINPR_NAMED_PIPE* pipe = (WINPR_NAMED_PIPE*) Object;
fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
@ -432,23 +426,7 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
return WAIT_FAILED;
}
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
ZeroMemory(&timeout, sizeof(timeout));
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
timeout.tv_usec = (dwMilliseconds % 1000) * 1000;
}
do
{
status = select(fd + 1, &rfds, NULL, NULL,
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && (errno == EINTR));
status = waitOnFd(fd, dwMilliseconds);
if (status < 0)
{
fprintf(stderr, "WaitForSingleObject: named pipe select() failure [%d] %s\n", errno, strerror(errno));
@ -475,30 +453,41 @@ DWORD WaitForSingleObjectEx(HANDLE hHandle, DWORD dwMilliseconds, BOOL bAlertabl
return WAIT_OBJECT_0;
}
#define MAXIMUM_WAIT_OBJECTS 64
DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAll, DWORD dwMilliseconds)
{
int fd = -1;
int maxfd;
int index;
int status;
fd_set fds;
ULONG Type;
PVOID Object;
#ifdef HAVE_POLL_H
struct pollfd *pollfds;
#else
int maxfd;
fd_set fds;
struct timeval timeout;
#endif
if (!nCount)
if (!nCount || (nCount > MAXIMUM_WAIT_OBJECTS))
{
fprintf(stderr, "WaitForMultipleObjects: invalid handles count\n");
fprintf(stderr, "%s: invalid handles count(%d)\n", __FUNCTION__, nCount);
return WAIT_FAILED;
}
#ifdef HAVE_POLL_H
pollfds = alloca(nCount * sizeof(struct pollfd));
#else
maxfd = 0;
FD_ZERO(&fds);
ZeroMemory(&timeout, sizeof(timeout));
#endif
if (bWaitAll)
{
fprintf(stderr, "WaitForMultipleObjects: bWaitAll not yet implemented\n");
fprintf(stderr, "%s: bWaitAll not yet implemented\n", __FUNCTION__);
assert(0);
}
@ -506,7 +495,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
{
if (!winpr_Handle_GetInfo(lpHandles[index], &Type, &Object))
{
fprintf(stderr, "WaitForMultipleObjects: invalid handle\n");
fprintf(stderr, "%s: invalid handle\n", __FUNCTION__);
return WAIT_FAILED;
}
@ -517,7 +506,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (fd == -1)
{
fprintf(stderr, "WaitForMultipleObjects: invalid event file descriptor\n");
fprintf(stderr, "%s: invalid event file descriptor\n", __FUNCTION__);
return WAIT_FAILED;
}
}
@ -526,7 +515,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
#ifdef WINPR_PIPE_SEMAPHORE
fd = ((WINPR_SEMAPHORE*) Object)->pipe_fd[0];
#else
fprintf(stderr, "WaitForMultipleObjects: semaphore not supported\n");
fprintf(stderr, "%s: semaphore not supported\n", __FUNCTION__);
return WAIT_FAILED;
#endif
}
@ -537,7 +526,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (fd == -1)
{
fprintf(stderr, "WaitForMultipleObjects: invalid timer file descriptor\n");
fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__);
return WAIT_FAILED;
}
}
@ -548,28 +537,41 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (fd == -1)
{
fprintf(stderr, "WaitForMultipleObjects: invalid timer file descriptor\n");
fprintf(stderr, "%s: invalid timer file descriptor\n", __FUNCTION__);
return WAIT_FAILED;
}
}
else
{
fprintf(stderr, "WaitForMultipleObjects: unknown handle type %d\n", (int) Type);
fprintf(stderr, "%s: unknown handle type %d\n", __FUNCTION__, (int) Type);
return WAIT_FAILED;
}
if (fd == -1)
{
fprintf(stderr, "WaitForMultipleObjects: invalid file descriptor\n");
fprintf(stderr, "%s: invalid file descriptor\n", __FUNCTION__);
return WAIT_FAILED;
}
#ifdef HAVE_POLL_H
pollfds[index].fd = fd;
pollfds[index].events = POLLIN;
pollfds[index].revents = 0;
#else
FD_SET(fd, &fds);
if (fd > maxfd)
maxfd = fd;
#endif
}
#ifdef HAVE_POLL_H
do
{
status = poll(pollfds, nCount, dwMilliseconds);
}
while (status < 0 && errno == EINTR);
#else
if ((dwMilliseconds != INFINITE) && (dwMilliseconds != 0))
{
timeout.tv_sec = dwMilliseconds / 1000;
@ -582,10 +584,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
(dwMilliseconds == INFINITE) ? NULL : &timeout);
}
while (status < 0 && errno == EINTR);
#endif
if (status < 0)
{
fprintf(stderr, "WaitForMultipleObjects: select() failure [%d] %s\n", errno, strerror(errno));
fprintf(stderr, "%s: select() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno));
return WAIT_FAILED;
}
@ -615,7 +618,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
fd = (pipe->ServerMode) ? pipe->serverfd : pipe->clientfd;
}
#ifdef HAVE_POLL_H
if (pollfds[index].revents & POLLIN)
#else
if (FD_ISSET(fd, &fds))
#endif
{
if (Type == HANDLE_TYPE_SEMAPHORE)
{
@ -625,7 +632,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (length != 1)
{
fprintf(stderr, "WaitForMultipleObjects: semaphore read() failure [%d] %s\n", errno, strerror(errno));
fprintf(stderr, "%s: semaphore read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno));
return WAIT_FAILED;
}
}
@ -643,11 +650,11 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
if (errno == ETIMEDOUT)
return WAIT_TIMEOUT;
fprintf(stderr, "WaitForMultipleObjects: timer read() failure [%d] %s\n", errno, strerror(errno));
fprintf(stderr, "%s: timer read() failure [%d] %s\n", __FUNCTION__, errno, strerror(errno));
}
else
{
fprintf(stderr, "WaitForMultipleObjects: timer read() failure - incorrect number of bytes read");
fprintf(stderr, "%s: timer read() failure - incorrect number of bytes read", __FUNCTION__);
}
return WAIT_FAILED;
@ -658,7 +665,7 @@ DWORD WaitForMultipleObjects(DWORD nCount, const HANDLE* lpHandles, BOOL bWaitAl
}
}
fprintf(stderr, "WaitForMultipleObjects: failed (unknown error)\n");
fprintf(stderr, "%s: failed (unknown error)\n", __FUNCTION__);
return WAIT_FAILED;
}
@ -677,3 +684,4 @@ DWORD SignalObjectAndWait(HANDLE hObjectToSignal, HANDLE hObjectToWaitOn, DWORD
}
#endif

View File

@ -23,7 +23,6 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <winpr/crt.h>
#include <winpr/print.h>

View File

@ -612,7 +612,11 @@ int _select(int nfds, fd_set* readfds, fd_set* writefds, fd_set* exceptfds, cons
{
int status;
status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout);
do
{
status = select(nfds, readfds, writefds, exceptfds, (struct timeval*) timeout);
}
while ((status < 0) && (errno == EINTR));
return status;
}