VirtualBox

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

Last change on this file since 37299 was 35353, checked in by vboxsync, 14 years ago

Move the misc files the in src/VBox/Devices/ directory into a build/ subdirectory, changing their names to match the target module.

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