VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/utils/TestExecServ/TestExecServiceSerial.cpp@ 90802

Last change on this file since 90802 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: TestExecServiceSerial.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * TestExecServ - Basic Remote Execution Service, Serial port Transport Layer.
4 */
5
6/*
7 * Copyright (C) 2018-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_DEFAULT
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/err.h>
35#include <iprt/log.h>
36#include <iprt/mem.h>
37#include <iprt/message.h>
38#include <iprt/string.h>
39#include <iprt/serialport.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42
43#include "TestExecServiceInternal.h"
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49/** The default baud rate port. */
50#define TXS_SERIAL_DEF_BAUDRATE 115200
51/** The default serial device to use. */
52#if defined(RT_OS_LINUX)
53# define TXS_SERIAL_DEF_DEVICE "/dev/ttyS0"
54#elif defined(RT_OS_WINDOWS)
55# define TXS_SERIAL_DEF_DEVICE "COM1"
56#elif defined(RT_OS_SOLARIS)
57# define TXS_SERIAL_DEF_DEVICE "<todo>"
58#elif defined(RT_OS_FREEBSD)
59# define TXS_SERIAL_DEF_DEVICE "<todo>"
60#elif defined(RT_OS_DARWIN)
61# define TXS_SERIAL_DEF_DEVICE "<todo>"
62#else
63# error "Port me"
64#endif
65
66
67/*********************************************************************************************************************************
68* Global Variables *
69*********************************************************************************************************************************/
70/** @name Serial Parameters
71 * @{ */
72/** The addresses to bind to. Empty string means any. */
73static uint32_t g_uSerialBaudRate = TXS_SERIAL_DEF_BAUDRATE;
74/** The serial port device to use. */
75static char g_szSerialDevice[256] = TXS_SERIAL_DEF_DEVICE;
76/** @} */
77
78/** The serial port handle. */
79static RTSERIALPORT g_hSerialPort = NIL_RTSERIALPORT;
80/** The size of the stashed data. */
81static size_t g_cbSerialStashed = 0;
82/** The size of the stashed data allocation. */
83static size_t g_cbSerialStashedAlloced = 0;
84/** The stashed data. */
85static uint8_t *g_pbSerialStashed = NULL;
86
87
88
89/**
90 * @interface_method_impl{TXSTRANSPORT,pfnNotifyReboot}
91 */
92static DECLCALLBACK(void) txsSerialNotifyReboot(void)
93{
94 /* nothing to do here */
95}
96
97/**
98 * @interface_method_impl{TXSTRANSPORT,pfnNotifyBye}
99 */
100static DECLCALLBACK(void) txsSerialNotifyBye(void)
101{
102 /* nothing to do here */
103}
104
105/**
106 * @interface_method_impl{TXSTRANSPORT,pfnNotifyHowdy}
107 */
108static DECLCALLBACK(void) txsSerialNotifyHowdy(void)
109{
110 /* nothing to do here */
111}
112
113/**
114 * @interface_method_impl{TXSTRANSPORT,pfnBabble}
115 */
116static DECLCALLBACK(void) txsSerialBabble(PCTXSPKTHDR pPktHdr, RTMSINTERVAL cMsSendTimeout)
117{
118 Assert(g_hSerialPort != NIL_RTSERIALPORT);
119
120 /*
121 * Try send the babble reply.
122 */
123 NOREF(cMsSendTimeout); /** @todo implement the timeout here; non-blocking write + select-on-write. */
124 int rc;
125 size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
126 do rc = RTSerialPortWrite(g_hSerialPort, pPktHdr, cbToSend, NULL);
127 while (rc == VERR_INTERRUPTED);
128
129 /*
130 * Disconnect the client.
131 */
132 Log(("txsSerialBabble: RTSerialPortWrite rc=%Rrc\n", rc));
133}
134
135/**
136 * @interface_method_impl{TXSTRANSPORT,pfnSendPkt}
137 */
138static DECLCALLBACK(int) txsSerialSendPkt(PCTXSPKTHDR pPktHdr)
139{
140 Assert(g_hSerialPort != NIL_RTSERIALPORT);
141 Assert(pPktHdr->cb >= sizeof(TXSPKTHDR));
142
143 /*
144 * Write it.
145 */
146 size_t cbToSend = RT_ALIGN_Z(pPktHdr->cb, TXSPKT_ALIGNMENT);
147 int rc = RTSerialPortWrite(g_hSerialPort, pPktHdr, cbToSend, NULL);
148 if ( RT_FAILURE(rc)
149 && rc != VERR_INTERRUPTED)
150 {
151 /* assume fatal connection error. */
152 Log(("RTSerialPortWrite -> %Rrc\n", rc));
153 }
154
155 return rc;
156}
157
158/**
159 * @interface_method_impl{TXSTRANSPORT,pfnRecvPkt}
160 */
161static DECLCALLBACK(int) txsSerialRecvPkt(PPTXSPKTHDR ppPktHdr)
162{
163 Assert(g_hSerialPort != NIL_RTSERIALPORT);
164
165 int rc = VINF_SUCCESS;
166 *ppPktHdr = NULL;
167
168 /*
169 * Read state.
170 */
171 size_t offData = 0;
172 size_t cbData = 0;
173 size_t cbDataAlloced;
174 uint8_t *pbData = NULL;
175
176 /*
177 * Any stashed data?
178 */
179 if (g_cbSerialStashedAlloced)
180 {
181 offData = g_cbSerialStashed;
182 cbDataAlloced = g_cbSerialStashedAlloced;
183 pbData = g_pbSerialStashed;
184
185 g_cbSerialStashed = 0;
186 g_cbSerialStashedAlloced = 0;
187 g_pbSerialStashed = NULL;
188 }
189 else
190 {
191 cbDataAlloced = RT_ALIGN_Z(64, TXSPKT_ALIGNMENT);
192 pbData = (uint8_t *)RTMemAlloc(cbDataAlloced);
193 if (!pbData)
194 return VERR_NO_MEMORY;
195 }
196
197 /*
198 * Read and valid the length.
199 */
200 while (offData < sizeof(uint32_t))
201 {
202 size_t cbRead = sizeof(uint32_t) - offData;
203 rc = RTSerialPortRead(g_hSerialPort, pbData + offData, cbRead, NULL);
204 if (RT_FAILURE(rc))
205 break;
206 offData += cbRead;
207 }
208 if (RT_SUCCESS(rc))
209 {
210 ASMCompilerBarrier(); /* paranoia^3 */
211 cbData = *(uint32_t volatile *)pbData;
212 if (cbData >= sizeof(TXSPKTHDR) && cbData <= TXSPKT_MAX_SIZE)
213 {
214 /*
215 * Align the length and reallocate the return packet it necessary.
216 */
217 cbData = RT_ALIGN_Z(cbData, TXSPKT_ALIGNMENT);
218 if (cbData > cbDataAlloced)
219 {
220 void *pvNew = RTMemRealloc(pbData, cbData);
221 if (pvNew)
222 {
223 pbData = (uint8_t *)pvNew;
224 cbDataAlloced = cbData;
225 }
226 else
227 rc = VERR_NO_MEMORY;
228 }
229 if (RT_SUCCESS(rc))
230 {
231 /*
232 * Read the remainder of the data.
233 */
234 while (offData < cbData)
235 {
236 size_t cbRead = cbData - offData;
237 rc = RTSerialPortRead(g_hSerialPort, pbData + offData, cbRead, NULL);
238 if (RT_FAILURE(rc))
239 break;
240 offData += cbRead;
241 }
242 }
243 }
244 else
245 rc = VERR_NET_PROTOCOL_ERROR;
246 }
247 if (RT_SUCCESS(rc))
248 *ppPktHdr = (PTXSPKTHDR)pbData;
249 else
250 {
251 /*
252 * Deal with errors.
253 */
254 if (rc == VERR_INTERRUPTED)
255 {
256 /* stash it away for the next call. */
257 g_cbSerialStashed = cbData;
258 g_cbSerialStashedAlloced = cbDataAlloced;
259 g_pbSerialStashed = pbData;
260 }
261 else
262 {
263 RTMemFree(pbData);
264
265 /* assume fatal connection error. */
266 Log(("txsSerialRecvPkt: RTSerialPortRead -> %Rrc\n", rc));
267 }
268 }
269
270 return rc;
271}
272
273/**
274 * @interface_method_impl{TXSTRANSPORT,pfnPollIn}
275 */
276static DECLCALLBACK(bool) txsSerialPollIn(void)
277{
278 Assert(g_hSerialPort != NIL_RTSERIALPORT);
279
280 uint32_t fEvtsRecv = 0;
281 int rc = RTSerialPortEvtPoll(g_hSerialPort, RTSERIALPORT_EVT_F_DATA_RX,
282 &fEvtsRecv, 0/*cMillies*/);
283 return RT_SUCCESS(rc);
284}
285
286/**
287 * @interface_method_impl{TXSTRANSPORT,pfnTerm}
288 */
289static DECLCALLBACK(void) txsSerialTerm(void)
290{
291 if (g_hSerialPort != NIL_RTSERIALPORT)
292 RTSerialPortClose(g_hSerialPort);
293
294 /* Clean up stashing. */
295 if (g_pbSerialStashed)
296 RTMemFree(g_pbSerialStashed);
297 g_pbSerialStashed = NULL;
298 g_cbSerialStashed = 0;
299 g_cbSerialStashedAlloced = 0;
300
301 Log(("txsSerialTerm: done\n"));
302}
303
304/**
305 * @interface_method_impl{TXSTRANSPORT,pfnInit}
306 */
307static DECLCALLBACK(int) txsSerialInit(void)
308{
309 uint32_t fOpenFlags = RTSERIALPORT_OPEN_F_READ | RTSERIALPORT_OPEN_F_WRITE;
310 int rc = RTSerialPortOpen(&g_hSerialPort, &g_szSerialDevice[0], fOpenFlags);
311 if (RT_SUCCESS(rc))
312 {
313 RTSERIALPORTCFG SerPortCfg;
314
315 SerPortCfg.uBaudRate = g_uSerialBaudRate;
316 SerPortCfg.enmParity = RTSERIALPORTPARITY_NONE;
317 SerPortCfg.enmDataBitCount = RTSERIALPORTDATABITS_8BITS;
318 SerPortCfg.enmStopBitCount = RTSERIALPORTSTOPBITS_ONE;
319 rc = RTSerialPortCfgSet(g_hSerialPort, &SerPortCfg, NULL);
320 if (RT_FAILURE(rc))
321 {
322 RTMsgError("RTSerialPortCfgSet() failed: %Rrc\n", rc);
323 RTSerialPortClose(g_hSerialPort);
324 g_hSerialPort = NIL_RTSERIALPORT;
325 }
326 }
327 else
328 RTMsgError("RTSerialPortOpen(, %s, %#x) failed: %Rrc\n",
329 g_szSerialDevice, fOpenFlags, rc);
330
331 return rc;
332}
333
334/** Options */
335enum TXSSERIALOPT
336{
337 TXSSERIALOPT_BAUDRATE = 1000,
338 TXSSERIALOPT_DEVICE
339};
340
341/**
342 * @interface_method_impl{TXSTRANSPORT,pfnOption}
343 */
344static DECLCALLBACK(int) txsSerialOption(int ch, PCRTGETOPTUNION pVal)
345{
346 int rc;
347
348 switch (ch)
349 {
350 case TXSSERIALOPT_DEVICE:
351 rc = RTStrCopy(g_szSerialDevice, sizeof(g_szSerialDevice), pVal->psz);
352 if (RT_FAILURE(rc))
353 return RTMsgErrorRc(VERR_INVALID_PARAMETER, "Serial port device path is too long (%Rrc)", rc);
354 if (!g_szSerialDevice[0])
355 strcpy(g_szSerialDevice, TXS_SERIAL_DEF_DEVICE);
356 return VINF_SUCCESS;
357 case TXSSERIALOPT_BAUDRATE:
358 g_uSerialBaudRate = pVal->u32 == 0 ? TXS_SERIAL_DEF_BAUDRATE : pVal->u32;
359 return VINF_SUCCESS;
360 }
361 return VERR_TRY_AGAIN;
362}
363
364/**
365 * @interface_method_impl{TXSTRANSPORT,pfnUsage}
366 */
367DECLCALLBACK(void) txsSerialUsage(PRTSTREAM pStream)
368{
369 RTStrmPrintf(pStream,
370 " --serial-device <device>\n"
371 " Selects the serial port to use.\n"
372 " Default: %s\n"
373 " --serial-baudrate <baudrate>\n"
374 " Selects the baudrate to set the serial port to.\n"
375 " Default: %u\n"
376 , TXS_SERIAL_DEF_DEVICE, TXS_SERIAL_DEF_BAUDRATE);
377}
378
379/** Command line options for the serial transport layer. */
380static const RTGETOPTDEF g_SerialOpts[] =
381{
382 { "--serial-device", TXSSERIALOPT_DEVICE, RTGETOPT_REQ_STRING },
383 { "--serial-baudrate", TXSSERIALOPT_BAUDRATE, RTGETOPT_REQ_UINT32 }
384};
385
386/** Serial port transport layer. */
387const TXSTRANSPORT g_SerialTransport =
388{
389 /* .szName = */ "serial",
390 /* .pszDesc = */ "Serial",
391 /* .cOpts = */ &g_SerialOpts[0],
392 /* .paOpts = */ RT_ELEMENTS(g_SerialOpts),
393 /* .pfnUsage = */ txsSerialUsage,
394 /* .pfnOption = */ txsSerialOption,
395 /* .pfnInit = */ txsSerialInit,
396 /* .pfnTerm = */ txsSerialTerm,
397 /* .pfnPollIn = */ txsSerialPollIn,
398 /* .pfnPollSetAdd = */ NULL,
399 /* .pfnRecvPkt = */ txsSerialRecvPkt,
400 /* .pfnSendPkt = */ txsSerialSendPkt,
401 /* .pfnBabble = */ txsSerialBabble,
402 /* .pfnNotifyHowdy = */ txsSerialNotifyHowdy,
403 /* .pfnNotifyBye = */ txsSerialNotifyBye,
404 /* .pfnNotifyReboot = */ txsSerialNotifyReboot,
405 /* .u32EndMarker = */ UINT32_C(0x12345678)
406};
407
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette