VirtualBox

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

Last change on this file since 4849 was 4372, checked in by vboxsync, 17 years ago

Finally corrected the RTFileRead, RTFileReadAt, RTFileWrite and RTFileWriteAt APIs to size_t. This was long overdue.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.7 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 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
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 RTFILE 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 != NIL_RTFILE)
107 {
108 DWORD cbReallyRead;
109 pData->OverlappedRead.Offset = 0;
110 pData->OverlappedRead.OffsetHigh = 0;
111 if (!ReadFile((HANDLE)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((HANDLE)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 RTFILE tmp = pData->NamedPipe;
151 FlushFileBuffers((HANDLE)tmp);
152 DisconnectNamedPipe((HANDLE)tmp);
153 if (!pData->fIsServer)
154 {
155 pData->NamedPipe = NIL_RTFILE;
156 RTFileClose(tmp);
157 }
158 /* pretend success */
159 rc = VINF_SUCCESS;
160 }
161 cbReallyRead = 0;
162 }
163 *cbRead = (size_t)cbReallyRead;
164 }
165#else /* !RT_OS_WINDOWS */
166 if (pData->LocalSocket != NIL_RTSOCKET)
167 {
168 ssize_t cbReallyRead;
169 cbReallyRead = recv(pData->LocalSocket, pvBuf, *cbRead, 0);
170 if (cbReallyRead == 0)
171 {
172 RTSOCKET tmp = pData->LocalSocket;
173 pData->LocalSocket = NIL_RTSOCKET;
174 close(tmp);
175 }
176 else if (cbReallyRead == -1)
177 {
178 cbReallyRead = 0;
179 rc = RTErrConvertFromErrno(errno);
180 }
181 *cbRead = cbReallyRead;
182 }
183#endif /* !RT_OS_WINDOWS */
184 else
185 {
186 RTThreadSleep(100);
187 *cbRead = 0;
188 }
189
190 LogFlow(("%s: cbRead=%d returns %Vrc\n", __FUNCTION__, *cbRead, rc));
191 return rc;
192}
193
194
195/** @copydoc PDMISTREAM::pfnWrite */
196static DECLCALLBACK(int) drvNamedPipeWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *cbWrite)
197{
198 int rc = VINF_SUCCESS;
199 PDRVNAMEDPIPE pData = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
200 LogFlow(("%s: pvBuf=%p cbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, cbWrite, pData->pszLocation));
201
202 Assert(pvBuf);
203#ifdef RT_OS_WINDOWS
204 if (pData->NamedPipe != NIL_RTFILE)
205 {
206 unsigned cbWritten;
207 pData->OverlappedWrite.Offset = 0;
208 pData->OverlappedWrite.OffsetHigh = 0;
209 if (!WriteFile((HANDLE)pData->NamedPipe, pvBuf, *cbWrite, NULL, &pData->OverlappedWrite))
210 {
211 DWORD uError = GetLastError();
212
213 if ( uError == ERROR_PIPE_LISTENING
214 || uError == ERROR_PIPE_NOT_CONNECTED)
215 {
216 /* No connection yet/anymore; just discard the write. */
217 cbWritten = *cbWrite;
218 }
219 else
220 if (uError != ERROR_IO_PENDING)
221 {
222 rc = RTErrConvertFromWin32(uError);
223 Log(("drvNamedPipeWrite: WriteFile returned %d (%Vrc)\n", uError, rc));
224 }
225 else
226 {
227 /* Wait for the write to complete. */
228 if (GetOverlappedResult((HANDLE)pData->NamedPipe, &pData->OverlappedWrite, (DWORD *)&cbWritten, TRUE) == FALSE)
229 uError = GetLastError();
230 }
231 }
232 else
233 cbWritten = *cbWrite;
234
235 if (VBOX_FAILURE(rc))
236 {
237 if ( rc == VERR_EOF
238 || rc == VERR_BROKEN_PIPE)
239 {
240 RTFILE tmp = pData->NamedPipe;
241 FlushFileBuffers((HANDLE)tmp);
242 DisconnectNamedPipe((HANDLE)tmp);
243 if (!pData->fIsServer)
244 {
245 pData->NamedPipe = NIL_RTFILE;
246 RTFileClose(tmp);
247 }
248 /* pretend success */
249 rc = VINF_SUCCESS;
250 }
251 cbWritten = 0;
252 }
253 *cbWrite = cbWritten;
254 }
255#else /* !RT_OS_WINDOWS */
256 if (pData->LocalSocket != NIL_RTSOCKET)
257 {
258 ssize_t cbWritten;
259 cbWritten = send(pData->LocalSocket, pvBuf, *cbWrite, 0);
260 if (cbWritten == 0)
261 {
262 RTSOCKET tmp = pData->LocalSocket;
263 pData->LocalSocket = NIL_RTSOCKET;
264 close(tmp);
265 }
266 else if (cbWritten == -1)
267 {
268 cbWritten = 0;
269 rc = RTErrConvertFromErrno(errno);
270 }
271 *cbWrite = cbWritten;
272 }
273#endif /* !RT_OS_WINDOWS */
274
275 LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
276 return rc;
277}
278
279
280/**
281 * Queries an interface to the driver.
282 *
283 * @returns Pointer to interface.
284 * @returns NULL if the interface was not supported by the driver.
285 * @param pInterface Pointer to this interface structure.
286 * @param enmInterface The requested interface identification.
287 * @thread Any thread.
288 */
289static DECLCALLBACK(void *) drvNamedPipeQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
290{
291 PPDMDRVINS pDrvIns = PDMIBASE_2_DRVINS(pInterface);
292 PDRVNAMEDPIPE pDrv = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
293 switch (enmInterface)
294 {
295 case PDMINTERFACE_BASE:
296 return &pDrvIns->IBase;
297 case PDMINTERFACE_STREAM:
298 return &pDrv->IStream;
299 default:
300 return NULL;
301 }
302}
303
304
305/* -=-=-=-=- listen thread -=-=-=-=- */
306
307/**
308 * Receive thread loop.
309 *
310 * @returns 0 on success.
311 * @param ThreadSelf Thread handle to this thread.
312 * @param pvUser User argument.
313 */
314static DECLCALLBACK(int) drvNamedPipeListenLoop(RTTHREAD ThreadSelf, void *pvUser)
315{
316 PDRVNAMEDPIPE pData = (PDRVNAMEDPIPE)pvUser;
317 int rc = VINF_SUCCESS;
318#ifdef RT_OS_WINDOWS
319 RTFILE NamedPipe = pData->NamedPipe;
320 HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, 0);
321#endif
322
323 while (RT_LIKELY(!pData->fShutdown))
324 {
325#ifdef RT_OS_WINDOWS
326 OVERLAPPED overlapped;
327
328 memset(&overlapped, 0, sizeof(overlapped));
329 overlapped.hEvent = hEvent;
330
331 BOOL fConnected = ConnectNamedPipe((HANDLE)NamedPipe, &overlapped);
332 if ( !fConnected
333 && !pData->fShutdown)
334 {
335 DWORD hrc = GetLastError();
336
337 if (hrc == ERROR_IO_PENDING)
338 {
339 DWORD dummy;
340
341 hrc = 0;
342 if (GetOverlappedResult((HANDLE)pData->NamedPipe, &overlapped, &dummy, TRUE) == FALSE)
343 hrc = GetLastError();
344
345 }
346
347 if (pData->fShutdown)
348 break;
349
350 if (hrc == ERROR_PIPE_CONNECTED)
351 {
352 RTSemEventWait(pData->ListenSem, 250);
353 }
354 else
355 if (hrc != ERROR_SUCCESS)
356 {
357 rc = RTErrConvertFromWin32(hrc);
358 LogRel(("NamedPipe%d: ConnectNamedPipe failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
359 break;
360 }
361 }
362#else /* !RT_OS_WINDOWS */
363 if (listen(pData->LocalSocketServer, 0) == -1)
364 {
365 rc = RTErrConvertFromErrno(errno);
366 LogRel(("NamedPipe%d: listen failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
367 break;
368 }
369 int s = accept(pData->LocalSocketServer, NULL, NULL);
370 if (s == -1)
371 {
372 rc = RTErrConvertFromErrno(errno);
373 LogRel(("NamedPipe%d: accept failed, rc=%Vrc\n", pData->pDrvIns->iInstance, rc));
374 break;
375 }
376 else
377 {
378 if (pData->LocalSocket != NIL_RTSOCKET)
379 {
380 LogRel(("NamedPipe%d: only single connection supported\n", pData->pDrvIns->iInstance));
381 close(s);
382 }
383 else
384 pData->LocalSocket = s;
385 }
386#endif /* !RT_OS_WINDOWS */
387 }
388
389#ifdef RT_OS_WINDOWS
390 CloseHandle(hEvent);
391#endif
392 pData->ListenThread = NIL_RTTHREAD;
393 return VINF_SUCCESS;
394}
395
396
397/**
398 * Construct a named pipe stream driver instance.
399 *
400 * @returns VBox status.
401 * @param pDrvIns The driver instance data.
402 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
403 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
404 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
405 * iInstance it's expected to be used a bit in this function.
406 */
407static DECLCALLBACK(int) drvNamedPipeConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
408{
409 int rc;
410 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
411
412 /*
413 * Init the static parts.
414 */
415 pData->pDrvIns = pDrvIns;
416 pData->pszLocation = NULL;
417 pData->fIsServer = false;
418#ifdef RT_OS_WINDOWS
419 pData->NamedPipe = NIL_RTFILE;
420#else /* !RT_OS_WINDOWS */
421 pData->LocalSocketServer = NIL_RTSOCKET;
422 pData->LocalSocket = NIL_RTSOCKET;
423#endif /* !RT_OS_WINDOWS */
424 pData->ListenThread = NIL_RTTHREAD;
425 pData->fShutdown = false;
426 /* IBase */
427 pDrvIns->IBase.pfnQueryInterface = drvNamedPipeQueryInterface;
428 /* IStream */
429 pData->IStream.pfnRead = drvNamedPipeRead;
430 pData->IStream.pfnWrite = drvNamedPipeWrite;
431
432 /*
433 * Read the configuration.
434 */
435 if (!CFGMR3AreValuesValid(pCfgHandle, "Location\0IsServer\0"))
436 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
437
438 char *pszLocation;
439 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Location", &pszLocation);
440 if (VBOX_FAILURE(rc))
441 {
442 AssertMsgFailed(("Configuration error: query \"Location\" resulted in %Vrc.\n", rc));
443 return rc;
444 }
445 pData->pszLocation = pszLocation;
446
447 bool fIsServer;
448 rc = CFGMR3QueryBool(pCfgHandle, "IsServer", &fIsServer);
449 if (VBOX_FAILURE(rc))
450 {
451 AssertMsgFailed(("Configuration error: query \"IsServer\" resulted in %Vrc.\n", rc));
452 goto out;
453 }
454 pData->fIsServer = fIsServer;
455
456#ifdef RT_OS_WINDOWS
457 if (fIsServer)
458 {
459 HANDLE hPipe = CreateNamedPipe(pData->pszLocation, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 32, 32, 10000, NULL);
460 if (hPipe == INVALID_HANDLE_VALUE)
461 {
462 rc = RTErrConvertFromWin32(GetLastError());
463 LogRel(("NamedPipe%d: CreateNamedPipe failed rc=%Vrc\n", pData->pDrvIns->iInstance));
464 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"), pDrvIns->iInstance, pszLocation);
465 }
466 pData->NamedPipe = (HFILE)hPipe;
467
468 rc = RTThreadCreate(&pData->ListenThread, drvNamedPipeListenLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "NamedPipe");
469 if VBOX_FAILURE(rc)
470 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
471
472 rc = RTSemEventCreate(&pData->ListenSem);
473 AssertRC(rc);
474 }
475 else
476 {
477 /* Connect to the named pipe. */
478 rc = RTFileOpen(&pData->NamedPipe, pszLocation, RTFILE_O_READWRITE);
479 if (VBOX_FAILURE(rc))
480 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"), pDrvIns->iInstance, pszLocation);
481 }
482
483 memset(&pData->OverlappedWrite, 0, sizeof(pData->OverlappedWrite));
484 memset(&pData->OverlappedRead, 0, sizeof(pData->OverlappedRead));
485 pData->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
486 pData->OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
487#else /* !RT_OS_WINDOWS */
488 int s;
489 struct sockaddr_un addr;
490
491 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
492 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
493
494 memset(&addr, 0, sizeof(addr));
495 addr.sun_family = AF_UNIX;
496 strncpy(addr.sun_path, pszLocation, sizeof(addr.sun_path)-1);
497
498 if (fIsServer)
499 {
500 /* Bind address to the local socket. */
501 RTFileDelete(pszLocation);
502 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
503 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to bind to local socket %s"), pDrvIns->iInstance, pszLocation);
504 rc = RTThreadCreate(&pData->ListenThread, drvNamedPipeListenLoop, (void *)pData, 0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "NamedPipe");
505 if VBOX_FAILURE(rc)
506 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
507 pData->LocalSocketServer = s;
508 }
509 else
510 {
511 /* Connect to the local socket. */
512 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
513 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS, N_("NamedPipe#%d failed to connect to local socket %s"), pDrvIns->iInstance, pszLocation);
514 pData->LocalSocket = s;
515 }
516#endif /* !RT_OS_WINDOWS */
517
518out:
519 if (VBOX_FAILURE(rc))
520 {
521 if (pszLocation)
522 MMR3HeapFree(pszLocation);
523 }
524 else
525 {
526 LogFlow(("drvNamedPipeConstruct: location %s isServer %d\n", pszLocation, fIsServer));
527 LogRel(("NamedPipe: location %s, %s\n", pszLocation, fIsServer ? "server" : "client"));
528 }
529 return rc;
530}
531
532
533/**
534 * Destruct a named pipe stream driver instance.
535 *
536 * Most VM resources are freed by the VM. This callback is provided so that
537 * any non-VM resources can be freed correctly.
538 *
539 * @param pDrvIns The driver instance data.
540 */
541static DECLCALLBACK(void) drvNamedPipeDestruct(PPDMDRVINS pDrvIns)
542{
543 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
544 LogFlow(("%s: %s\n", __FUNCTION__, pData->pszLocation));
545
546 if (pData->ListenThread)
547 {
548 RTThreadWait(pData->ListenThread, 250, NULL);
549 if (pData->ListenThread != NIL_RTTHREAD)
550 LogRel(("NamedPipe%d: listen thread did not terminate\n", pDrvIns->iInstance));
551 }
552
553 if (pData->pszLocation)
554 MMR3HeapFree(pData->pszLocation);
555}
556
557
558/**
559 * Power off a named pipe stream driver instance.
560 *
561 * This does most of the destruction work, to avoid ordering dependencies.
562 *
563 * @param pDrvIns The driver instance data.
564 */
565static DECLCALLBACK(void) drvNamedPipePowerOff(PPDMDRVINS pDrvIns)
566{
567 PDRVNAMEDPIPE pData = PDMINS2DATA(pDrvIns, PDRVNAMEDPIPE);
568 LogFlow(("%s: %s\n", __FUNCTION__, pData->pszLocation));
569
570 pData->fShutdown = true;
571
572#ifdef RT_OS_WINDOWS
573 if (pData->NamedPipe != NIL_RTFILE)
574 {
575 FlushFileBuffers((HANDLE)pData->NamedPipe);
576 if (!pData->fIsServer)
577 DisconnectNamedPipe((HANDLE)pData->NamedPipe);
578
579 RTFileClose(pData->NamedPipe);
580 pData->NamedPipe = NIL_RTFILE;
581 CloseHandle(pData->OverlappedRead.hEvent);
582 CloseHandle(pData->OverlappedWrite.hEvent);
583 }
584 /* Wake up listen thread */
585 RTSemEventSignal(pData->ListenSem);
586 RTSemEventDestroy(pData->ListenSem);
587#else /* !RT_OS_WINDOWS */
588 if (pData->fIsServer)
589 {
590 if (pData->LocalSocketServer != NIL_RTSOCKET)
591 close(pData->LocalSocketServer);
592 if (pData->pszLocation)
593 RTFileDelete(pData->pszLocation);
594 }
595 else
596 {
597 if (pData->LocalSocket != NIL_RTSOCKET)
598 close(pData->LocalSocket);
599 }
600#endif /* !RT_OS_WINDOWS */
601}
602
603
604/**
605 * Named pipe driver registration record.
606 */
607const PDMDRVREG g_DrvNamedPipe =
608{
609 /* u32Version */
610 PDM_DRVREG_VERSION,
611 /* szDriverName */
612 "NamedPipe",
613 /* pszDescription */
614 "Named Pipe stream driver.",
615 /* fFlags */
616 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
617 /* fClass. */
618 PDM_DRVREG_CLASS_STREAM,
619 /* cMaxInstances */
620 ~0,
621 /* cbInstance */
622 sizeof(DRVNAMEDPIPE),
623 /* pfnConstruct */
624 drvNamedPipeConstruct,
625 /* pfnDestruct */
626 drvNamedPipeDestruct,
627 /* pfnIOCtl */
628 NULL,
629 /* pfnPowerOn */
630 NULL,
631 /* pfnReset */
632 NULL,
633 /* pfnSuspend */
634 NULL,
635 /* pfnResume */
636 NULL,
637 /* pfnDetach */
638 NULL,
639 /* pfnPowerOff */
640 drvNamedPipePowerOff,
641};
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