VirtualBox

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

Last change on this file since 6071 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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