VirtualBox

source: vbox/trunk/src/VBox/Storage/VDIfTcpNet.cpp@ 106212

Last change on this file since 106212 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.5 KB
Line 
1/* $Id: VDIfTcpNet.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VD - Virtual disk container implementation, Default TCP/IP interface implementation.
4 */
5
6/*
7 * Copyright (C) 2019-2024 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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <VBox/vd.h>
33#include <VBox/err.h>
34#include <iprt/asm.h>
35#include <iprt/log.h>
36#include <iprt/tcp.h>
37#include <iprt/sg.h>
38#include <iprt/poll.h>
39#include <iprt/pipe.h>
40#include <iprt/system.h>
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46
47/** Pollset id of the socket. */
48#define VDSOCKET_POLL_ID_SOCKET 0
49/** Pollset id of the pipe. */
50#define VDSOCKET_POLL_ID_PIPE 1
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56
57/**
58 * Socket data.
59 */
60typedef struct VDSOCKETINT
61{
62 /** IPRT socket handle. */
63 RTSOCKET hSocket;
64 /** Pollset with the wakeup pipe and socket. */
65 RTPOLLSET hPollSet;
66 /** Pipe endpoint - read (in the pollset). */
67 RTPIPE hPipeR;
68 /** Pipe endpoint - write. */
69 RTPIPE hPipeW;
70 /** Flag whether the thread was woken up. */
71 volatile bool fWokenUp;
72 /** Flag whether the thread is waiting in the select call. */
73 volatile bool fWaiting;
74 /** Old event mask. */
75 uint32_t fEventsOld;
76} VDSOCKETINT, *PVDSOCKETINT;
77
78
79/**
80 * VD TCP/NET interface instance data.
81 */
82typedef struct VDIFINSTINT
83{
84 /** The TCP/NET interface descriptor. */
85 VDINTERFACETCPNET VdIfTcpNet;
86} VDIFINSTINT;
87/** Pointer to the VD TCP/NET interface instance data. */
88typedef VDIFINSTINT *PVDIFINSTINT;
89
90
91/*********************************************************************************************************************************
92* Internal Functions *
93*********************************************************************************************************************************/
94
95/** @interface_method_impl{VDINTERFACETCPNET,pfnSocketCreate} */
96static DECLCALLBACK(int) vdIfTcpNetSocketCreate(uint32_t fFlags, PVDSOCKET phVdSock)
97{
98 int rc = VINF_SUCCESS;
99 int rc2 = VINF_SUCCESS;
100 PVDSOCKETINT pSockInt = NULL;
101
102 pSockInt = (PVDSOCKETINT)RTMemAllocZ(sizeof(VDSOCKETINT));
103 if (!pSockInt)
104 return VERR_NO_MEMORY;
105
106 pSockInt->hSocket = NIL_RTSOCKET;
107 pSockInt->hPollSet = NIL_RTPOLLSET;
108 pSockInt->hPipeR = NIL_RTPIPE;
109 pSockInt->hPipeW = NIL_RTPIPE;
110 pSockInt->fWokenUp = false;
111 pSockInt->fWaiting = false;
112
113 if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
114 {
115 /* Init pipe and pollset. */
116 rc = RTPipeCreate(&pSockInt->hPipeR, &pSockInt->hPipeW, 0);
117 if (RT_SUCCESS(rc))
118 {
119 rc = RTPollSetCreate(&pSockInt->hPollSet);
120 if (RT_SUCCESS(rc))
121 {
122 rc = RTPollSetAddPipe(pSockInt->hPollSet, pSockInt->hPipeR,
123 RTPOLL_EVT_READ, VDSOCKET_POLL_ID_PIPE);
124 if (RT_SUCCESS(rc))
125 {
126 *phVdSock = pSockInt;
127 return VINF_SUCCESS;
128 }
129
130 RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
131 rc2 = RTPollSetDestroy(pSockInt->hPollSet);
132 AssertRC(rc2);
133 }
134
135 rc2 = RTPipeClose(pSockInt->hPipeR);
136 AssertRC(rc2);
137 rc2 = RTPipeClose(pSockInt->hPipeW);
138 AssertRC(rc2);
139 }
140 }
141 else
142 {
143 *phVdSock = pSockInt;
144 return VINF_SUCCESS;
145 }
146
147 RTMemFree(pSockInt);
148
149 return rc;
150}
151
152/** @interface_method_impl{VDINTERFACETCPNET,pfnSocketDestroy} */
153static DECLCALLBACK(int) vdIfTcpNetSocketDestroy(VDSOCKET hVdSock)
154{
155 int rc = VINF_SUCCESS;
156 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
157
158 /* Destroy the pipe and pollset if necessary. */
159 if (pSockInt->hPollSet != NIL_RTPOLLSET)
160 {
161 if (pSockInt->hSocket != NIL_RTSOCKET)
162 {
163 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
164 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
165 }
166 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
167 AssertRC(rc);
168 rc = RTPollSetDestroy(pSockInt->hPollSet);
169 AssertRC(rc);
170 rc = RTPipeClose(pSockInt->hPipeR);
171 AssertRC(rc);
172 rc = RTPipeClose(pSockInt->hPipeW);
173 AssertRC(rc);
174 }
175
176 if (pSockInt->hSocket != NIL_RTSOCKET)
177 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
178
179 RTMemFree(pSockInt);
180
181 return rc;
182}
183
184/** @interface_method_impl{VDINTERFACETCPNET,pfnClientConnect} */
185static DECLCALLBACK(int) vdIfTcpNetClientConnect(VDSOCKET hVdSock, const char *pszAddress, uint32_t uPort,
186 RTMSINTERVAL cMillies)
187{
188 int rc = VINF_SUCCESS;
189 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
190
191 rc = RTTcpClientConnectEx(pszAddress, uPort, &pSockInt->hSocket, cMillies, NULL);
192 if (RT_SUCCESS(rc))
193 {
194 /* Add to the pollset if required. */
195 if (pSockInt->hPollSet != NIL_RTPOLLSET)
196 {
197 pSockInt->fEventsOld = RTPOLL_EVT_READ | RTPOLL_EVT_WRITE | RTPOLL_EVT_ERROR;
198
199 rc = RTPollSetAddSocket(pSockInt->hPollSet, pSockInt->hSocket,
200 pSockInt->fEventsOld, VDSOCKET_POLL_ID_SOCKET);
201 }
202
203 if (RT_SUCCESS(rc))
204 return VINF_SUCCESS;
205
206 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
207 }
208
209 return rc;
210}
211
212/** @interface_method_impl{VDINTERFACETCPNET,pfnClientClose} */
213static DECLCALLBACK(int) vdIfTcpNetClientClose(VDSOCKET hVdSock)
214{
215 int rc = VINF_SUCCESS;
216 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
217
218 if (pSockInt->hPollSet != NIL_RTPOLLSET)
219 {
220 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
221 AssertRC(rc);
222 }
223
224 rc = RTTcpClientCloseEx(pSockInt->hSocket, false /*fGracefulShutdown*/);
225 pSockInt->hSocket = NIL_RTSOCKET;
226
227 return rc;
228}
229
230/** @interface_method_impl{VDINTERFACETCPNET,pfnIsClientConnected} */
231static DECLCALLBACK(bool) vdIfTcpNetIsClientConnected(VDSOCKET hVdSock)
232{
233 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
234
235 return pSockInt->hSocket != NIL_RTSOCKET;
236}
237
238/** @interface_method_impl{VDINTERFACETCPNET,pfnSelectOne} */
239static DECLCALLBACK(int) vdIfTcpNetSelectOne(VDSOCKET hVdSock, RTMSINTERVAL cMillies)
240{
241 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
242
243 return RTTcpSelectOne(pSockInt->hSocket, cMillies);
244}
245
246/** @interface_method_impl{VDINTERFACETCPNET,pfnRead} */
247static DECLCALLBACK(int) vdIfTcpNetRead(VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
248{
249 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
250
251 return RTTcpRead(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
252}
253
254/** @interface_method_impl{VDINTERFACETCPNET,pfnWrite} */
255static DECLCALLBACK(int) vdIfTcpNetWrite(VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer)
256{
257 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
258
259 return RTTcpWrite(pSockInt->hSocket, pvBuffer, cbBuffer);
260}
261
262/** @interface_method_impl{VDINTERFACETCPNET,pfnSgWrite} */
263static DECLCALLBACK(int) vdIfTcpNetSgWrite(VDSOCKET hVdSock, PCRTSGBUF pSgBuf)
264{
265 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
266
267 return RTTcpSgWrite(pSockInt->hSocket, pSgBuf);
268}
269
270/** @interface_method_impl{VDINTERFACETCPNET,pfnReadNB} */
271static DECLCALLBACK(int) vdIfTcpNetReadNB(VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
272{
273 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
274
275 return RTTcpReadNB(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
276}
277
278/** @interface_method_impl{VDINTERFACETCPNET,pfnWriteNB} */
279static DECLCALLBACK(int) vdIfTcpNetWriteNB(VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)
280{
281 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
282
283 return RTTcpWriteNB(pSockInt->hSocket, pvBuffer, cbBuffer, pcbWritten);
284}
285
286/** @interface_method_impl{VDINTERFACETCPNET,pfnSgWriteNB} */
287static DECLCALLBACK(int) vdIfTcpNetSgWriteNB(VDSOCKET hVdSock, PRTSGBUF pSgBuf, size_t *pcbWritten)
288{
289 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
290
291 return RTTcpSgWriteNB(pSockInt->hSocket, pSgBuf, pcbWritten);
292}
293
294/** @interface_method_impl{VDINTERFACETCPNET,pfnFlush} */
295static DECLCALLBACK(int) vdIfTcpNetFlush(VDSOCKET hVdSock)
296{
297 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
298
299 return RTTcpFlush(pSockInt->hSocket);
300}
301
302/** @interface_method_impl{VDINTERFACETCPNET,pfnSetSendCoalescing} */
303static DECLCALLBACK(int) vdIfTcpNetSetSendCoalescing(VDSOCKET hVdSock, bool fEnable)
304{
305 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
306
307 return RTTcpSetSendCoalescing(pSockInt->hSocket, fEnable);
308}
309
310/** @interface_method_impl{VDINTERFACETCPNET,pfnGetLocalAddress} */
311static DECLCALLBACK(int) vdIfTcpNetGetLocalAddress(VDSOCKET hVdSock, PRTNETADDR pAddr)
312{
313 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
314
315 return RTTcpGetLocalAddress(pSockInt->hSocket, pAddr);
316}
317
318/** @interface_method_impl{VDINTERFACETCPNET,pfnGetPeerAddress} */
319static DECLCALLBACK(int) vdIfTcpNetGetPeerAddress(VDSOCKET hVdSock, PRTNETADDR pAddr)
320{
321 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
322
323 return RTTcpGetPeerAddress(pSockInt->hSocket, pAddr);
324}
325
326static DECLCALLBACK(int) vdIfTcpNetSelectOneExPoll(VDSOCKET hVdSock, uint32_t fEvents,
327 uint32_t *pfEvents, RTMSINTERVAL cMillies)
328{
329 int rc = VINF_SUCCESS;
330 uint32_t id = 0;
331 uint32_t fEventsRecv = 0;
332 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
333
334 *pfEvents = 0;
335
336 if ( pSockInt->fEventsOld != fEvents
337 && pSockInt->hSocket != NIL_RTSOCKET)
338 {
339 uint32_t fPollEvents = 0;
340
341 if (fEvents & VD_INTERFACETCPNET_EVT_READ)
342 fPollEvents |= RTPOLL_EVT_READ;
343 if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
344 fPollEvents |= RTPOLL_EVT_WRITE;
345 if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
346 fPollEvents |= RTPOLL_EVT_ERROR;
347
348 rc = RTPollSetEventsChange(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET, fPollEvents);
349 if (RT_FAILURE(rc))
350 return rc;
351
352 pSockInt->fEventsOld = fEvents;
353 }
354
355 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
356 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
357 {
358 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
359 return VERR_INTERRUPTED;
360 }
361
362 rc = RTPoll(pSockInt->hPollSet, cMillies, &fEventsRecv, &id);
363 Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
364
365 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
366
367 if (RT_SUCCESS(rc))
368 {
369 if (id == VDSOCKET_POLL_ID_SOCKET)
370 {
371 fEventsRecv &= RTPOLL_EVT_VALID_MASK;
372
373 if (fEventsRecv & RTPOLL_EVT_READ)
374 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
375 if (fEventsRecv & RTPOLL_EVT_WRITE)
376 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
377 if (fEventsRecv & RTPOLL_EVT_ERROR)
378 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
379 }
380 else
381 {
382 size_t cbRead = 0;
383 uint8_t abBuf[10];
384 Assert(id == VDSOCKET_POLL_ID_PIPE);
385 Assert((fEventsRecv & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
386
387 /* We got interrupted, drain the pipe. */
388 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
389 AssertRC(rc);
390
391 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
392
393 rc = VERR_INTERRUPTED;
394 }
395 }
396
397 return rc;
398}
399
400/** @interface_method_impl{VDINTERFACETCPNET,pfnSelectOneEx} */
401static DECLCALLBACK(int) vdIfTcpNetSelectOneExNoPoll(VDSOCKET hVdSock, uint32_t fEvents, uint32_t *pfEvents, RTMSINTERVAL cMillies)
402{
403 RT_NOREF(cMillies); /** @todo timeouts */
404 int rc = VINF_SUCCESS;
405 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
406
407 *pfEvents = 0;
408
409 ASMAtomicXchgBool(&pSockInt->fWaiting, true);
410 if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
411 {
412 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
413 return VERR_INTERRUPTED;
414 }
415
416 if ( pSockInt->hSocket == NIL_RTSOCKET
417 || !fEvents)
418 {
419 /*
420 * Only the pipe is configured or the caller doesn't wait for a socket event,
421 * wait until there is something to read from the pipe.
422 */
423 size_t cbRead = 0;
424 char ch = 0;
425 rc = RTPipeReadBlocking(pSockInt->hPipeR, &ch, 1, &cbRead);
426 if (RT_SUCCESS(rc))
427 {
428 Assert(cbRead == 1);
429 rc = VERR_INTERRUPTED;
430 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
431 }
432 }
433 else
434 {
435 uint32_t fSelectEvents = 0;
436
437 if (fEvents & VD_INTERFACETCPNET_EVT_READ)
438 fSelectEvents |= RTSOCKET_EVT_READ;
439 if (fEvents & VD_INTERFACETCPNET_EVT_WRITE)
440 fSelectEvents |= RTSOCKET_EVT_WRITE;
441 if (fEvents & VD_INTERFACETCPNET_EVT_ERROR)
442 fSelectEvents |= RTSOCKET_EVT_ERROR;
443
444 if (fEvents & VD_INTERFACETCPNET_HINT_INTERRUPT)
445 {
446 uint32_t fEventsRecv = 0;
447
448 /* Make sure the socket is not in the pollset. */
449 rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
450 Assert(RT_SUCCESS(rc) || rc == VERR_POLL_HANDLE_ID_NOT_FOUND);
451
452 for (;;)
453 {
454 uint32_t id = 0;
455 rc = RTPoll(pSockInt->hPollSet, 5, &fEvents, &id);
456 if (rc == VERR_TIMEOUT)
457 {
458 /* Check the socket. */
459 rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 0);
460 if (RT_SUCCESS(rc))
461 {
462 if (fEventsRecv & RTSOCKET_EVT_READ)
463 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
464 if (fEventsRecv & RTSOCKET_EVT_WRITE)
465 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
466 if (fEventsRecv & RTSOCKET_EVT_ERROR)
467 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
468 break; /* Quit */
469 }
470 else if (rc != VERR_TIMEOUT)
471 break;
472 }
473 else if (RT_SUCCESS(rc))
474 {
475 size_t cbRead = 0;
476 uint8_t abBuf[10];
477 Assert(id == VDSOCKET_POLL_ID_PIPE);
478 Assert((fEventsRecv & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
479
480 /* We got interrupted, drain the pipe. */
481 rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
482 AssertRC(rc);
483
484 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
485
486 rc = VERR_INTERRUPTED;
487 break;
488 }
489 else
490 break;
491 }
492 }
493 else /* The caller waits for a socket event. */
494 {
495 uint32_t fEventsRecv = 0;
496
497 /* Loop until we got woken up or a socket event occurred. */
498 for (;;)
499 {
500 /** @todo find an adaptive wait algorithm based on the
501 * number of wakeups in the past. */
502 rc = RTTcpSelectOneEx(pSockInt->hSocket, fSelectEvents, &fEventsRecv, 5);
503 if (rc == VERR_TIMEOUT)
504 {
505 /* Check if there is an event pending. */
506 size_t cbRead = 0;
507 char ch = 0;
508 rc = RTPipeRead(pSockInt->hPipeR, &ch, 1, &cbRead);
509 if (RT_SUCCESS(rc) && rc != VINF_TRY_AGAIN)
510 {
511 Assert(cbRead == 1);
512 rc = VERR_INTERRUPTED;
513 ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
514 break; /* Quit */
515 }
516 else
517 Assert(rc == VINF_TRY_AGAIN);
518 }
519 else if (RT_SUCCESS(rc))
520 {
521 if (fEventsRecv & RTSOCKET_EVT_READ)
522 *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
523 if (fEventsRecv & RTSOCKET_EVT_WRITE)
524 *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
525 if (fEventsRecv & RTSOCKET_EVT_ERROR)
526 *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
527 break; /* Quit */
528 }
529 else
530 break;
531 }
532 }
533 }
534
535 ASMAtomicXchgBool(&pSockInt->fWaiting, false);
536
537 return rc;
538}
539
540/** @interface_method_impl{VDINTERFACETCPNET,pfnPoke} */
541static DECLCALLBACK(int) vdIfTcpNetPoke(VDSOCKET hVdSock)
542{
543 int rc = VINF_SUCCESS;
544 size_t cbWritten = 0;
545 PVDSOCKETINT pSockInt = (PVDSOCKETINT)hVdSock;
546
547 ASMAtomicXchgBool(&pSockInt->fWokenUp, true);
548
549 if (ASMAtomicReadBool(&pSockInt->fWaiting))
550 {
551 rc = RTPipeWrite(pSockInt->hPipeW, "", 1, &cbWritten);
552 Assert(RT_SUCCESS(rc) || cbWritten == 0);
553 }
554
555 return VINF_SUCCESS;
556}
557
558
559VBOXDDU_DECL(int) VDIfTcpNetInstDefaultCreate(PVDIFINST phTcpNetInst, PVDINTERFACE *ppVdIfs)
560{
561 AssertPtrReturn(phTcpNetInst, VERR_INVALID_POINTER);
562 AssertPtrReturn(ppVdIfs, VERR_INVALID_POINTER);
563
564 int rc = VINF_SUCCESS;
565 PVDIFINSTINT pThis = (PVDIFINSTINT)RTMemAllocZ(sizeof(*pThis));
566 if (RT_LIKELY(pThis))
567 {
568 pThis->VdIfTcpNet.pfnSocketCreate = vdIfTcpNetSocketCreate;
569 pThis->VdIfTcpNet.pfnSocketDestroy = vdIfTcpNetSocketDestroy;
570 pThis->VdIfTcpNet.pfnClientConnect = vdIfTcpNetClientConnect;
571 pThis->VdIfTcpNet.pfnIsClientConnected = vdIfTcpNetIsClientConnected;
572 pThis->VdIfTcpNet.pfnClientClose = vdIfTcpNetClientClose;
573 pThis->VdIfTcpNet.pfnSelectOne = vdIfTcpNetSelectOne;
574 pThis->VdIfTcpNet.pfnRead = vdIfTcpNetRead;
575 pThis->VdIfTcpNet.pfnWrite = vdIfTcpNetWrite;
576 pThis->VdIfTcpNet.pfnSgWrite = vdIfTcpNetSgWrite;
577 pThis->VdIfTcpNet.pfnReadNB = vdIfTcpNetReadNB;
578 pThis->VdIfTcpNet.pfnWriteNB = vdIfTcpNetWriteNB;
579 pThis->VdIfTcpNet.pfnSgWriteNB = vdIfTcpNetSgWriteNB;
580 pThis->VdIfTcpNet.pfnFlush = vdIfTcpNetFlush;
581 pThis->VdIfTcpNet.pfnSetSendCoalescing = vdIfTcpNetSetSendCoalescing;
582 pThis->VdIfTcpNet.pfnGetLocalAddress = vdIfTcpNetGetLocalAddress;
583 pThis->VdIfTcpNet.pfnGetPeerAddress = vdIfTcpNetGetPeerAddress;
584 pThis->VdIfTcpNet.pfnPoke = vdIfTcpNetPoke;
585
586 /*
587 * There is a 15ms delay between receiving the data and marking the socket
588 * as readable on Windows XP which hurts async I/O performance of
589 * TCP backends badly. Provide a different select method without
590 * using poll on XP.
591 * This is only used on XP because it is not as efficient as the one using poll
592 * and all other Windows versions are working fine.
593 */
594 char szOS[64];
595 memset(szOS, 0, sizeof(szOS));
596 rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, &szOS[0], sizeof(szOS));
597
598 if (RT_SUCCESS(rc) && !strncmp(szOS, "Windows XP", 10))
599 {
600 LogRel(("VD: Detected Windows XP, disabled poll based waiting for TCP\n"));
601 pThis->VdIfTcpNet.pfnSelectOneEx = vdIfTcpNetSelectOneExNoPoll;
602 }
603 else
604 pThis->VdIfTcpNet.pfnSelectOneEx = vdIfTcpNetSelectOneExPoll;
605
606 rc = VDInterfaceAdd(&pThis->VdIfTcpNet.Core, "VD_IfTcpNet",
607 VDINTERFACETYPE_TCPNET, NULL,
608 sizeof(VDINTERFACETCPNET), ppVdIfs);
609 AssertRC(rc);
610
611 if (RT_SUCCESS(rc))
612 *phTcpNetInst = pThis;
613 else
614 RTMemFree(pThis);
615 }
616 else
617 rc = VERR_NO_MEMORY;
618
619 return rc;
620}
621
622
623VBOXDDU_DECL(void) VDIfTcpNetInstDefaultDestroy(VDIFINST hTcpNetInst)
624{
625 PVDIFINSTINT pThis = hTcpNetInst;
626 AssertPtrReturnVoid(pThis);
627
628 RTMemFree(pThis);
629}
630
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