VirtualBox

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

Last change on this file since 78071 was 77855, checked in by vboxsync, 6 years ago

Storage/VD: Move the TCP/NET implementation from DrvVD to a separate file in the VD storage library so it can be reused elsewhere

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