Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,34 @@
set(MODULE_NAME "TestComm")
set(MODULE_PREFIX "TEST_COMM")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
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})
target_link_libraries(${MODULE_NAME} winpr)
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})
set_tests_properties(${TestName} PROPERTIES LABELS "comm")
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")

View File

@@ -0,0 +1,151 @@
/**
* 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 = WINPR_C_ARRAY_INIT;
BOOL success = FALSE;
LPCSTR lpFileName = "\\\\.\\COM1";
COMMPROP commProp = WINPR_C_ARRAY_INIT;
struct stat statbuf = WINPR_C_ARRAY_INIT;
HANDLE hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
0, nullptr);
if (hComm && (hComm != INVALID_HANDLE_VALUE))
{
(void)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)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
success = DefineCommDevice(lpFileName, "/dev/ttyS0");
if (!success)
{
(void)fprintf(stderr, "DefineCommDevice failure: %s\n", lpFileName);
return EXIT_FAILURE;
}
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE, /* invalid parameter */
nullptr, CREATE_NEW, /* invalid parameter */
0, (HANDLE)1234); /* invalid parameter */
if (hComm != INVALID_HANDLE_VALUE)
{
(void)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, nullptr, OPEN_EXISTING, 0,
nullptr);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
(void)fprintf(stderr, "CreateFileA failure: %s GetLastError() = 0x%08x\n", lpFileName,
GetLastError());
return EXIT_FAILURE;
}
/* TODO: a second call to CreateFileA should failed and
* GetLastError should return ERROR_SHARING_VIOLATION */
dcb.DCBlength = sizeof(DCB);
success = GetCommState(hComm, &dcb);
if (!success)
{
(void)fprintf(stderr, "GetCommState failure: GetLastError() = Ox%x\n", GetLastError());
return EXIT_FAILURE;
}
(void)fprintf(stderr,
"BaudRate: %" PRIu32 " ByteSize: %" PRIu8 " Parity: %" PRIu8 " StopBits: %" PRIu8
"\n",
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
if (!GetCommProperties(hComm, &commProp))
{
(void)fprintf(stderr, "GetCommProperties failure: GetLastError(): 0x%08x\n",
GetLastError());
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_57600) <= 0)
{
(void)fprintf(stderr, "BAUD_57600 unsupported!\n");
return EXIT_FAILURE;
}
if ((commProp.dwSettableBaud & BAUD_14400) > 0)
{
(void)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)
{
(void)fprintf(stderr, "SetCommState failure: GetLastError() = 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
success = GetCommState(hComm, &dcb);
if (!success)
{
(void)fprintf(stderr, "GetCommState failure: GetLastError() = 0x%x\n", GetLastError());
return 0;
}
if ((dcb.BaudRate != CBR_57600) || (dcb.ByteSize != 8) || (dcb.Parity != NOPARITY) ||
(dcb.StopBits != ONESTOPBIT))
{
(void)fprintf(stderr,
"Got an unexpected value among: BaudRate: %" PRIu32 " ByteSize: %" PRIu8
" Parity: %" PRIu8 " StopBits: %" PRIu8 "\n",
dcb.BaudRate, dcb.ByteSize, dcb.Parity, dcb.StopBits);
}
(void)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)
{
TCHAR lpTargetPath[MAX_PATH] = WINPR_C_ARRAY_INIT;
BOOL 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;
}
const size_t tclen = QueryCommDevice(lpDeviceName, lpTargetPath, MAX_PATH);
if (expectedResult)
{
const size_t tlen = _tcsnlen(lpTargetPath, ARRAYSIZE(lpTargetPath) - 1);
if (tclen <= tlen) /* at least 2 more TCHAR are expected */
{
_tprintf(_T("QueryCommDevice failure: didn't find the device name: %s\n"),
lpDeviceName);
return FALSE;
}
if (_tcsncmp(_T("/dev/test"), lpTargetPath, ARRAYSIZE(lpTargetPath)) != 0)
{
_tprintf(
_T("QueryCommDevice failure: device name: %s, expected result: %s, result: %s\n"),
lpDeviceName, _T("/dev/test"), lpTargetPath);
return FALSE;
}
if ((tlen >= (ARRAYSIZE(lpTargetPath) - 1)) || (lpTargetPath[tlen + 1] != 0))
{
_tprintf(
_T("QueryCommDevice failure: device name: %s, the second nullptr character is ")
_T("missing at the end of the buffer\n"),
lpDeviceName);
return FALSE;
}
}
else
{
if (tclen > 0)
{
_tprintf(_T("QueryCommDevice failure: device name: %s, expected result: <none>, ")
_T("result: %") _T(PRIuz) _T(" %s\n"),
lpDeviceName, tclen, 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,70 @@
#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 = nullptr;
DWORD dwError = 0;
BOOL fSuccess = 0;
DWORD dwEvtMask = 0;
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
LPCSTR lpFileName = "\\\\.\\COM1";
hComm = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, nullptr);
if (!hComm || (hComm == INVALID_HANDLE_VALUE))
{
printf("CreateFileA failure: %s\n", lpFileName);
return -1;
}
fSuccess = SetCommMask(hComm, EV_CTS | EV_DSR);
if (!fSuccess)
{
printf("SetCommMask failure: GetLastError() = %" PRIu32 "\n", GetLastError());
return -1;
}
if (!(overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
{
printf("CreateEvent failed: GetLastError() = %" PRIu32 "\n", GetLastError());
return -1;
}
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() = %" PRIu32 "\n", dwError);
return -1;
}
}
(void)CloseHandle(hComm);
return 0;
}

View File

@@ -0,0 +1,123 @@
/**
* 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 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
DCB dcb = WINPR_C_ARRAY_INIT;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.ByteSize = 5;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = MARKPARITY;
if (!SetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 5) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != MARKPARITY))
{
(void)fprintf(stderr, "test1 failed.\n");
return FALSE;
}
/* Test 2 */
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if (!SetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "SetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ByteSize != 8) || (dcb.StopBits != ONESTOPBIT) || (dcb.Parity != NOPARITY))
{
(void)fprintf(stderr, "test2 failed.\n");
return FALSE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,140 @@
/**
* 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 = WINPR_C_ARRAY_INIT;
DCB* pDcb = nullptr;
BOOL result = 0;
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(2, sizeof(DCB));
if (!pDcb)
return FALSE;
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 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)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 =
CreateFileA("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
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))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,92 @@
/**
* 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>
#ifndef _WIN32
#include <termios.h>
#endif
#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 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_SerialSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCxSys); */
/* if (!test_SerCxSys(hComm)) */
/* { */
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
/* _comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys); */
/* if (!test_SerCx2Sys(hComm)) */
/* { */
/* (void)fprintf(stderr, "test_SerCxSys failure\n"); */
/* return EXIT_FAILURE; */
/* } */
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\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>
#ifndef _WIN32
#include <termios.h>
#endif
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_SerCxSys(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
UCHAR XonChar = 0;
UCHAR XoffChar = 0;
struct termios currentTermios = WINPR_C_ARRAY_INIT;
if (tcgetattr(((WINPR_COMM*)hComm)->fd, &currentTermios) < 0)
{
(void)fprintf(stderr, "tcgetattr failure.\n");
return FALSE;
}
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar == '\0') || (dcb.XoffChar == '\0'))
{
(void)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]))
{
(void)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))
{
(void)fprintf(stderr, "SetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
ZeroMemory(&dcb, sizeof(DCB));
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure, GetLastError(): 0x%08x\n", GetLastError());
return FALSE;
}
if ((dcb.XonChar != XoffChar) || (dcb.XoffChar != XonChar))
{
(void)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))
{
(void)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)
{
(void)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 = WINPR_C_ARRAY_INIT;
dcb.DCBlength = sizeof(DCB);
if (!GetCommState(hComm, &dcb))
{
(void)fprintf(stderr, "GetCommState failure; GetLastError(): %08x\n", GetLastError());
return FALSE;
}
if ((dcb.ErrorChar != '\0') || (dcb.EofChar != '\0') || (dcb.EvtChar != '\0') ||
(dcb.XonChar != '\0') || (dcb.XoffChar != '\0'))
{
(void)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 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_SerCxSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_SerCx2Sys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,335 @@
/**
* 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)
{
WINPR_ASSERT(pDcb);
ZeroMemory(pDcb, sizeof(DCB));
pDcb->DCBlength = sizeof(DCB);
pDcb->XonChar = 1;
pDcb->XoffChar = 2;
}
static BOOL test_fParity(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
/* test 1 */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
return FALSE;
}
/* test 2 */
dcb.fParity = FALSE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of FALSE\n", dcb.fParity);
return FALSE;
}
/* test 3 (redo test 1) */
dcb.fParity = TRUE;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%08" PRIx32 "\n", GetLastError());
return FALSE;
}
if (!dcb.fParity)
{
(void)fprintf(stderr, "unexpected fParity: %" PRIu32 " instead of TRUE\n", dcb.fParity);
return FALSE;
}
return TRUE;
}
static BOOL test_SerialSys(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
/* Test 1 */
dcb.BaudRate = CBR_115200;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_115200)
{
(void)fprintf(stderr, "SetCommState failure: could not set BaudRate=%d (CBR_115200)\n",
CBR_115200);
return FALSE;
}
/* Test 2 using a different baud rate */
dcb.BaudRate = CBR_57600;
result = SetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "SetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (dcb.BaudRate != CBR_57600)
{
(void)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)
{
(void)fprintf(stderr,
"SetCommState failure: unexpected support of BaudRate=%d (CBR_128000)\n",
CBR_128000);
return FALSE;
}
return TRUE;
}
static BOOL test_SerCxSys(HANDLE hComm)
{
/* as of today there is no difference */
return test_SerialSys(hComm);
}
static BOOL test_SerCx2Sys(HANDLE hComm)
{
/* as of today there is no difference */
return test_SerialSys(hComm);
}
static BOOL test_generic(HANDLE hComm)
{
DCB dcb = WINPR_C_ARRAY_INIT;
DCB dcb2 = WINPR_C_ARRAY_INIT;
BOOL result = 0;
init_empty_dcb(&dcb);
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)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)
{
(void)fprintf(stderr, "SetCommState failure: 0x%08x\n", GetLastError());
return FALSE;
}
result = GetCommState(hComm, &dcb);
if (!result)
{
(void)fprintf(stderr, "GetCommState failure: 0x%x\n", GetLastError());
return FALSE;
}
if (memcmp(&dcb, &dcb2, sizeof(DCB)) != 0)
{
(void)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))
{
(void)fprintf(stderr, "test_fParity failure\n");
return FALSE;
}
return TRUE;
}
int TestSetCommState(int argc, char* argv[])
{
struct stat statbuf = WINPR_C_ARRAY_INIT;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverUnknown)\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerialSys)\n");
return EXIT_FAILURE;
}
if (!test_SerialSys(hComm))
{
(void)fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCxSys)\n");
return EXIT_FAILURE;
}
if (!test_SerCxSys(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_generic failure (SerialDriverSerCx2Sys)\n");
return EXIT_FAILURE;
}
if (!test_SerCx2Sys(hComm))
{
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,141 @@
/**
* 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>
#ifndef _WIN32
#include <termios.h>
#endif
#include <winpr/comm.h>
#include <winpr/crt.h>
#include "../comm.h"
static BOOL test_generic(HANDLE hComm)
{
COMMTIMEOUTS timeouts = WINPR_C_ARRAY_INIT;
COMMTIMEOUTS timeouts2 = WINPR_C_ARRAY_INIT;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 2;
timeouts.ReadTotalTimeoutConstant = 3;
timeouts.WriteTotalTimeoutMultiplier = 4;
timeouts.WriteTotalTimeoutConstant = 5;
if (!SetCommTimeouts(hComm, &timeouts))
{
(void)fprintf(stderr, "SetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
return FALSE;
}
if (!GetCommTimeouts(hComm, &timeouts2))
{
(void)fprintf(stderr, "GetCommTimeouts failure, GetLastError: 0x%08x\n", GetLastError());
return FALSE;
}
if (memcmp(&timeouts, &timeouts2, sizeof(COMMTIMEOUTS)) != 0)
{
(void)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))
{
(void)fprintf(
stderr,
"SetCommTimeouts succeeded with ReadIntervalTimeout and ReadTotalTimeoutConstant "
"set to MAXULONG. GetLastError: 0x%08x\n",
GetLastError());
return FALSE;
}
if (GetLastError() != ERROR_INVALID_PARAMETER)
{
(void)fprintf(
stderr,
"SetCommTimeouts failure, expected GetLastError to return ERROR_INVALID_PARAMETER "
"and got: 0x%08x\n",
GetLastError());
return FALSE;
}
return TRUE;
}
int TestTimeouts(int argc, char* argv[])
{
struct stat statbuf;
BOOL result = 0;
HANDLE hComm = nullptr;
if (stat("/dev/ttyS0", &statbuf) < 0)
{
(void)fprintf(stderr, "/dev/ttyS0 not available, making the test to succeed though\n");
return EXIT_SUCCESS;
}
result = DefineCommDevice("COM1", "/dev/ttyS0");
if (!result)
{
(void)fprintf(stderr, "DefineCommDevice failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (hComm == INVALID_HANDLE_VALUE)
{
(void)fprintf(stderr, "CreateFileA failure: 0x%x\n", GetLastError());
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerialSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerialSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCxSys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerCxSys failure\n");
return EXIT_FAILURE;
}
_comm_setServerSerialDriver(hComm, SerialDriverSerCx2Sys);
if (!test_generic(hComm))
{
(void)fprintf(stderr, "test_SerCx2Sys failure\n");
return EXIT_FAILURE;
}
if (!CloseHandle(hComm))
{
(void)fprintf(stderr, "CloseHandle failure, GetLastError()=%08x\n", GetLastError());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}