VirtualBox

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

Last change on this file since 28185 was 27934, checked in by vboxsync, 15 years ago

build fix

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