VirtualBox

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

Last change on this file since 63495 was 62956, checked in by vboxsync, 8 years ago

@copydoc -> @interface_method_impl

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 KB
Line 
1/* $Id: DrvNamedPipe.cpp 62956 2016-08-04 07:49:34Z vboxsync $ */
2/** @file
3 * Named pipe / local socket stream driver.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 <iprt/win/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/** @interface_method_impl{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/** @interface_method_impl{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 hThreadSelf Thread handle to this thread.
300 * @param pvUser User argument.
301 */
302static DECLCALLBACK(int) drvNamedPipeListenLoop(RTTHREAD hThreadSelf, void *pvUser)
303{
304 RT_NOREF(hThreadSelf);
305 PDRVNAMEDPIPE pThis = (PDRVNAMEDPIPE)pvUser;
306 int rc = VINF_SUCCESS;
307#ifdef RT_OS_WINDOWS
308 HANDLE NamedPipe = pThis->NamedPipe;
309 HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, 0);
310#endif
311
312 while (RT_LIKELY(!pThis->fShutdown))
313 {
314#ifdef RT_OS_WINDOWS
315 OVERLAPPED overlapped;
316
317 memset(&overlapped, 0, sizeof(overlapped));
318 overlapped.hEvent = hEvent;
319
320 BOOL fConnected = ConnectNamedPipe(NamedPipe, &overlapped);
321 if ( !fConnected
322 && !pThis->fShutdown)
323 {
324 DWORD hrc = GetLastError();
325
326 if (hrc == ERROR_IO_PENDING)
327 {
328 DWORD dummy;
329
330 hrc = 0;
331 if (GetOverlappedResult(pThis->NamedPipe, &overlapped, &dummy, TRUE) == FALSE)
332 hrc = GetLastError();
333
334 }
335
336 if (pThis->fShutdown)
337 break;
338
339 if (hrc == ERROR_PIPE_CONNECTED)
340 {
341 RTSemEventMultiWait(pThis->ListenSem, 250);
342 }
343 else if (hrc != ERROR_SUCCESS)
344 {
345 rc = RTErrConvertFromWin32(hrc);
346 LogRel(("NamedPipe%d: ConnectNamedPipe failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
347 break;
348 }
349 }
350#else /* !RT_OS_WINDOWS */
351 if (listen(pThis->LocalSocketServer, 0) == -1)
352 {
353 rc = RTErrConvertFromErrno(errno);
354 LogRel(("NamedPipe%d: listen failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
355 break;
356 }
357 int s = accept(pThis->LocalSocketServer, NULL, NULL);
358 if (s == -1)
359 {
360 rc = RTErrConvertFromErrno(errno);
361 LogRel(("NamedPipe%d: accept failed, rc=%Rrc\n", pThis->pDrvIns->iInstance, rc));
362 break;
363 }
364 if (pThis->LocalSocket != -1)
365 {
366 LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance));
367 close(s);
368 }
369 else
370 pThis->LocalSocket = s;
371
372#endif /* !RT_OS_WINDOWS */
373 }
374
375#ifdef RT_OS_WINDOWS
376 CloseHandle(hEvent);
377#endif
378 return VINF_SUCCESS;
379}
380
381/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
382
383/**
384 * Common worker for drvNamedPipePowerOff and drvNamedPipeDestructor.
385 *
386 * @param pThis The instance data.
387 */
388static void drvNamedPipeShutdownListener(PDRVNAMEDPIPE pThis)
389{
390 /*
391 * Signal shutdown of the listener thread.
392 */
393 pThis->fShutdown = true;
394#ifdef RT_OS_WINDOWS
395 if ( pThis->fIsServer
396 && pThis->NamedPipe != INVALID_HANDLE_VALUE)
397 {
398 FlushFileBuffers(pThis->NamedPipe);
399 DisconnectNamedPipe(pThis->NamedPipe);
400
401 BOOL fRc = CloseHandle(pThis->NamedPipe);
402 Assert(fRc); NOREF(fRc);
403 pThis->NamedPipe = INVALID_HANDLE_VALUE;
404
405 /* Wake up listen thread */
406 if (pThis->ListenSem != NIL_RTSEMEVENT)
407 RTSemEventMultiSignal(pThis->ListenSem);
408 }
409#else
410 if ( pThis->fIsServer
411 && pThis->LocalSocketServer != -1)
412 {
413 int rc = shutdown(pThis->LocalSocketServer, SHUT_RDWR);
414 AssertRC(rc == 0); NOREF(rc);
415
416 rc = close(pThis->LocalSocketServer);
417 AssertRC(rc == 0);
418 pThis->LocalSocketServer = -1;
419 }
420#endif
421}
422
423
424/**
425 * Power off a named pipe stream driver instance.
426 *
427 * This does most of the destruction work, to avoid ordering dependencies.
428 *
429 * @param pDrvIns The driver instance data.
430 */
431static DECLCALLBACK(void) drvNamedPipePowerOff(PPDMDRVINS pDrvIns)
432{
433 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
434 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
435
436 drvNamedPipeShutdownListener(pThis);
437}
438
439
440/**
441 * Destruct a named pipe stream driver instance.
442 *
443 * Most VM resources are freed by the VM. This callback is provided so that
444 * any non-VM resources can be freed correctly.
445 *
446 * @param pDrvIns The driver instance data.
447 */
448static DECLCALLBACK(void) drvNamedPipeDestruct(PPDMDRVINS pDrvIns)
449{
450 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
451 LogFlow(("%s: %s\n", __FUNCTION__, pThis->pszLocation));
452 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
453
454 drvNamedPipeShutdownListener(pThis);
455
456 /*
457 * While the thread exits, clean up as much as we can.
458 */
459#ifdef RT_OS_WINDOWS
460 if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
461 {
462 CloseHandle(pThis->NamedPipe);
463 pThis->NamedPipe = INVALID_HANDLE_VALUE;
464 }
465 if (pThis->OverlappedRead.hEvent != NULL)
466 {
467 CloseHandle(pThis->OverlappedRead.hEvent);
468 pThis->OverlappedRead.hEvent = NULL;
469 }
470 if (pThis->OverlappedWrite.hEvent != NULL)
471 {
472 CloseHandle(pThis->OverlappedWrite.hEvent);
473 pThis->OverlappedWrite.hEvent = NULL;
474 }
475#else /* !RT_OS_WINDOWS */
476 Assert(pThis->LocalSocketServer == -1);
477 if (pThis->LocalSocket != -1)
478 {
479 int rc = shutdown(pThis->LocalSocket, SHUT_RDWR);
480 AssertRC(rc == 0); NOREF(rc);
481
482 rc = close(pThis->LocalSocket);
483 Assert(rc == 0);
484 pThis->LocalSocket = -1;
485 }
486 if ( pThis->fIsServer
487 && pThis->pszLocation)
488 RTFileDelete(pThis->pszLocation);
489#endif /* !RT_OS_WINDOWS */
490
491 MMR3HeapFree(pThis->pszLocation);
492 pThis->pszLocation = NULL;
493
494 /*
495 * Wait for the thread.
496 */
497 if (pThis->ListenThread != NIL_RTTHREAD)
498 {
499 int rc = RTThreadWait(pThis->ListenThread, 30000, NULL);
500 if (RT_SUCCESS(rc))
501 pThis->ListenThread = NIL_RTTHREAD;
502 else
503 LogRel(("NamedPipe%d: listen thread did not terminate (%Rrc)\n", pDrvIns->iInstance, rc));
504 }
505
506 /*
507 * The last bits of cleanup.
508 */
509#ifdef RT_OS_WINDOWS
510 if (pThis->ListenSem != NIL_RTSEMEVENT)
511 {
512 RTSemEventMultiDestroy(pThis->ListenSem);
513 pThis->ListenSem = NIL_RTSEMEVENT;
514 }
515#endif
516}
517
518
519/**
520 * Construct a named pipe stream driver instance.
521 *
522 * @copydoc FNPDMDRVCONSTRUCT
523 */
524static DECLCALLBACK(int) drvNamedPipeConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
525{
526 RT_NOREF(fFlags);
527 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
528 PDRVNAMEDPIPE pThis = PDMINS_2_DATA(pDrvIns, PDRVNAMEDPIPE);
529
530 /*
531 * Init the static parts.
532 */
533 pThis->pDrvIns = pDrvIns;
534 pThis->pszLocation = NULL;
535 pThis->fIsServer = false;
536#ifdef RT_OS_WINDOWS
537 pThis->NamedPipe = INVALID_HANDLE_VALUE;
538 pThis->ListenSem = NIL_RTSEMEVENTMULTI;
539 pThis->OverlappedWrite.hEvent = NULL;
540 pThis->OverlappedRead.hEvent = NULL;
541#else /* !RT_OS_WINDOWS */
542 pThis->LocalSocketServer = -1;
543 pThis->LocalSocket = -1;
544#endif /* !RT_OS_WINDOWS */
545 pThis->ListenThread = NIL_RTTHREAD;
546 pThis->fShutdown = false;
547 /* IBase */
548 pDrvIns->IBase.pfnQueryInterface = drvNamedPipeQueryInterface;
549 /* IStream */
550 pThis->IStream.pfnRead = drvNamedPipeRead;
551 pThis->IStream.pfnWrite = drvNamedPipeWrite;
552
553 /*
554 * Validate and read the configuration.
555 */
556 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "Location|IsServer", "");
557
558 int rc = CFGMR3QueryStringAlloc(pCfg, "Location", &pThis->pszLocation);
559 if (RT_FAILURE(rc))
560 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
561 N_("Configuration error: querying \"Location\" resulted in %Rrc"), rc);
562 rc = CFGMR3QueryBool(pCfg, "IsServer", &pThis->fIsServer);
563 if (RT_FAILURE(rc))
564 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
565 N_("Configuration error: querying \"IsServer\" resulted in %Rrc"), rc);
566
567 /*
568 * Create/Open the pipe.
569 */
570#ifdef RT_OS_WINDOWS
571 if (pThis->fIsServer)
572 {
573 pThis->NamedPipe = CreateNamedPipe(pThis->pszLocation,
574 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
575 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
576 1, /*nMaxInstances*/
577 32, /*nOutBufferSize*/
578 32, /*nOutBufferSize*/
579 10000, /*nDefaultTimeOut*/
580 NULL); /* lpSecurityAttributes*/
581 if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
582 {
583 rc = RTErrConvertFromWin32(GetLastError());
584 LogRel(("NamedPipe%d: CreateNamedPipe failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
585 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create named pipe %s"),
586 pDrvIns->iInstance, pThis->pszLocation);
587 }
588
589 rc = RTSemEventMultiCreate(&pThis->ListenSem);
590 AssertRCReturn(rc, rc);
591
592 rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
593 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
594 if (RT_FAILURE(rc))
595 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to create listening thread"),
596 pDrvIns->iInstance);
597
598 }
599 else
600 {
601 /* Connect to the named pipe. */
602 pThis->NamedPipe = CreateFile(pThis->pszLocation, GENERIC_READ | GENERIC_WRITE, 0, NULL,
603 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
604 if (pThis->NamedPipe == INVALID_HANDLE_VALUE)
605 {
606 rc = RTErrConvertFromWin32(GetLastError());
607 LogRel(("NamedPipe%d: CreateFile failed rc=%Rrc\n", pThis->pDrvIns->iInstance));
608 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NamedPipe#%d failed to connect to named pipe %s"),
609 pDrvIns->iInstance, pThis->pszLocation);
610 }
611 }
612
613 memset(&pThis->OverlappedWrite, 0, sizeof(pThis->OverlappedWrite));
614 pThis->OverlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
615 AssertReturn(pThis->OverlappedWrite.hEvent != NULL, VERR_OUT_OF_RESOURCES);
616
617 memset(&pThis->OverlappedRead, 0, sizeof(pThis->OverlappedRead));
618 pThis->OverlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
619 AssertReturn(pThis->OverlappedRead.hEvent != NULL, VERR_OUT_OF_RESOURCES);
620
621#else /* !RT_OS_WINDOWS */
622 int s = socket(PF_UNIX, SOCK_STREAM, 0);
623 if (s == -1)
624 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
625 N_("NamedPipe#%d failed to create local socket"), pDrvIns->iInstance);
626
627 struct sockaddr_un addr;
628 memset(&addr, 0, sizeof(addr));
629 addr.sun_family = AF_UNIX;
630 strncpy(addr.sun_path, pThis->pszLocation, sizeof(addr.sun_path) - 1);
631
632 if (pThis->fIsServer)
633 {
634 /* Bind address to the local socket. */
635 pThis->LocalSocketServer = s;
636 RTFileDelete(pThis->pszLocation);
637 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
638 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
639 N_("NamedPipe#%d failed to bind to local socket %s"),
640 pDrvIns->iInstance, pThis->pszLocation);
641 rc = RTThreadCreate(&pThis->ListenThread, drvNamedPipeListenLoop, (void *)pThis, 0,
642 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SerPipe");
643 if (RT_FAILURE(rc))
644 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
645 N_("NamedPipe#%d failed to create listening thread"), pDrvIns->iInstance);
646 }
647 else
648 {
649 /* Connect to the local socket. */
650 pThis->LocalSocket = s;
651 if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
652 return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
653 N_("NamedPipe#%d failed to connect to local socket %s"),
654 pDrvIns->iInstance, pThis->pszLocation);
655 }
656#endif /* !RT_OS_WINDOWS */
657
658 LogRel(("NamedPipe: location %s, %s\n", pThis->pszLocation, pThis->fIsServer ? "server" : "client"));
659 return VINF_SUCCESS;
660}
661
662
663/**
664 * Named pipe driver registration record.
665 */
666const PDMDRVREG g_DrvNamedPipe =
667{
668 /* u32Version */
669 PDM_DRVREG_VERSION,
670 /* szName */
671 "NamedPipe",
672 /* szRCMod */
673 "",
674 /* szR0Mod */
675 "",
676 /* pszDescription */
677 "Named Pipe stream driver.",
678 /* fFlags */
679 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
680 /* fClass. */
681 PDM_DRVREG_CLASS_STREAM,
682 /* cMaxInstances */
683 ~0U,
684 /* cbInstance */
685 sizeof(DRVNAMEDPIPE),
686 /* pfnConstruct */
687 drvNamedPipeConstruct,
688 /* pfnDestruct */
689 drvNamedPipeDestruct,
690 /* pfnRelocate */
691 NULL,
692 /* pfnIOCtl */
693 NULL,
694 /* pfnPowerOn */
695 NULL,
696 /* pfnReset */
697 NULL,
698 /* pfnSuspend */
699 NULL,
700 /* pfnResume */
701 NULL,
702 /* pfnAttach */
703 NULL,
704 /* pfnDetach */
705 NULL,
706 /* pfnPowerOff */
707 drvNamedPipePowerOff,
708 /* pfnSoftReset */
709 NULL,
710 /* u32EndVersion */
711 PDM_DRVREG_VERSION
712};
713
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