VirtualBox

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

Last change on this file since 5822 was 5756, checked in by vboxsync, 17 years ago

Client end of named pipe must be opened in overlapped mode, else writes from client
will be severely delayed and the client VM will get stuck on disconnect.

Also changed the type of NamedPipe variable to HANDLE to avoid casts and replaced
calls to RTFileClose with CloseHandle since all other calls operating on NamedPipe
were Windows API anyway.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.9 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 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.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette