VirtualBox

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

Last change on this file since 59381 was 57882, checked in by vboxsync, 9 years ago

Serial/NamedPipe: Reorder error checks in the receive code path on Windows. Looks like Kaspersky AV changes the behavior of the named pipe API when hooking into it, always returning ERROR_IO_PENDING on an overlapped read even if no other process connected to the named pipe yet. ERROR_PIPE_LISTENING is returned as the overlapped result making our error checks trip and aborting the receive thread. The fix moves the check for ERROR_IO_PENDING to the front so it executed first and the check for other non fatal errors is done afterwards

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.6 KB
Line 
1/* $Id: DrvNamedPipe.cpp 57882 2015-09-24 14:40:39Z vboxsync $ */
2/** @file
3 * Named pipe / local socket stream driver.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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#define LOG_GROUP LOG_GROUP_DRV_NAMEDPIPE
23#include <VBox/vmm/pdmdrv.h>
24#include <iprt/assert.h>
25#include <iprt/file.h>
26#include <iprt/stream.h>
27#include <iprt/alloc.h>
28#include <iprt/string.h>
29#include <iprt/semaphore.h>
30#include <iprt/uuid.h>
31
32#include "VBoxDD.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# ifndef SHUT_RDWR /* OS/2 */
43# define SHUT_RDWR 3
44# endif
45#endif /* !RT_OS_WINDOWS */
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51/** Converts a pointer to DRVNAMEDPIPE::IMedia to a PDRVNAMEDPIPE. */
52#define PDMISTREAM_2_DRVNAMEDPIPE(pInterface) ( (PDRVNAMEDPIPE)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAMEDPIPE, IStream)) )
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58/**
59 * Named pipe driver instance data.
60 *
61 * @implements PDMISTREAM
62 */
63typedef struct DRVNAMEDPIPE
64{
65 /** The stream interface. */
66 PDMISTREAM IStream;
67 /** Pointer to the driver instance. */
68 PPDMDRVINS pDrvIns;
69 /** Pointer to the named pipe file name. (Freed by MM) */
70 char *pszLocation;
71 /** Flag whether VirtualBox represents the server or client side. */
72 bool fIsServer;
73#ifdef RT_OS_WINDOWS
74 /** File handle of the named pipe. */
75 HANDLE NamedPipe;
76 /** Overlapped structure for writes. */
77 OVERLAPPED OverlappedWrite;
78 /** Overlapped structure for reads. */
79 OVERLAPPED OverlappedRead;
80 /** Listen thread wakeup semaphore */
81 RTSEMEVENTMULTI ListenSem;
82#else /* !RT_OS_WINDOWS */
83 /** Socket handle of the local socket for server. */
84 int LocalSocketServer;
85 /** Socket handle of the local socket. */
86 int LocalSocket;
87#endif /* !RT_OS_WINDOWS */
88 /** Thread for listening for new connections. */
89 RTTHREAD ListenThread;
90 /** Flag to signal listening thread to shut down. */
91 bool volatile fShutdown;
92} DRVNAMEDPIPE, *PDRVNAMEDPIPE;
93
94
95/*********************************************************************************************************************************
96* Internal Functions *
97*********************************************************************************************************************************/
98
99
100/** @copydoc PDMISTREAM::pfnRead */
101static DECLCALLBACK(int) drvNamedPipeRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)
102{
103 int rc = VINF_SUCCESS;
104 PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
105 LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation));
106
107 Assert(pvBuf);
108#ifdef RT_OS_WINDOWS
109 if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
110 {
111 DWORD cbReallyRead;
112 pThis->OverlappedRead.Offset = 0;
113 pThis->OverlappedRead.OffsetHigh = 0;
114 if (!ReadFile(pThis->NamedPipe, pvBuf, (DWORD)*pcbRead, &cbReallyRead, &pThis->OverlappedRead))
115 {
116 DWORD uError = GetLastError();
117
118 if (uError == ERROR_IO_PENDING)
119 {
120 uError = 0;
121
122 /* Wait for incoming bytes. */
123 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedRead, &cbReallyRead, TRUE) == FALSE)
124 uError = GetLastError();
125 }
126
127 if ( uError == ERROR_PIPE_LISTENING
128 || uError == ERROR_PIPE_NOT_CONNECTED)
129 {
130 /* No connection yet/anymore */
131 cbReallyRead = 0;
132
133 /* wait a bit or else we'll be called right back. */
134 RTThreadSleep(100);
135 }
136 else
137 {
138 rc = RTErrConvertFromWin32(uError);
139 Log(("drvNamedPipeRead: ReadFile returned %d (%Rrc)\n", uError, rc));
140 }
141 }
142
143 if (RT_FAILURE(rc))
144 {
145 Log(("drvNamedPipeRead: FileRead returned %Rrc fShutdown=%d\n", rc, pThis->fShutdown));
146 if ( !pThis->fShutdown
147 && ( rc == VERR_EOF
148 || rc == VERR_BROKEN_PIPE
149 )
150 )
151 {
152 FlushFileBuffers(pThis->NamedPipe);
153 DisconnectNamedPipe(pThis->NamedPipe);
154 if (!pThis->fIsServer)
155 {
156 CloseHandle(pThis->NamedPipe);
157 pThis->NamedPipe = INVALID_HANDLE_VALUE;
158 }
159 /* pretend success */
160 rc = VINF_SUCCESS;
161 }
162 cbReallyRead = 0;
163 }
164 *pcbRead = (size_t)cbReallyRead;
165 }
166#else /* !RT_OS_WINDOWS */
167 if (pThis->LocalSocket != -1)
168 {
169 ssize_t cbReallyRead;
170 cbReallyRead = recv(pThis->LocalSocket, pvBuf, *pcbRead, 0);
171 if (cbReallyRead == 0)
172 {
173 int tmp = pThis->LocalSocket;
174 pThis->LocalSocket = -1;
175 close(tmp);
176 }
177 else if (cbReallyRead == -1)
178 {
179 cbReallyRead = 0;
180 rc = RTErrConvertFromErrno(errno);
181 }
182 *pcbRead = cbReallyRead;
183 }
184#endif /* !RT_OS_WINDOWS */
185 else
186 {
187 RTThreadSleep(100);
188 *pcbRead = 0;
189 }
190
191 LogFlow(("%s: *pcbRead=%zu returns %Rrc\n", __FUNCTION__, *pcbRead, rc));
192 return rc;
193}
194
195
196/** @copydoc PDMISTREAM::pfnWrite */
197static DECLCALLBACK(int) drvNamedPipeWrite(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)
198{
199 int rc = VINF_SUCCESS;
200 PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
201 LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
202
203 Assert(pvBuf);
204#ifdef RT_OS_WINDOWS
205 if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
206 {
207 DWORD cbWritten = (DWORD)*pcbWrite;
208 pThis->OverlappedWrite.Offset = 0;
209 pThis->OverlappedWrite.OffsetHigh = 0;
210 if (!WriteFile(pThis->NamedPipe, pvBuf, cbWritten, NULL, &pThis->OverlappedWrite))
211 {
212 DWORD uError = GetLastError();
213
214 if ( uError == ERROR_PIPE_LISTENING
215 || uError == ERROR_PIPE_NOT_CONNECTED)
216 {
217 /* No connection yet/anymore; just discard the write (pretending everything was written). */;
218 }
219 else if (uError != ERROR_IO_PENDING)
220 {
221 rc = RTErrConvertFromWin32(uError);
222 Log(("drvNamedPipeWrite: WriteFile returned %d (%Rrc)\n", uError, rc));
223 cbWritten = 0;
224 }
225 else
226 {
227 /* Wait for the write to complete. */
228 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedWrite, &cbWritten, TRUE /*bWait*/) == FALSE)
229 rc = RTErrConvertFromWin32(uError = GetLastError());
230 }
231 }
232
233 if (RT_FAILURE(rc))
234 {
235 /** @todo WriteFile(pipe) has been observed to return ERROR_NO_DATA
236 * (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
237 * disconnected. */
238 if ( rc == VERR_EOF
239 || rc == VERR_BROKEN_PIPE)
240 {
241 FlushFileBuffers(pThis->NamedPipe);
242 DisconnectNamedPipe(pThis->NamedPipe);
243 if (!pThis->fIsServer)
244 {
245 CloseHandle(pThis->NamedPipe);
246 pThis->NamedPipe = INVALID_HANDLE_VALUE;
247 }
248 /* pretend success */
249 rc = VINF_SUCCESS;
250 }
251 cbWritten = 0;
252 }
253 *pcbWrite = cbWritten;
254 }
255#else /* !RT_OS_WINDOWS */
256 if (pThis->LocalSocket != -1)
257 {
258 ssize_t cbWritten;
259 cbWritten = send(pThis->LocalSocket, pvBuf, *pcbWrite, 0);
260 if (cbWritten == 0)
261 {
262 int tmp = pThis->LocalSocket;
263 pThis->LocalSocket = -1;
264 close(tmp);
265 }
266 else if (cbWritten == -1)
267 {
268 cbWritten = 0;
269 rc = RTErrConvertFromErrno(errno);
270 }
271 *pcbWrite = cbWritten;
272 }
273#endif /* !RT_OS_WINDOWS */
274
275 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
276 return rc;
277}
278
279
280/**
281 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
282 */
283static DECLCALLBACK(void *) drvNamedPipeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
284{
285 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
286 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
287 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
288 PDMIBASE_RETURN_INTERFACE(pszIID, PDMISTREAM, &pThis->IStream);
289 return NULL;
290}
291
292
293/* -=-=-=-=- listen thread -=-=-=-=- */
294
295/**
296 * Receive thread loop.
297 *
298 * @returns 0 on success.
299 * @param ThreadSelf Thread handle to this thread.
300 * @param pvUser User argument.
301 */
302static DECLCALLBACK(int) drvNamedPipeListenLoop(RTTHREAD ThreadSelf, void *pvUser)
303{
304 PDRVNAMEDPIPE pThis = (PDRVNAMEDPIPE)pvUser;
305 int rc = VINF_SUCCESS;
306#ifdef RT_OS_WINDOWS
307 HANDLE NamedPipe = pThis->NamedPipe;
308 HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, 0);
309#endif
310
311 while (RT_LIKELY(!pThis->fShutdown))
312 {
313#ifdef RT_OS_WINDOWS
314 OVERLAPPED overlapped;
315
316 memset(&overlapped, 0, sizeof(overlapped));
317 overlapped.hEvent = hEvent;
318
319 BOOL fConnected = ConnectNamedPipe(NamedPipe, &overlapped);
320 if ( !fConnected
321 && !pThis->fShutdown)
322 {
323 DWORD hrc = GetLastError();
324
325 if (hrc == ERROR_IO_PENDING)
326 {
327 DWORD dummy;
328
329 hrc = 0;
330 if (GetOverlappedResult(pThis->NamedPipe, &overlapped, &dummy, TRUE) == FALSE)
331 hrc = GetLastError();
332
333 }
334
335 if (pThis->fShutdown)
336 break;
337
338 if (hrc == ERROR_PIPE_CONNECTED)
339 {
340 RTSemEventMultiWait(pThis->ListenSem, 250);
341 }
342 else if (hrc != ERROR_SUCCESS)
343 {
344 rc = RTErrConvertFromWin32(hrc);
345 LogRel(("NamedPipe%d: ConnectNamedPipe failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
346 break;
347 }
348 }
349#else /* !RT_OS_WINDOWS */
350 if (listen(pThis->LocalSocketServer, 0) == -1)
351 {
352 rc = RTErrConvertFromErrno(errno);
353 LogRel(("NamedPipe%d: listen failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
354 break;
355 }
356 int s = accept(pThis->LocalSocketServer, NULL, NULL);
357 if (s == -1)
358 {
359 rc = RTErrConvertFromErrno(errno);
360 LogRel(("NamedPipe%d: accept failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
361 break;
362 }
363 if (pThis->LocalSocket != -1)
364 {
365 LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance));
366 close(s);
367 }
368 else
369 pThis->LocalSocket = s;
370
371#endif /* !RT_OS_WINDOWS */
372 }
373
374#ifdef RT_OS_WINDOWS
375 CloseHandle(hEvent);
376#endif
377 return VINF_SUCCESS;
378}
379
380/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
381
382/**
383 * Common worker for drvNamedPipePowerOff and drvNamedPipeDestructor.
384 *
385 * @param pThis The instance data.
386 */
387static void drvNamedPipeShutdownListener(PDRVNAMEDPIPE pThis)
388{
389 /*
390 * Signal shutdown of the listener thread.
391 */
392 pThis->fShutdown = true;
393#ifdef RT_OS_WINDOWS
394 if ( pThis->fIsServer
395 && pThis->NamedPipe != INVALID_HANDLE_VALUE)
396 {
397 FlushFileBuffers(pThis->NamedPipe);
398 DisconnectNamedPipe(pThis->NamedPipe);
399
400 BOOL fRc = CloseHandle(pThis->NamedPipe);
401 Assert(fRc); NOREF(fRc);
402 pThis->NamedPipe = INVALID_HANDLE_VALUE;
403
404 /* Wake up listen thread */
405 if (pThis->ListenSem != NIL_RTSEMEVENT)
406 RTSemEventMultiSignal(pThis->ListenSem);
407 }
408#else
409 if ( pThis->fIsServer
410 && pThis->LocalSocketServer != -1)
411 {
412 int rc = shutdown(pThis->LocalSocketServer, SHUT_RDWR);
413 AssertRC(rc == 0); NOREF(rc);
414
415 rc = close(pThis->LocalSocketServer);
416 AssertRC(rc == 0);
417 pThis->LocalSocketServer = -1;
418 }
419#endif
420}
421
422
423/**
424 * Power off a named pipe stream driver instance.
425 *
426 * This does most of the destruction work, to avoid ordering dependencies.
427 *
428 * @param pDrvIns The driver instance data.
429 */
430static DECLCALLBACK(void) drvNamedPipePowerOff(PPDMDRVINS pDrvIns)
431{
432 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
433 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
434
435 drvNamedPipeShutdownListener(pThis);
436}
437
438
439/**
440 * Destruct a named pipe stream driver instance.
441 *
442 * Most VM resources are freed by the VM. This callback is provided so that
443 * any non-VM resources can be freed correctly.
444 *
445 * @param pDrvIns The driver instance data.
446 */
447static DECLCALLBACK(void) drvNamedPipeDestruct(PPDMDRVINS pDrvIns)
448{
449 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
450 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
451 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
452
453 drvNamedPipeShutdownListener(pThis);
454
455 /*
456 * While the thread exits, clean up as much as we can.
457 */
458#ifdef RT_OS_WINDOWS
459 if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
460 {
461 CloseHandle(pThis->NamedPipe);
462 pThis->NamedPipe = INVALID_HANDLE_VALUE;
463 }
464 if (pThis->OverlappedRead.hEvent != NULL)
465 {
466 CloseHandle(pThis->OverlappedRead.hEvent);
467 pThis->OverlappedRead.hEvent = NULL;
468 }
469 if (pThis->OverlappedWrite.hEvent != NULL)
470 {
471 CloseHandle(pThis->OverlappedWrite.hEvent);
472 pThis->OverlappedWrite.hEvent = NULL;
473 }
474#else /* !RT_OS_WINDOWS */
475 Assert(pThis->LocalSocketServer == -1);
476 if (pThis->LocalSocket != -1)
477 {
478 int rc = shutdown(pThis->LocalSocket, SHUT_RDWR);
479 AssertRC(rc == 0); NOREF(rc);
480
481 rc = close(pThis->LocalSocket);
482 Assert(rc == 0);
483 pThis->LocalSocket = -1;
484 }
485 if ( pThis->fIsServer
486 && pThis->pszLocation)
487 RTFileDelete(pThis->pszLocation);
488#endif /* !RT_OS_WINDOWS */
489
490 MMR3HeapFree(pThis->pszLocation);
491 pThis->pszLocation = NULL;
492
493 /*
494 * Wait for the thread.
495 */
496 if (pThis->ListenThread != NIL_RTTHREAD)
497 {
498 int rc = RTThreadWait(pThis->ListenThread, 30000, NULL);
499 if (RT_SUCCESS(rc))
500 pThis->ListenThread = NIL_RTTHREAD;
501 else
502 LogRel(("NamedPipe%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
503 }
504
505 /*
506 * The last bits of cleanup.
507 */
508#ifdef RT_OS_WINDOWS
509 if (pThis->ListenSem != NIL_RTSEMEVENT)
510 {
511 RTSemEventMultiDestroy(pThis->ListenSem);
512 pThis->ListenSem = NIL_RTSEMEVENT;
513 }
514#endif
515}
516
517
518/**
519 * Construct a named pipe stream driver instance.
520 *
521 * @copydoc FNPDMDRVCONSTRUCT
522 */
523static DECLCALLBACK(int) drvNamedPipeConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
524{
525 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
526 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
527
528 /*
529 * Init the static parts.
530 */
531 pThis->pDrvIns = pDrvIns;
532 pThis->pszLocation = NULL;
533 pThis->fIsServer = false;
534#ifdef RT_OS_WINDOWS
535 pThis->NamedPipe = INVALID_HANDLE_VALUE;
536 pThis->ListenSem = NIL_RTSEMEVENTMULTI;
537 pThis->OverlappedWrite.hEvent = NULL;
538 pThis->OverlappedRead.hEvent = NULL;
539#else /* !RT_OS_WINDOWS */
540 pThis->LocalSocketServer = -1;
541 pThis->LocalSocket = -1;
542#endif /* !RT_OS_WINDOWS */
543 pThis->ListenThread = NIL_RTTHREAD;
544 pThis->fShutdown = false;
545 /* IBase */
546 pDrvIns->IBase.pfnQueryInterface = drvNamedPipeQueryInterface;
547 /* IStream */
548 pThis->IStream.pfnRead = drvNamedPipeRead;
549 pThis->IStream.pfnWrite = drvNamedPipeWrite;
550
551 /*
552 * Validate and read the configuration.
553 */
554 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", "");
555
556 int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
557 if (RT_FAILURE(rc))
558 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
559 N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
560 rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer);
561 if (RT_FAILURE(rc))
562 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
563 N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc);
564
565 /*
566 * Create/Open the pipe.
567 */
568#ifdef RT_OS_WINDOWS
569 if (pThis->fIsServer)
570 {
571 pThis->NamedPipe = CreateNamedPipe(pThis->pszLocation,
572 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
573 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
574 1, /*nMaxInstances*/
575 32, /*nOutBufferSize*/
576 32, /*nOutBufferSize*/
577 10000, /*nDefaultTimeOut*/
578 NULL); /* lpSecurityAttributes*/
579 if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
580 {
581 rc = RTErrConvertFromWin32(GetLastError());
582 LogRel(("NamedPipe%d: CreateNamedPipe failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
583 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"),
584 pDrvIns->iInstance, pThis->pszLocation);
585 }
586
587 rc = RTSemEventMultiCreate(&pThis->ListenSem);
588 AssertRCReturn(rc, rc);
589
590 rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
591 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
592 if (RT_FAILURE(rc))
593 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"),
594 pDrvIns->iInstance);
595
596 }
597 else
598 {
599 /* Connect to the named pipe. */
600 pThis->NamedPipe = CreateFile(pThis->pszLocation, GENERIC_READ | GENERIC_WRITE, 0, NULL,
601 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
602 if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
603 {
604 rc = RTErrConvertFromWin32(GetLastError());
605 LogRel(("NamedPipe%d: CreateFile failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
606 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"),
607 pDrvIns->iInstance, pThis->pszLocation);
608 }
609 }
610
611 memset(&pThis->OverlappedWrite, 0, sizeof(pThis->OverlappedWrite));
612 pThis->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
613 AssertReturn(pThis->OverlappedWrite.hEvent != NULL, VERR_OUT_OF_RESOURCES);
614
615 memset(&pThis->OverlappedRead, 0, sizeof(pThis->OverlappedRead));
616 pThis->OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
617 AssertReturn(pThis->OverlappedRead.hEvent != NULL, VERR_OUT_OF_RESOURCES);
618
619#else /* !RT_OS_WINDOWS */
620 int s = socket(PF_UNIX, SOCK_STREAM, 0);
621 if (s == -1)
622 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
623 N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
624
625 struct sockaddr_un addr;
626 memset(&addr, 0, sizeof(addr));
627 addr.sun_family = AF_UNIX;
628 strncpy(addr.sun_path, pThis->pszLocation, sizeof(addr.sun_path) - 1);
629
630 if (pThis->fIsServer)
631 {
632 /* Bind address to the local socket. */
633 pThis->LocalSocketServer = s;
634 RTFileDelete(pThis->pszLocation);
635 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
636 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
637 N_("NamedPipe#%d failed to bind to local socket %s"),
638 pDrvIns->iInstance, pThis->pszLocation);
639 rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
640 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
641 if (RT_FAILURE(rc))
642 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
643 N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
644 }
645 else
646 {
647 /* Connect to the local socket. */
648 pThis->LocalSocket = s;
649 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
650 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
651 N_("NamedPipe#%d failed to connect to local socket %s"),
652 pDrvIns->iInstance, pThis->pszLocation);
653 }
654#endif /* !RT_OS_WINDOWS */
655
656 LogRel(("NamedPipe: location %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client"));
657 return VINF_SUCCESS;
658}
659
660
661/**
662 * Named pipe driver registration record.
663 */
664const PDMDRVREG g_DrvNamedPipe =
665{
666 /* u32Version */
667 PDM_DRVREG_VERSION,
668 /* szName */
669 "NamedPipe",
670 /* szRCMod */
671 "",
672 /* szR0Mod */
673 "",
674 /* pszDescription */
675 "Named Pipe stream driver.",
676 /* fFlags */
677 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
678 /* fClass. */
679 PDM_DRVREG_CLASS_STREAM,
680 /* cMaxInstances */
681 ~0U,
682 /* cbInstance */
683 sizeof(DRVNAMEDPIPE),
684 /* pfnConstruct */
685 drvNamedPipeConstruct,
686 /* pfnDestruct */
687 drvNamedPipeDestruct,
688 /* pfnRelocate */
689 NULL,
690 /* pfnIOCtl */
691 NULL,
692 /* pfnPowerOn */
693 NULL,
694 /* pfnReset */
695 NULL,
696 /* pfnSuspend */
697 NULL,
698 /* pfnResume */
699 NULL,
700 /* pfnAttach */
701 NULL,
702 /* pfnDetach */
703 NULL,
704 /* pfnPowerOff */
705 drvNamedPipePowerOff,
706 /* pfnSoftReset */
707 NULL,
708 /* u32EndVersion */
709 PDM_DRVREG_VERSION
710};
711
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