VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DrvNamedPipe.cpp@ 2418

Last change on this file since 2418 was 2052, checked in by vboxsync, 18 years ago

Make named pipe destruction independent of driver destruction order.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.8 KB
Line 
1/** @file
2 *
3 * VBox stream devices:
4 * Named pipe stream
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_NAMEDPIPE
28#include <VBox/pdm.h>
29#include <VBox/cfgm.h>
30#include <VBox/err.h>
31
32#include <VBox/log.h>
33#include <VBox/mm.h>
34#include <iprt/assert.h>
35#include <iprt/file.h>
36#include <iprt/stream.h>
37#include <iprt/alloc.h>
38#include <iprt/string.h>
39#include <iprt/semaphore.h>
40
41#include "Builtins.h"
42
43#ifdef __WIN__
44#include <windows.h>
45#else /* !__WIN__ */
46#include <errno.h>
47#include <unistd.h>
48#include <sys/types.h>
49#include <sys/socket.h>
50#include <sys/un.h>
51#endif /* !__WIN__ */
52
53/*******************************************************************************
54* Defined Constants And Macros *
55*******************************************************************************/
56
57/** Converts a pointer to DRVNAMEDPIPE::IMedia to a PDRVNAMEDPIPE. */
58#define PDMISTREAM_2_DRVNAMEDPIPE(pInterface) ( (PDRVNAMEDPIPE)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAMEDPIPE, IStream)) )
59
60/** Converts a pointer to PDMDRVINS::IBase to a PPDMDRVINS. */
61#define PDMIBASE_2_DRVINS(pInterface) ( (PPDMDRVINS)((uintptr_t)pInterface - RT_OFFSETOF(PDMDRVINS, IBase)) )
62
63/*******************************************************************************
64* Structures and Typedefs *
65*******************************************************************************/
66/**
67 * Named pipe driver instance data.
68 */
69typedef struct DRVNAMEDPIPE
70{
71 /** The stream interface. */
72 PDMISTREAM IStream;
73 /** Pointer to the driver instance. */
74 PPDMDRVINS pDrvIns;
75 /** Pointer to the named pipe file name. (Freed by MM) */
76 char *pszLocation;
77 /** Flag whether VirtualBox represents the server or client side. */
78 bool fIsServer;
79#ifdef __WIN__
80 /* File handle of the named pipe. */
81 RTFILE NamedPipe;
82 /* Overlapped structure for writes. */
83 OVERLAPPED OverlappedWrite;
84 /* Overlapped structure for reads. */
85 OVERLAPPED OverlappedRead;
86 /* Listen thread wakeup semaphore */
87 RTSEMEVENT ListenSem;
88#else /* !__WIN__ */
89 /** Socket handle of the local socket for server. */
90 RTSOCKET LocalSocketServer;
91 /** Socket handle of the local socket. */
92 RTSOCKET LocalSocket;
93#endif /* !__WIN__ */
94 /** Thread for listening for new connections. */
95 RTTHREAD ListenThread;
96 /** Flag to signal listening thread to shut down. */
97 bool fShutdown;
98} DRVNAMEDPIPE, *PDRVNAMEDPIPE;
99
100
101/*******************************************************************************
102* Internal Functions *
103*******************************************************************************/
104
105
106/** @copydoc PDMISTREAM::pfnRead */
107static DECLCALLBACK(int) drvNamedPipeRead(PPDMISTREAM pInterface, void *pvBuf, size_t *cbRead)
108{
109 int rc = VINF_SUCCESS;
110 PDRVNAMEDPIPE pData = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
111 LogFlow(("%s: pvBuf=%p cbRead=%#x (%s)\n", __FUNCTION__, pvBuf, cbRead, pData->pszLocation));
112
113 Assert(pvBuf);
114#ifdef __WIN__
115 if (pData->NamedPipe != NIL_RTFILE)
116 {
117 DWORD cbReallyRead;
118 pData->OverlappedRead.Offset = 0;
119 pData->OverlappedRead.OffsetHigh = 0;
120 if (!ReadFile((HANDLE)pData->NamedPipe, pvBuf, *cbRead, &cbReallyRead, &pData->OverlappedRead))
121 {
122 DWORD uError = GetLastError();
123
124 if ( uError == ERROR_PIPE_LISTENING
125 || uError == ERROR_PIPE_NOT_CONNECTED)
126 {
127 /* No connection yet/anymore */
128 cbReallyRead = 0;
129
130 /* wait a bit or else we'll be called right back. */
131 RTThreadSleep(100);
132 }
133 else
134 {
135 if (uError == ERROR_IO_PENDING)
136 {
137 uError = 0;
138
139 /* Wait for incoming bytes. */
140 if (GetOverlappedResult((HANDLE)pData->NamedPipe, &pData->OverlappedRead, &cbReallyRead, TRUE) == FALSE)
141 uError = GetLastError();
142 }
143
144 rc = RTErrConvertFromWin32(uError);
145 Log(("drvNamedPipeRead: ReadFile returned %d (%Vrc)\n", uError, rc));
146 }
147 }
148
149 if (VBOX_FAILURE(rc))
150 {
151 Log(("drvNamedPipeRead: RTFileRead returned %Vrc fShutdown=%d\n", rc, pData->fShutdown));
152 if ( !pData->fShutdown
153 && ( rc == VERR_EOF
154 || rc == VERR_BROKEN_PIPE
155 )
156 )
157
158 {
159 RTFILE tmp = pData->NamedPipe;
160 FlushFileBuffers((HANDLE)tmp);
161 DisconnectNamedPipe((HANDLE)tmp);
162 if (!pData->fIsServer)
163 {
164 pData->NamedPipe = NIL_RTFILE;
165 RTFileClose(tmp);
166 }
167 /* pretend success */
168 rc = VINF_SUCCESS;
169 }
170 cbReallyRead = 0;
171 }
172 *cbRead = (size_t)cbReallyRead;
173 }
174#else /* !__WIN__ */
175 if (pData->LocalSocket != NIL_RTSOCKET)
176 {
177 ssize_t cbReallyRead;
178 cbReallyRead = recv(pData->LocalSocket, pvBuf, *cbRead, 0);
179 if (cbReallyRead == 0)
180 {
181 RTSOCKET tmp = pData->LocalSocket;
182 pData->LocalSocket = NIL_RTSOCKET;
183 close(tmp);
184 }
185 else if (cbReallyRead == -1)
186 {
187 cbReallyRead = 0;
188 rc = RTErrConvertFromErrno(errno);
189 }
190 *cbRead = cbReallyRead;
191 }
192#endif /* !__WIN__ */
193 else
194 {
195 RTThreadSleep(100);
196 *cbRead = 0;
197 }
198
199 LogFlow(("%s: cbRead=%d returns %Vrc\n", __FUNCTION__, *cbRead, rc));
200 return rc;
201}
202
203
204/** @copydoc PDMISTREAM::pfnWrite */
205static DECLCALLBACK(int) drvNamedPipeWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *cbWrite)
206{
207 int rc = VINF_SUCCESS;
208 PDRVNAMEDPIPE pData = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
209 LogFlow(("%s: pvBuf=%p cbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, cbWrite, pData->pszLocation));
210
211 Assert(pvBuf);
212#ifdef __WIN__
213 if (pData->NamedPipe != NIL_RTFILE)
214 {
215 unsigned cbWritten;
216 pData->OverlappedWrite.Offset = 0;
217 pData->OverlappedWrite.OffsetHigh = 0;
218 if (!WriteFile((HANDLE)pData->NamedPipe, pvBuf, *cbWrite, NULL, &pData->OverlappedWrite))
219 {
220 DWORD uError = GetLastError();
221
222 if ( uError == ERROR_PIPE_LISTENING
223 || uError == ERROR_PIPE_NOT_CONNECTED)
224 {
225 /* No connection yet/anymore; just discard the write. */
226 cbWritten = *cbWrite;
227 }
228 else
229 if (uError != ERROR_IO_PENDING)
230 {
231 rc = RTErrConvertFromWin32(uError);
232 Log(("drvNamedPipeWrite: WriteFile returned %d (%Vrc)\n", uError, rc));
233 }
234 else
235 {
236 /* Wait for the write to complete. */
237 if (GetOverlappedResult((HANDLE)pData->NamedPipe, &pData->OverlappedWrite, (DWORD *)&cbWritten, TRUE) == FALSE)
238 uError = GetLastError();
239 }
240 }
241 else
242 cbWritten = *cbWrite;
243
244 if (VBOX_FAILURE(rc))
245 {
246 if ( rc == VERR_EOF
247 || rc == VERR_BROKEN_PIPE)
248 {
249 RTFILE tmp = pData->NamedPipe;
250 FlushFileBuffers((HANDLE)tmp);
251 DisconnectNamedPipe((HANDLE)tmp);
252 if (!pData->fIsServer)
253 {
254 pData->NamedPipe = NIL_RTFILE;
255 RTFileClose(tmp);
256 }
257 /* pretend success */
258 rc = VINF_SUCCESS;
259 }
260 cbWritten = 0;
261 }
262 *cbWrite = cbWritten;
263 }
264#else /* !__WIN__ */
265 if (pData->LocalSocket != NIL_RTSOCKET)
266 {
267 ssize_t cbWritten;
268 cbWritten = send(pData->LocalSocket, pvBuf, *cbWrite, 0);
269 if (cbWritten == 0)
270 {
271 RTSOCKET tmp = pData->LocalSocket;
272 pData->LocalSocket = NIL_RTSOCKET;
273 close(tmp);
274 }
275 else if (cbWritten == -1)
276 {
277 cbWritten = 0;
278 rc = RTErrConvertFromErrno(errno);
279 }
280 *cbWrite = cbWritten;
281 }
282#endif /* !__WIN__ */
283
284 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
285 return rc;
286}
287
288
289/**
290 * Queries an interface to the driver.
291 *
292 * @returns Pointer to interface.
293 * @returns NULL if the interface was not supported by the driver.
294 * @param pInterface Pointer to this interface structure.
295 * @param enmInterface The requested interface identification.
296 * @thread Any thread.
297 */
298static DECLCALLBACK(void *) drvNamedPipeQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
299{
300 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
301 PDRVNAMEDPIPE pDrv = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
302 switch (enmInterface)
303 {
304 case PDMINTERFACE_BASE:
305 return &pDrvIns->IBase;
306 case PDMINTERFACE_STREAM:
307 return &pDrv->IStream;
308 default:
309 return NULL;
310 }
311}
312
313
314/* -=-=-=-=- listen thread -=-=-=-=- */
315
316/**
317 * Receive thread loop.
318 *
319 * @returns 0 on success.
320 * @param ThreadSelf Thread handle to this thread.
321 * @param pvUser User argument.
322 */
323static DECLCALLBACK(int) drvNamedPipeListenLoop(RTTHREAD ThreadSelf, void *pvUser)
324{
325 PDRVNAMEDPIPE pData = (PDRVNAMEDPIPE)pvUser;
326 int rc = VINF_SUCCESS;
327#ifdef __WIN__
328 RTFILE NamedPipe = pData->NamedPipe;
329 HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, 0);
330#endif
331
332 while (RT_LIKELY(!pData->fShutdown))
333 {
334#ifdef __WIN__
335 OVERLAPPED overlapped;
336
337 memset(&overlapped, 0, sizeof(overlapped));
338 overlapped.hEvent = hEvent;
339
340 BOOL fConnected = ConnectNamedPipe((HANDLE)NamedPipe, &overlapped);
341 if ( !fConnected
342 && !pData->fShutdown)
343 {
344 DWORD hrc = GetLastError();
345
346 if (hrc == ERROR_IO_PENDING)
347 {
348 DWORD dummy;
349
350 hrc = 0;
351 if (GetOverlappedResult((HANDLE)pData->NamedPipe, &overlapped, &dummy, TRUE) == FALSE)
352 hrc = GetLastError();
353
354 }
355
356 if (pData->fShutdown)
357 break;
358
359 if (hrc == ERROR_PIPE_CONNECTED)
360 {
361 RTSemEventWait(pData->ListenSem, 250);
362 }
363 else
364 if (hrc != ERROR_SUCCESS)
365 {
366 rc = RTErrConvertFromWin32(hrc);
367 LogRel(("NamedPipe%d: ConnectNamedPipe failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
368 break;
369 }
370 }
371#else /* !__WIN__ */
372 if (listen(pData->LocalSocketServer, 0) == -1)
373 {
374 rc = RTErrConvertFromErrno(errno);
375 LogRel(("NamedPipe%d: listen failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
376 break;
377 }
378 int s = accept(pData->LocalSocketServer, NULL, NULL);
379 if (s == -1)
380 {
381 rc = RTErrConvertFromErrno(errno);
382 LogRel(("NamedPipe%d: accept failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
383 break;
384 }
385 else
386 {
387 if (pData->LocalSocket != NIL_RTSOCKET)
388 {
389 LogRel(("NamedPipe%d: only single connection supported\n", pData->pDrvIns->iInstance));
390 close(s);
391 }
392 else
393 pData->LocalSocket = s;
394 }
395#endif /* !__WIN__ */
396 }
397
398#ifdef __WIN__
399 CloseHandle(hEvent);
400#endif
401 pData->ListenThread = NIL_RTTHREAD;
402 return VINF_SUCCESS;
403}
404
405
406/**
407 * Construct a named pipe stream driver instance.
408 *
409 * @returns VBox status.
410 * @param pDrvIns The driver instance data.
411 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
412 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
413 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
414 * iInstance it's expected to be used a bit in this function.
415 */
416static DECLCALLBACK(int) drvNamedPipeConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
417{
418 int rc;
419 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
420
421 /*
422 * Init the static parts.
423 */
424 pData->pDrvIns = pDrvIns;
425 pData->pszLocation = NULL;
426 pData->fIsServer = false;
427#ifdef __WIN__
428 pData->NamedPipe = NIL_RTFILE;
429#else /* !__WIN__ */
430 pData->LocalSocketServer = NIL_RTSOCKET;
431 pData->LocalSocket = NIL_RTSOCKET;
432#endif /* !__WIN__ */
433 pData->ListenThread = NIL_RTTHREAD;
434 pData->fShutdown = false;
435 /* IBase */
436 pDrvIns->IBase.pfnQueryInterface = drvNamedPipeQueryInterface;
437 /* IStream */
438 pData->IStream.pfnRead = drvNamedPipeRead;
439 pData->IStream.pfnWrite = drvNamedPipeWrite;
440
441 /*
442 * Read the configuration.
443 */
444 if (!CFGMR3AreValuesValid(pCfgHandle, "Location\0IsServer\0"))
445 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
446
447 char *pszLocation;
448 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Location", &pszLocation);
449 if (VBOX_FAILURE(rc))
450 {
451 AssertMsgFailed(("Configuration error: query \"Location\" resulted in %Vrc.\n", rc));
452 return rc;
453 }
454 pData->pszLocation = pszLocation;
455
456 bool fIsServer;
457 rc = CFGMR3QueryBool(pCfgHandle, "IsServer", &fIsServer);
458 if (VBOX_FAILURE(rc))
459 {
460 AssertMsgFailed(("Configuration error: query \"IsServer\" resulted in %Vrc.\n", rc));
461 goto out;
462 }
463 pData->fIsServer = fIsServer;
464
465#ifdef __WIN__
466 if (fIsServer)
467 {
468 HANDLE hPipe = CreateNamedPipe(pData->pszLocation, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 32, 32, 10000, NULL);
469 if (hPipe == INVALID_HANDLE_VALUE)
470 {
471 rc = RTErrConvertFromWin32(GetLastError());
472 LogRel(("NamedPipe%d: CreateNamedPipe failed rc=%Vrc\n", pData->pDrvIns->iInstance));
473 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"), pDrvIns->iInstance, pszLocation);
474 }
475 pData->NamedPipe = (HFILE)hPipe;
476
477 rc = RTThreadCreate(&pData->ListenThread, drvNamedPipeListenLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "NamedPipe");
478 if VBOX_FAILURE(rc)
479 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread\n"), pDrvIns->iInstance);
480
481 rc = RTSemEventCreate(&pData->ListenSem);
482 AssertRC(rc);
483 }
484 else
485 {
486 /* Connect to the named pipe. */
487 rc = RTFileOpen(&pData->NamedPipe, pszLocation, RTFILE_O_READWRITE);
488 if (VBOX_FAILURE(rc))
489 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"), pDrvIns->iInstance, pszLocation);
490 }
491
492 memset(&pData->OverlappedWrite, 0, sizeof(pData->OverlappedWrite));
493 memset(&pData->OverlappedRead, 0, sizeof(pData->OverlappedRead));
494 pData->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
495 pData->OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
496#else /* !__WIN__ */
497 int s;
498 struct sockaddr_un addr;
499
500 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
501 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
502
503 memset(&addr, 0, sizeof(addr));
504 addr.sun_family = AF_UNIX;
505 strncpy(addr.sun_path, pszLocation, sizeof(addr.sun_path)-1);
506
507 if (fIsServer)
508 {
509 /* Bind address to the local socket. */
510 RTFileDelete(pszLocation);
511 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
512 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to bind to local socket %s"), pDrvIns->iInstance, pszLocation);
513 rc = RTThreadCreate(&pData->ListenThread, drvNamedPipeListenLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "NamedPipe");
514 if VBOX_FAILURE(rc)
515 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread\n"), pDrvIns->iInstance);
516 pData->LocalSocketServer = s;
517 }
518 else
519 {
520 /* Connect to the local socket. */
521 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
522 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to connect to local socket %s"), pDrvIns->iInstance, pszLocation);
523 pData->LocalSocket = s;
524 }
525#endif /* !__WIN__ */
526
527out:
528 if (VBOX_FAILURE(rc))
529 {
530 if (pszLocation)
531 MMR3HeapFree(pszLocation);
532 }
533 else
534 {
535 LogFlow(("drvNamedPipeConstruct: location %s isServer %d\n", pszLocation, fIsServer));
536 LogRel(("NamedPipe: location %s, %s\n", pszLocation, fIsServer ? "server" : "client"));
537 }
538 return rc;
539}
540
541
542/**
543 * Destruct a named pipe stream driver instance.
544 *
545 * Most VM resources are freed by the VM. This callback is provided so that
546 * any non-VM resources can be freed correctly.
547 *
548 * @param pDrvIns The driver instance data.
549 */
550static DECLCALLBACK(void) drvNamedPipeDestruct(PPDMDRVINS pDrvIns)
551{
552 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
553 LogFlow(("%s: %s\n", __FUNCTION__, pData->pszLocation));
554
555 if (pData->ListenThread)
556 {
557 RTThreadWait(pData->ListenThread, 250, NULL);
558 if (pData->ListenThread != NIL_RTTHREAD)
559 LogRel(("NamedPipe%d: listen thread did not terminate\n", pDrvIns->iInstance));
560 }
561
562 if (pData->pszLocation)
563 MMR3HeapFree(pData->pszLocation);
564}
565
566
567/**
568 * Power off a named pipe stream driver instance.
569 *
570 * This does most of the destruction work, to avoid ordering dependencies.
571 *
572 * @param pDrvIns The driver instance data.
573 */
574static DECLCALLBACK(void) drvNamedPipePowerOff(PPDMDRVINS pDrvIns)
575{
576 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
577 LogFlow(("%s: %s\n", __FUNCTION__, pData->pszLocation));
578
579 pData->fShutdown = true;
580
581#ifdef __WIN__
582 if (pData->NamedPipe != NIL_RTFILE)
583 {
584 FlushFileBuffers((HANDLE)pData->NamedPipe);
585 if (!pData->fIsServer)
586 DisconnectNamedPipe((HANDLE)pData->NamedPipe);
587
588 RTFileClose(pData->NamedPipe);
589 pData->NamedPipe = NIL_RTFILE;
590 CloseHandle(pData->OverlappedRead.hEvent);
591 CloseHandle(pData->OverlappedWrite.hEvent);
592 }
593 /* Wake up listen thread */
594 RTSemEventSignal(pData->ListenSem);
595 RTSemEventDestroy(pData->ListenSem);
596#else /* !__WIN__ */
597 if (pData->fIsServer)
598 {
599 if (pData->LocalSocketServer != NIL_RTSOCKET)
600 close(pData->LocalSocketServer);
601 if (pData->pszLocation)
602 RTFileDelete(pData->pszLocation);
603 }
604 else
605 {
606 if (pData->LocalSocket != NIL_RTSOCKET)
607 close(pData->LocalSocket);
608 }
609#endif /* !__WIN__ */
610}
611
612
613/**
614 * Named pipe driver registration record.
615 */
616const PDMDRVREG g_DrvNamedPipe =
617{
618 /* u32Version */
619 PDM_DRVREG_VERSION,
620 /* szDriverName */
621 "NamedPipe",
622 /* pszDescription */
623 "Named Pipe stream driver.",
624 /* fFlags */
625 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
626 /* fClass. */
627 PDM_DRVREG_CLASS_STREAM,
628 /* cMaxInstances */
629 ~0,
630 /* cbInstance */
631 sizeof(DRVNAMEDPIPE),
632 /* pfnConstruct */
633 drvNamedPipeConstruct,
634 /* pfnDestruct */
635 drvNamedPipeDestruct,
636 /* pfnIOCtl */
637 NULL,
638 /* pfnPowerOn */
639 NULL,
640 /* pfnReset */
641 NULL,
642 /* pfnSuspend */
643 NULL,
644 /* pfnResume */
645 NULL,
646 /* pfnDetach */
647 NULL,
648 /* pfnPowerOff */
649 drvNamedPipePowerOff,
650};
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