VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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