VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DrvTCP.cpp@ 83584

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

Devices/Serial/DrvTCP: Fix connection handling for the server case and avoid modifying the hTcpSock member from different threads during runtime (was modified from the listen and I/O thread in the server case without using atomics or any protection). Fix timeout handling in the poll handler (wasn't adjusted properly when poll returned for an internal event)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.8 KB
Line 
1/* $Id: DrvTCP.cpp 83584 2020-04-06 09:57:12Z vboxsync $ */
2/** @file
3 * TCP socket driver implementing the IStream interface.
4 */
5
6/*
7 * Contributed by Alexey Eromenko (derived from DrvNamedPipe).
8 *
9 * Copyright (C) 2006-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DRV_TCP
25#include <VBox/vmm/pdmdrv.h>
26#include <iprt/assert.h>
27#include <iprt/file.h>
28#include <iprt/stream.h>
29#include <iprt/alloc.h>
30#include <iprt/pipe.h>
31#include <iprt/poll.h>
32#include <iprt/string.h>
33#include <iprt/semaphore.h>
34#include <iprt/socket.h>
35#include <iprt/tcp.h>
36#include <iprt/uuid.h>
37#include <stdlib.h>
38
39#include "VBoxDD.h"
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45
46#define DRVTCP_POLLSET_ID_SOCKET 0
47#define DRVTCP_POLLSET_ID_WAKEUP 1
48
49#define DRVTCP_WAKEUP_REASON_EXTERNAL 0
50#define DRVTCP_WAKEUP_REASON_NEW_CONNECTION 1
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * TCP driver instance data.
58 *
59 * @implements PDMISTREAM
60 */
61typedef struct DRVTCP
62{
63 /** The stream interface. */
64 PDMISTREAM IStream;
65 /** Pointer to the driver instance. */
66 PPDMDRVINS pDrvIns;
67 /** Pointer to the TCP server address:port or port only. (Freed by MM) */
68 char *pszLocation;
69 /** Flag whether VirtualBox represents the server or client side. */
70 bool fIsServer;
71
72 /** Handle of the TCP server for incoming connections. */
73 PRTTCPSERVER hTcpServ;
74 /** Socket handle of the TCP socket connection. */
75 RTSOCKET hTcpSock;
76
77 /** Poll set used to wait for I/O events. */
78 RTPOLLSET hPollSet;
79 /** Reading end of the wakeup pipe. */
80 RTPIPE hPipeWakeR;
81 /** Writing end of the wakeup pipe. */
82 RTPIPE hPipeWakeW;
83 /** Flag whether the send buffer is full nad it is required to wait for more
84 * space until there is room again. */
85 bool fXmitBufFull;
86
87 /** Number of connections active. */
88 volatile uint32_t cConnections;
89 /** Thread for listening for new connections. */
90 RTTHREAD ListenThread;
91 /** Flag to signal listening thread to shut down. */
92 bool volatile fShutdown;
93} DRVTCP, *PDRVTCP;
94
95
96/*********************************************************************************************************************************
97* Internal Functions *
98*********************************************************************************************************************************/
99
100
101/**
102 * Kicks any possibly polling thread to get informed about changes - extended version
103 * sending additional data along with the wakeup reason.
104 *
105 * @returns VBOx status code.
106 * @param pThis The TCP driver instance.
107 * @param bReason The reason code to handle.
108 * @param pvData The additional to send along with the wakeup reason.
109 * @param cbData Number of bytes to send along.
110 */
111static int drvTcpPollerKickEx(PDRVTCP pThis, uint8_t bReason, const void *pvData, size_t cbData)
112{
113 size_t cbWritten = 0;
114 int rc = RTPipeWriteBlocking(pThis->hPipeWakeW, &bReason, 1, &cbWritten);
115 if (RT_SUCCESS(rc))
116 rc = RTPipeWriteBlocking(pThis->hPipeWakeW, pvData, cbData, &cbWritten);
117 return rc;
118}
119
120
121/**
122 * Kicks any possibly polling thread to get informed about changes.
123 *
124 * @returns VBOx status code.
125 * @param pThis The TCP driver instance.
126 * @param bReason The reason code to handle.
127 */
128static int drvTcpPollerKick(PDRVTCP pThis, uint8_t bReason)
129{
130 size_t cbWritten = 0;
131 return RTPipeWriteBlocking(pThis->hPipeWakeW, &bReason, 1, &cbWritten);
132}
133
134
135/** @interface_method_impl{PDMISTREAM,pfnPoll} */
136static DECLCALLBACK(int) drvTcpPoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)
137{
138 int rc = VINF_SUCCESS;
139 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream);
140
141 if (pThis->hTcpSock != NIL_RTSOCKET)
142 {
143 Assert(ASMAtomicReadU32(&pThis->cConnections) > 0);
144
145 /* Always include error event. */
146 fEvts |= RTPOLL_EVT_ERROR;
147 rc = RTPollSetEventsChange(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET, fEvts);
148 AssertRC(rc);
149 }
150
151 if (RT_SUCCESS(rc))
152 {
153 while (RT_SUCCESS(rc))
154 {
155 uint32_t fEvtsRecv = 0;
156 uint32_t idHnd = 0;
157 uint64_t tsStartMs = RTTimeMilliTS();
158 RTMSINTERVAL cThisWaitMs = cMillies;
159
160 /*
161 * Just check for data available to be read if the send buffer wasn't full till now and
162 * the caller wants to check whether writing is possible with the event set.
163 *
164 * On Windows the write event is only posted after a send operation returned
165 * WSAEWOULDBLOCK. So without this we would block in the poll call below waiting
166 * for an event which would never happen if the buffer has space left.
167 */
168 if ( (fEvts & RTPOLL_EVT_WRITE)
169 && !pThis->fXmitBufFull
170 && pThis->hTcpSock != NIL_RTSOCKET)
171 cThisWaitMs = 0;
172
173 rc = RTPoll(pThis->hPollSet, cThisWaitMs, &fEvtsRecv, &idHnd);
174
175 /* Adjust remaining time to wait. */
176 uint64_t tsPollSpanMs = RTTimeMilliTS() - tsStartMs;
177 cMillies -= RT_MIN(cMillies, tsPollSpanMs);
178 if (RT_SUCCESS(rc))
179 {
180 if (idHnd == DRVTCP_POLLSET_ID_WAKEUP)
181 {
182 /* We got woken up, drain the pipe and return. */
183 uint8_t bReason;
184 size_t cbRead = 0;
185 rc = RTPipeRead(pThis->hPipeWakeR, &bReason, 1, &cbRead);
186 AssertRC(rc);
187
188 if (bReason == DRVTCP_WAKEUP_REASON_EXTERNAL)
189 rc = VERR_INTERRUPTED;
190 else if (bReason == DRVTCP_WAKEUP_REASON_NEW_CONNECTION)
191 {
192 Assert(pThis->hTcpSock == NIL_RTSOCKET);
193
194 /* Read the socket handle. */
195 RTSOCKET hTcpSockNew = NIL_RTSOCKET;
196 rc = RTPipeReadBlocking(pThis->hPipeWakeR, &hTcpSockNew, sizeof(hTcpSockNew), NULL);
197 AssertRC(rc);
198
199 /* Always include error event. */
200 fEvts |= RTPOLL_EVT_ERROR;
201 rc = RTPollSetAddSocket(pThis->hPollSet, hTcpSockNew,
202 fEvts, DRVTCP_POLLSET_ID_SOCKET);
203 if (RT_SUCCESS(rc))
204 pThis->hTcpSock = hTcpSockNew;
205 }
206 else
207 AssertMsgFailed(("Unknown wakeup reason in pipe %u\n", bReason));
208 }
209 else
210 {
211 Assert(idHnd == DRVTCP_POLLSET_ID_SOCKET);
212
213 /* On error we close the socket here. */
214 if (fEvtsRecv & RTPOLL_EVT_ERROR)
215 {
216 rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET);
217 AssertRC(rc);
218
219 if (pThis->fIsServer)
220 RTTcpServerDisconnectClient2(pThis->hTcpSock);
221 else
222 RTSocketClose(pThis->hTcpSock);
223 pThis->hTcpSock = NIL_RTSOCKET;
224 ASMAtomicDecU32(&pThis->cConnections);
225 /* Continue with polling. */
226 }
227 else
228 {
229 if (fEvtsRecv & RTPOLL_EVT_WRITE)
230 pThis->fXmitBufFull = false;
231 else if (!pThis->fXmitBufFull)
232 fEvtsRecv |= RTPOLL_EVT_WRITE;
233 *pfEvts = fEvtsRecv;
234 break;
235 }
236 }
237 }
238 else if ( rc == VERR_TIMEOUT
239 && !pThis->fXmitBufFull)
240 {
241 *pfEvts = RTPOLL_EVT_WRITE;
242 rc = VINF_SUCCESS;
243 break;
244 }
245 }
246 }
247
248 return rc;
249}
250
251
252/** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */
253static DECLCALLBACK(int) drvTcpPollInterrupt(PPDMISTREAM pInterface)
254{
255 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream);
256 return drvTcpPollerKick(pThis, DRVTCP_WAKEUP_REASON_EXTERNAL);
257}
258
259
260/** @interface_method_impl{PDMISTREAM,pfnRead} */
261static DECLCALLBACK(int) drvTcpRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)
262{
263 int rc = VINF_SUCCESS;
264 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream);
265 LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation));
266
267 Assert(pvBuf);
268
269 if (pThis->hTcpSock != NIL_RTSOCKET)
270 {
271 size_t cbRead;
272 size_t cbBuf = *pcbRead;
273 rc = RTSocketReadNB(pThis->hTcpSock, pvBuf, cbBuf, &cbRead);
274 if (RT_SUCCESS(rc))
275 {
276 if (!cbRead && rc != VINF_TRY_AGAIN)
277 {
278 rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET);
279 AssertRC(rc);
280
281 if (pThis->fIsServer)
282 RTTcpServerDisconnectClient2(pThis->hTcpSock);
283 else
284 RTSocketClose(pThis->hTcpSock);
285 pThis->hTcpSock = NIL_RTSOCKET;
286 rc = VINF_SUCCESS;
287 }
288 *pcbRead = cbRead;
289 }
290 }
291 else
292 {
293 RTThreadSleep(100);
294 *pcbRead = 0;
295 }
296
297 LogFlow(("%s: *pcbRead=%zu returns %Rrc\n", __FUNCTION__, *pcbRead, rc));
298 return rc;
299}
300
301
302/** @interface_method_impl{PDMISTREAM,pfnWrite} */
303static DECLCALLBACK(int) drvTcpWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
304{
305 int rc = VINF_SUCCESS;
306 PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream);
307 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
308
309 Assert(pvBuf);
310 if (pThis->hTcpSock != NIL_RTSOCKET)
311 {
312 size_t cbBuf = *pcbWrite;
313 rc = RTSocketWriteNB(pThis->hTcpSock, pvBuf, cbBuf, pcbWrite);
314 if (rc == VINF_TRY_AGAIN)
315 {
316 Assert(*pcbWrite == 0);
317 pThis->fXmitBufFull = true;
318 rc = VERR_TIMEOUT;
319 }
320 }
321 else
322 *pcbWrite = 0;
323
324 LogFlow(("%s: returns %Rrc *pcbWrite=%zu\n", __FUNCTION__, rc, *pcbWrite));
325 return rc;
326}
327
328
329/**
330 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
331 */
332static DECLCALLBACK(void *) drvTCPQueryInterface(PPDMIBASE pInterface, const char *pszIID)
333{
334 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
335 PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
336 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
337 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
338 return NULL;
339}
340
341
342/* -=-=-=-=- listen thread -=-=-=-=- */
343
344/**
345 * Receive thread loop.
346 *
347 * @returns VINF_SUCCESS
348 * @param hThreadSelf Thread handle to this thread.
349 * @param pvUser User argument.
350 */
351static DECLCALLBACK(int) drvTCPListenLoop(RTTHREAD hThreadSelf, void *pvUser)
352{
353 RT_NOREF(hThreadSelf);
354 PDRVTCP pThis = (PDRVTCP)pvUser;
355
356 while (RT_LIKELY(!pThis->fShutdown))
357 {
358 RTSOCKET hTcpSockNew = NIL_RTSOCKET;
359 int rc = RTTcpServerListen2(pThis->hTcpServ, &hTcpSockNew);
360 if (RT_SUCCESS(rc))
361 {
362 if (ASMAtomicReadU32(&pThis->cConnections) > 0)
363 {
364 LogRel(("DrvTCP%d: only single connection supported\n", pThis->pDrvIns->iInstance));
365 RTTcpServerDisconnectClient2(hTcpSockNew);
366 }
367 else
368 {
369 ASMAtomicIncU32(&pThis->cConnections);
370
371 /* Inform the poller about the new socket. */
372 drvTcpPollerKickEx(pThis, DRVTCP_WAKEUP_REASON_NEW_CONNECTION, &hTcpSockNew, sizeof(hTcpSockNew));
373 }
374 }
375 }
376
377 return VINF_SUCCESS;
378}
379
380/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
381
382/**
383 * Common worker for drvTCPPowerOff and drvTCPDestructor.
384 *
385 * @param pThis The instance data.
386 */
387static void drvTCPShutdownListener(PDRVTCP pThis)
388{
389 /*
390 * Signal shutdown of the listener thread.
391 */
392 pThis->fShutdown = true;
393 if ( pThis->fIsServer
394 && pThis->hTcpServ != NULL)
395 {
396 int rc = RTTcpServerShutdown(pThis->hTcpServ);
397 AssertRC(rc);
398 pThis->hTcpServ = NULL;
399 }
400}
401
402
403/**
404 * Power off a TCP socket stream driver instance.
405 *
406 * This does most of the destruction work, to avoid ordering dependencies.
407 *
408 * @param pDrvIns The driver instance data.
409 */
410static DECLCALLBACK(void) drvTCPPowerOff(PPDMDRVINS pDrvIns)
411{
412 PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
413 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
414
415 drvTCPShutdownListener(pThis);
416}
417
418
419/**
420 * Destruct a TCP socket stream driver instance.
421 *
422 * Most VM resources are freed by the VM. This callback is provided so that
423 * any non-VM resources can be freed correctly.
424 *
425 * @param pDrvIns The driver instance data.
426 */
427static DECLCALLBACK(void) drvTCPDestruct(PPDMDRVINS pDrvIns)
428{
429 PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
430 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
431 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
432
433 drvTCPShutdownListener(pThis);
434
435 /*
436 * While the thread exits, clean up as much as we can.
437 */
438 if (pThis->hTcpSock != NIL_RTSOCKET)
439 {
440 int rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET);
441 AssertRC(rc);
442
443 rc = RTSocketShutdown(pThis->hTcpSock, true /* fRead */, true /* fWrite */);
444 AssertRC(rc);
445
446 rc = RTSocketClose(pThis->hTcpSock);
447 AssertRC(rc); RT_NOREF(rc);
448
449 pThis->hTcpSock = NIL_RTSOCKET;
450 }
451
452 if (pThis->hPipeWakeR != NIL_RTPIPE)
453 {
454 int rc = RTPipeClose(pThis->hPipeWakeR);
455 AssertRC(rc);
456
457 pThis->hPipeWakeR = NIL_RTPIPE;
458 }
459
460 if (pThis->hPipeWakeW != NIL_RTPIPE)
461 {
462 int rc = RTPipeClose(pThis->hPipeWakeW);
463 AssertRC(rc);
464
465 pThis->hPipeWakeW = NIL_RTPIPE;
466 }
467
468 if (pThis->hPollSet != NIL_RTPOLLSET)
469 {
470 int rc = RTPollSetDestroy(pThis->hPollSet);
471 AssertRC(rc);
472
473 pThis->hPollSet = NIL_RTPOLLSET;
474 }
475
476 MMR3HeapFree(pThis->pszLocation);
477 pThis->pszLocation = NULL;
478
479 /*
480 * Wait for the thread.
481 */
482 if (pThis->ListenThread != NIL_RTTHREAD)
483 {
484 int rc = RTThreadWait(pThis->ListenThread, 30000, NULL);
485 if (RT_SUCCESS(rc))
486 pThis->ListenThread = NIL_RTTHREAD;
487 else
488 LogRel(("DrvTCP%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
489 }
490}
491
492
493/**
494 * Construct a TCP socket stream driver instance.
495 *
496 * @copydoc FNPDMDRVCONSTRUCT
497 */
498static DECLCALLBACK(int) drvTCPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
499{
500 RT_NOREF(fFlags);
501 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
502 PDRVTCP pThis = PDMINS_2_DATA(pDrvIns, PDRVTCP);
503
504 /*
505 * Init the static parts.
506 */
507 pThis->pDrvIns = pDrvIns;
508 pThis->pszLocation = NULL;
509 pThis->fIsServer = false;
510 pThis->fXmitBufFull = false;
511 pThis->cConnections = 0;
512
513 pThis->hTcpServ = NULL;
514 pThis->hTcpSock = NIL_RTSOCKET;
515
516 pThis->hPollSet = NIL_RTPOLLSET;
517 pThis->hPipeWakeR = NIL_RTPIPE;
518 pThis->hPipeWakeW = NIL_RTPIPE;
519
520 pThis->ListenThread = NIL_RTTHREAD;
521 pThis->fShutdown = false;
522 /* IBase */
523 pDrvIns->IBase.pfnQueryInterface = drvTCPQueryInterface;
524 /* IStream */
525 pThis->IStream.pfnPoll = drvTcpPoll;
526 pThis->IStream.pfnPollInterrupt = drvTcpPollInterrupt;
527 pThis->IStream.pfnRead = drvTcpRead;
528 pThis->IStream.pfnWrite = drvTcpWrite;
529
530 /*
531 * Validate and read the configuration.
532 */
533 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", "");
534
535 int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
536 if (RT_FAILURE(rc))
537 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
538 N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
539 rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer);
540 if (RT_FAILURE(rc))
541 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
542 N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc);
543
544 rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */);
545 if (RT_FAILURE(rc))
546 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
547 N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance);
548
549 rc = RTPollSetCreate(&pThis->hPollSet);
550 if (RT_FAILURE(rc))
551 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
552 N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance);
553
554 rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR,
555 RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
556 DRVTCP_POLLSET_ID_WAKEUP);
557 if (RT_FAILURE(rc))
558 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
559 N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"),
560 pDrvIns->iInstance, pThis->pszLocation);
561
562 /*
563 * Create/Open the socket.
564 */
565 if (pThis->fIsServer)
566 {
567 uint32_t uPort = 0;
568 rc = RTStrToUInt32Ex(pThis->pszLocation, NULL, 10, &uPort);
569 if (RT_FAILURE(rc))
570 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
571 N_("DrvTCP#%d: The port part of the location is not a numerical value"),
572 pDrvIns->iInstance);
573
574 /** @todo Allow binding to distinct interfaces. */
575 rc = RTTcpServerCreateEx(NULL, uPort, &pThis->hTcpServ);
576 if (RT_FAILURE(rc))
577 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
578 N_("DrvTCP#%d failed to create server socket"), pDrvIns->iInstance);
579
580 rc = RTThreadCreate(&pThis->ListenThread, drvTCPListenLoop, (void *)pThis, 0,
581 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "DrvTCPStream");
582 if (RT_FAILURE(rc))
583 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
584 N_("DrvTCP#%d failed to create listening thread"), pDrvIns->iInstance);
585 }
586 else
587 {
588 char *pszPort = strchr(pThis->pszLocation, ':');
589 if (!pszPort)
590 return PDMDrvHlpVMSetError(pDrvIns, VERR_NOT_FOUND, RT_SRC_POS,
591 N_("DrvTCP#%d: The location misses the port to connect to"),
592 pDrvIns->iInstance);
593
594 *pszPort = '\0'; /* Overwrite temporarily to avoid copying the hostname into a temporary buffer. */
595 uint32_t uPort = 0;
596 rc = RTStrToUInt32Ex(pszPort + 1, NULL, 10, &uPort);
597 if (RT_FAILURE(rc))
598 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
599 N_("DrvTCP#%d: The port part of the location is not a numerical value"),
600 pDrvIns->iInstance);
601
602 rc = RTTcpClientConnect(pThis->pszLocation, uPort, &pThis->hTcpSock);
603 *pszPort = ':'; /* Restore delimiter before checking the status. */
604 if (RT_FAILURE(rc))
605 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
606 N_("DrvTCP#%d failed to connect to socket %s"),
607 pDrvIns->iInstance, pThis->pszLocation);
608
609 rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock,
610 RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR,
611 DRVTCP_POLLSET_ID_SOCKET);
612 if (RT_FAILURE(rc))
613 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
614 N_("DrvTCP#%d failed to add socket for %s to poll set"),
615 pDrvIns->iInstance, pThis->pszLocation);
616
617 ASMAtomicIncU32(&pThis->cConnections);
618 }
619
620 LogRel(("DrvTCP: %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client"));
621 return VINF_SUCCESS;
622}
623
624
625/**
626 * TCP stream driver registration record.
627 */
628const PDMDRVREG g_DrvTCP =
629{
630 /* u32Version */
631 PDM_DRVREG_VERSION,
632 /* szName */
633 "TCP",
634 /* szRCMod */
635 "",
636 /* szR0Mod */
637 "",
638 /* pszDescription */
639 "TCP serial stream driver.",
640 /* fFlags */
641 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
642 /* fClass. */
643 PDM_DRVREG_CLASS_STREAM,
644 /* cMaxInstances */
645 ~0U,
646 /* cbInstance */
647 sizeof(DRVTCP),
648 /* pfnConstruct */
649 drvTCPConstruct,
650 /* pfnDestruct */
651 drvTCPDestruct,
652 /* pfnRelocate */
653 NULL,
654 /* pfnIOCtl */
655 NULL,
656 /* pfnPowerOn */
657 NULL,
658 /* pfnReset */
659 NULL,
660 /* pfnSuspend */
661 NULL,
662 /* pfnResume */
663 NULL,
664 /* pfnAttach */
665 NULL,
666 /* pfnDetach */
667 NULL,
668 /* pfnPowerOff */
669 drvTCPPowerOff,
670 /* pfnSoftReset */
671 NULL,
672 /* u32EndVersion */
673 PDM_DRVREG_VERSION
674};
675
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