VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxIPC.cpp@ 96451

Last change on this file since 96451 was 96451, checked in by vboxsync, 2 years ago

Add/NT/Inst,Add/NT/VBoxTray,Add/VBoxService: Cleaned up VBoxGuestInstallHelper.cpp (tested) and the VBoxTray IPC interface (not tested). The motivation for the former was to make it compile in no-CRT mode, the latter was buggy code. The IPC interface is not backwards compatible, this is intentional to avoid buggy code. bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
Line 
1/* $Id: VBoxIPC.cpp 96451 2022-08-24 09:56:54Z vboxsync $ */
2/** @file
3 * VBoxIPC - IPC thread, acts as a (purely) local IPC server.
4 * Multiple sessions are supported, whereas every session
5 * has its own thread for processing requests.
6 */
7
8/*
9 * Copyright (C) 2010-2022 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/critsect.h>
37#include <iprt/errcore.h>
38#include <iprt/ldr.h>
39#include <iprt/list.h>
40#include <iprt/localipc.h>
41#include <iprt/log.h>
42#include <iprt/mem.h>
43#include <iprt/process.h>
44#include <iprt/win/windows.h>
45
46#include "VBoxTray.h"
47#include "VBoxTrayMsg.h"
48#include "VBoxHelpers.h"
49#include "VBoxIPC.h"
50
51
52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
55/**
56 * IPC context data.
57 */
58typedef struct VBOXIPCCONTEXT
59{
60 /** Pointer to the service environment. */
61 const VBOXSERVICEENV *pEnv;
62 /** Handle for the local IPC server. */
63 RTLOCALIPCSERVER hServer;
64 /** Critical section serializing access to the session list, the state,
65 * the response event, the session event, and the thread event. */
66 RTCRITSECT CritSect;
67 /** List of all active IPC sessions. */
68 RTLISTANCHOR SessionList;
69
70} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
71
72/** Function pointer for GetLastInputInfo(). */
73typedef BOOL (WINAPI *PFNGETLASTINPUTINFO)(PLASTINPUTINFO);
74
75/**
76 * IPC per-session thread data.
77 */
78typedef struct VBOXIPCSESSION
79{
80 /** The list node required to be part of the
81 * IPC session list. */
82 RTLISTNODE Node;
83 /** Pointer to the IPC context data. */
84 PVBOXIPCCONTEXT volatile pCtx;
85 /** The local ipc client handle. */
86 RTLOCALIPCSESSION volatile hSession;
87 /** Indicate that the thread should terminate ASAP. */
88 bool volatile fTerminate;
89 /** The thread handle. */
90 RTTHREAD hThread;
91
92} VBOXIPCSESSION, *PVBOXIPCSESSION;
93
94
95/*********************************************************************************************************************************
96* Global Variables *
97*********************************************************************************************************************************/
98static VBOXIPCCONTEXT g_Ctx = { NULL, NIL_RTLOCALIPCSERVER };
99static PFNGETLASTINPUTINFO g_pfnGetLastInputInfo = NULL;
100
101
102/*********************************************************************************************************************************
103* Internal Functions *
104*********************************************************************************************************************************/
105static int vboxIPCSessionStop(PVBOXIPCSESSION pSession);
106
107
108
109/**
110 * Handles VBOXTRAYIPCMSGTYPE_RESTART.
111 */
112static int vboxIPCHandleVBoxTrayRestart(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
113{
114 RT_NOREF(pSession, pHdr);
115
116 /** @todo Not implemented yet; don't return an error here. */
117 return VINF_SUCCESS;
118}
119
120/**
121 * Handles VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG.
122 */
123static int vboxIPCHandleShowBalloonMsg(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
124{
125 /*
126 * Unmarshal and validate the data.
127 */
128 union
129 {
130 uint8_t abBuf[_4K];
131 VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T s;
132 } Payload;
133 AssertReturn(pHdr->cbPayload >= RT_UOFFSETOF_DYN(VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T, szzStrings[2]), VERR_INVALID_PARAMETER);
134 AssertReturn(pHdr->cbPayload < sizeof(Payload), VERR_BUFFER_OVERFLOW);
135
136 int rc = RTLocalIpcSessionRead(pSession->hSession, &Payload, pHdr->cbPayload, NULL /*pcbRead - exact, blocking*/);
137 if (RT_FAILURE(rc))
138 return rc;
139
140 /* String lengths: */
141 AssertReturn( Payload.s.cchMsg + 1 + Payload.s.cchTitle + 1 + RT_UOFFSETOF(VBOXTRAYIPCMSG_SHOW_BALLOON_MSG_T, szzStrings)
142 <= pHdr->cbPayload, VERR_INVALID_PARAMETER);
143
144 /* Message text: */
145 const char *pszMsg = Payload.s.szzStrings;
146 rc = RTStrValidateEncodingEx(pszMsg, Payload.s.cchMsg + 1,
147 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
148 AssertRCReturn(rc, rc);
149
150 /* Title text: */
151 const char *pszTitle = &Payload.s.szzStrings[Payload.s.cchMsg + 1];
152 rc = RTStrValidateEncodingEx(pszMsg, Payload.s.cchTitle + 1,
153 RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
154 AssertRCReturn(rc, rc);
155
156 /* Type/dwInfoFlags: */
157 AssertReturn( Payload.s.uType == NIIF_NONE
158 || Payload.s.uType == NIIF_INFO
159 || Payload.s.uType == NIIF_WARNING
160 || Payload.s.uType == NIIF_ERROR,
161 VERR_WRONG_TYPE);
162
163 /* Timeout: */
164 if (!Payload.s.cMsTimeout)
165 Payload.s.cMsTimeout = RT_MS_5SEC;
166 AssertStmt(Payload.s.cMsTimeout >= RT_MS_1SEC, Payload.s.cMsTimeout = RT_MS_1SEC);
167 AssertStmt(Payload.s.cMsTimeout <= RT_MS_1MIN, Payload.s.cMsTimeout = RT_MS_1MIN);
168
169 /*
170 * Showing the balloon tooltip is not critical.
171 */
172 int rc2 = hlpShowBalloonTip(g_hInstance, g_hwndToolWindow, ID_TRAYICON,
173 pszMsg, pszTitle, Payload.s.cMsTimeout, Payload.s.uType);
174 LogFlowFunc(("Showing \"%s\" - \"%s\" (type %RU32, %RU32ms), rc=%Rrc\n",
175 pszTitle, pszMsg, Payload.s.cMsTimeout, Payload.s.uType, rc2));
176 RT_NOREF_PV(rc2);
177
178 return VINF_SUCCESS;
179}
180
181/**
182 * Handles VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT.
183 */
184static int vboxIPCHandleUserLastInput(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
185{
186 RT_NOREF(pHdr);
187
188 int rc = VINF_SUCCESS;
189 VBOXTRAYIPCREPLY_USER_LAST_INPUT_T Reply = { UINT32_MAX };
190 if (g_pfnGetLastInputInfo)
191 {
192 /* Note: This only works up to 49.7 days (= 2^32, 32-bit counter) since Windows was started. */
193 LASTINPUTINFO LastInput;
194 LastInput.cbSize = sizeof(LastInput);
195 if (g_pfnGetLastInputInfo(&LastInput))
196 Reply.cSecSinceLastInput = (GetTickCount() - LastInput.dwTime) / 1000;
197 else
198 rc = RTErrConvertFromWin32(GetLastError());
199 }
200
201 int rc2 = RTLocalIpcSessionWrite(pSession->hSession, &Reply, sizeof(Reply));
202 if (RT_SUCCESS(rc))
203 rc = rc2;
204
205 return rc;
206}
207
208/**
209 * Initializes the IPC communication.
210 *
211 * @return IPRT status code.
212 * @param pEnv The IPC service's environment.
213 * @param ppInstance The instance pointer which refers to this object.
214 */
215DECLCALLBACK(int) VBoxIPCInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
216{
217 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
218 AssertPtrReturn(ppInstance, VERR_INVALID_POINTER);
219
220 LogFlowFuncEnter();
221
222 PVBOXIPCCONTEXT pCtx = &g_Ctx; /* Only one instance at the moment. */
223 AssertPtr(pCtx);
224
225 int rc = RTCritSectInit(&pCtx->CritSect);
226 if (RT_SUCCESS(rc))
227 {
228 char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
229 memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
230 rc = RTProcQueryUsername(NIL_RTPROCESS,
231 &szPipeName[sizeof(VBOXTRAY_IPC_PIPE_PREFIX) - 1],
232 sizeof(szPipeName) - sizeof(VBOXTRAY_IPC_PIPE_PREFIX) + 1,
233 NULL /*pcbUser*/);
234 AssertRC(rc);
235 if (RT_SUCCESS(rc))
236 {
237 rc = RTLocalIpcServerCreate(&pCtx->hServer, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
238 AssertRC(rc);
239 if (RT_SUCCESS(rc))
240 {
241 pCtx->pEnv = pEnv;
242 RTListInit(&pCtx->SessionList);
243
244 *ppInstance = pCtx;
245
246 /* GetLastInputInfo only is available starting at Windows 2000 -- might fail. */
247 g_pfnGetLastInputInfo = (PFNGETLASTINPUTINFO)
248 RTLdrGetSystemSymbol("User32.dll", "GetLastInputInfo");
249
250 LogRelFunc(("Local IPC server now running at \"%s\"\n", szPipeName));
251 return VINF_SUCCESS;
252 }
253
254 }
255
256 RTCritSectDelete(&pCtx->CritSect);
257 }
258
259 LogRelFunc(("Creating local IPC server failed with rc=%Rrc\n", rc));
260 return rc;
261}
262
263DECLCALLBACK(void) VBoxIPCStop(void *pInstance)
264{
265 /* Can be NULL if VBoxIPCInit failed. */
266 if (!pInstance)
267 return;
268 AssertPtrReturnVoid(pInstance);
269
270 LogFlowFunc(("Stopping pInstance=%p\n", pInstance));
271
272 /* Shut down local IPC server. */
273 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
274 AssertPtr(pCtx);
275
276 if (pCtx->hServer != NIL_RTLOCALIPCSERVER)
277 {
278 int rc2 = RTLocalIpcServerCancel(pCtx->hServer);
279 if (RT_FAILURE(rc2))
280 LogFlowFunc(("Cancelling current listening call failed with rc=%Rrc\n", rc2));
281 }
282
283 /* Stop all remaining session threads. */
284 int rc = RTCritSectEnter(&pCtx->CritSect);
285 if (RT_SUCCESS(rc))
286 {
287 PVBOXIPCSESSION pSession;
288 RTListForEach(&pCtx->SessionList, pSession, VBOXIPCSESSION, Node)
289 {
290 int rc2 = vboxIPCSessionStop(pSession);
291 if (RT_FAILURE(rc2))
292 {
293 LogFlowFunc(("Stopping IPC session %p failed with rc=%Rrc\n",
294 pSession, rc2));
295 /* Keep going. */
296 }
297 }
298 }
299}
300
301DECLCALLBACK(void) VBoxIPCDestroy(void *pInstance)
302{
303 AssertPtrReturnVoid(pInstance);
304
305 LogFlowFunc(("Destroying pInstance=%p\n", pInstance));
306
307 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
308 AssertPtr(pCtx);
309
310 /* Shut down local IPC server. */
311 int rc = RTCritSectEnter(&pCtx->CritSect);
312 if (RT_SUCCESS(rc))
313 {
314 rc = RTLocalIpcServerDestroy(pCtx->hServer);
315 if (RT_FAILURE(rc))
316 LogFlowFunc(("Unable to destroy IPC server, rc=%Rrc\n", rc));
317
318 int rc2 = RTCritSectLeave(&pCtx->CritSect);
319 if (RT_SUCCESS(rc))
320 rc = rc2;
321 }
322
323 LogFlowFunc(("Waiting for remaining IPC sessions to shut down ...\n"));
324
325 /* Wait for all IPC session threads to shut down. */
326 bool fListIsEmpty = true;
327 do
328 {
329 int rc2 = RTCritSectEnter(&pCtx->CritSect);
330 if (RT_SUCCESS(rc2))
331 {
332 fListIsEmpty = RTListIsEmpty(&pCtx->SessionList);
333 rc2 = RTCritSectLeave(&pCtx->CritSect);
334
335 if (!fListIsEmpty) /* Don't hog CPU while waiting. */
336 RTThreadSleep(100);
337 }
338
339 if (RT_FAILURE(rc2))
340 break;
341
342 } while (!fListIsEmpty);
343
344 AssertMsg(fListIsEmpty,
345 ("Session thread list is not empty when it should\n"));
346
347 LogFlowFunc(("All remaining IPC sessions shut down\n"));
348
349 int rc2 = RTCritSectDelete(&pCtx->CritSect);
350 if (RT_SUCCESS(rc))
351 rc = rc2;
352
353 LogFlowFunc(("Destroyed pInstance=%p, rc=%Rrc\n",
354 pInstance, rc));
355}
356
357/**
358 * Services a client session.
359 *
360 * @returns VINF_SUCCESS.
361 * @param hThreadSelf The thread handle.
362 * @param pvSession Pointer to the session instance data.
363 */
364static DECLCALLBACK(int) vboxIPCSessionThread(RTTHREAD hThreadSelf, void *pvSession)
365{
366 RT_NOREF(hThreadSelf);
367 PVBOXIPCSESSION pThis = (PVBOXIPCSESSION)pvSession;
368 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
369 RTLOCALIPCSESSION hSession = pThis->hSession;
370 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
371
372 LogFlowFunc(("pThis=%p\n", pThis));
373
374 int rc = VINF_SUCCESS;
375
376 /*
377 * Process client requests until it quits or we're cancelled on termination.
378 */
379 while ( !ASMAtomicUoReadBool(&pThis->fTerminate)
380 && RT_SUCCESS(rc))
381 {
382 /* The next call will be cancelled via VBoxIPCStop if needed. */
383 rc = RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT);
384 if (RT_SUCCESS(rc))
385 {
386 /*
387 * Read the message header.
388 */
389 VBOXTRAYIPCHEADER Hdr = {0};
390 rc = RTLocalIpcSessionRead(hSession, &Hdr, sizeof(Hdr), NULL /*pcbRead - exact, blocking*/);
391 if (RT_FAILURE(rc))
392 break;
393
394 /*
395 * Validate the message header.
396 *
397 * Disconnecting the client if invalid or something we don't grok.
398 * Currently all clients are one-shots, so there is no need to get
399 * in complicated recovery code if we don't understand one another.
400 */
401 if ( Hdr.uMagic != VBOXTRAY_IPC_HDR_MAGIC
402 || Hdr.uVersion != VBOXTRAY_IPC_HDR_VERSION)
403 {
404 LogRelFunc(("Session %p: Invalid header magic/version: %#x, %#x, %#x, %#x\n",
405 Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload));
406 rc = VERR_INVALID_MAGIC;
407 break;
408 }
409 if (Hdr.cbPayload > VBOXTRAY_IPC_MAX_PAYLOAD)
410 {
411 LogRelFunc(("Session %p: Payload to big: %#x, %#x, %#x, %#x - max %#x\n",
412 Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload, VBOXTRAY_IPC_MAX_PAYLOAD));
413 rc = VERR_TOO_MUCH_DATA;
414 break;
415 }
416 if ( Hdr.enmMsgType > VBOXTRAYIPCMSGTYPE_INVALID
417 && Hdr.enmMsgType < VBOXTRAYIPCMSGTYPE_END)
418 {
419 LogRelFunc(("Session %p: Unknown message: %#x, %#x, %#x, %#x\n",
420 Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload));
421 rc = VERR_INVALID_FUNCTION;
422 break;
423 }
424
425 /*
426 * Handle the message.
427 */
428 switch (Hdr.enmMsgType)
429 {
430 case VBOXTRAYIPCMSGTYPE_RESTART:
431 rc = vboxIPCHandleVBoxTrayRestart(pThis, &Hdr);
432 break;
433
434 case VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG:
435 rc = vboxIPCHandleShowBalloonMsg(pThis, &Hdr);
436 break;
437
438 case VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT:
439 rc = vboxIPCHandleUserLastInput(pThis, &Hdr);
440 break;
441
442 default:
443 AssertFailedBreakStmt(rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE);
444 }
445 if (RT_FAILURE(rc))
446 LogFlowFunc(("Session %p: Handling command %RU32 failed with rc=%Rrc\n", pThis, Hdr.enmMsgType, rc));
447 }
448 else if (rc == VERR_CANCELLED)
449 {
450 LogFlowFunc(("Session %p: Waiting for data cancelled\n", pThis));
451 rc = VINF_SUCCESS;
452 break;
453 }
454 else
455 LogFlowFunc(("Session %p: Waiting for session data failed with rc=%Rrc\n", pThis, rc));
456 }
457
458 LogFlowFunc(("Session %p: Handler ended with rc=%Rrc\n", pThis, rc));
459
460 /*
461 * Close the session.
462 */
463 int rc2 = RTLocalIpcSessionClose(hSession);
464 if (RT_FAILURE(rc2))
465 LogFlowFunc(("Session %p: Failed closing session %p, rc=%Rrc\n", pThis, rc2));
466
467 /*
468 * Clean up the session.
469 */
470 PVBOXIPCCONTEXT pCtx = ASMAtomicReadPtrT(&pThis->pCtx, PVBOXIPCCONTEXT);
471 AssertMsg(pCtx, ("Session %p: No context found\n", pThis));
472 rc2 = RTCritSectEnter(&pCtx->CritSect);
473 if (RT_SUCCESS(rc2))
474 {
475 /* Remove this session from the session list. */
476 RTListNodeRemove(&pThis->Node);
477
478 rc2 = RTCritSectLeave(&pCtx->CritSect);
479 if (RT_SUCCESS(rc))
480 rc = rc2;
481 }
482
483 LogFlowFunc(("Session %p: Terminated with rc=%Rrc, freeing ...\n", pThis, rc));
484
485 RTMemFree(pThis);
486 pThis = NULL;
487
488 return rc;
489}
490
491static int vboxIPCSessionCreate(PVBOXIPCCONTEXT pCtx, RTLOCALIPCSESSION hSession)
492{
493 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
494 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
495
496 int rc = RTCritSectEnter(&pCtx->CritSect);
497 if (RT_SUCCESS(rc))
498 {
499 PVBOXIPCSESSION pSession = (PVBOXIPCSESSION)RTMemAllocZ(sizeof(VBOXIPCSESSION));
500 if (pSession)
501 {
502 pSession->pCtx = pCtx;
503 pSession->hSession = hSession;
504 pSession->fTerminate = false;
505 pSession->hThread = NIL_RTTHREAD;
506
507 /* Start IPC session thread. */
508 LogFlowFunc(("Creating thread for session %p ...\n", pSession));
509 rc = RTThreadCreate(&pSession->hThread, vboxIPCSessionThread,
510 pSession /* pvUser */, 0 /* Default stack size */,
511 RTTHREADTYPE_DEFAULT, 0 /* Flags */, "IPCSESSION");
512 if (RT_SUCCESS(rc))
513 {
514 /* Add session thread to session IPC list. */
515 RTListAppend(&pCtx->SessionList, &pSession->Node);
516 }
517 else
518 {
519 int rc2 = RTLocalIpcSessionClose(hSession);
520 if (RT_FAILURE(rc2))
521 LogFlowFunc(("Failed closing session %p, rc=%Rrc\n", pSession, rc2));
522
523 LogFlowFunc(("Failed to create thread for session %p, rc=%Rrc\n", pSession, rc));
524 RTMemFree(pSession);
525 }
526 }
527 else
528 rc = VERR_NO_MEMORY;
529
530 int rc2 = RTCritSectLeave(&pCtx->CritSect);
531 AssertRC(rc2);
532 }
533
534 return rc;
535}
536
537static int vboxIPCSessionStop(PVBOXIPCSESSION pSession)
538{
539 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
540
541 ASMAtomicWriteBool(&pSession->fTerminate, true);
542
543 RTLOCALIPCSESSION hSession;
544 ASMAtomicXchgHandle(&pSession->hSession, NIL_RTLOCALIPCSESSION, &hSession);
545 if (hSession)
546 return RTLocalIpcSessionClose(hSession);
547
548 return VINF_SUCCESS;
549}
550
551/**
552 * Thread function to wait for and process seamless mode change
553 * requests
554 */
555DECLCALLBACK(int) VBoxIPCWorker(void *pInstance, bool volatile *pfShutdown)
556{
557 AssertPtr(pInstance);
558 LogFlowFunc(("pInstance=%p\n", pInstance));
559
560 LogFlowFuncEnter();
561
562 /*
563 * Tell the control thread that it can continue
564 * spawning services.
565 */
566 RTThreadUserSignal(RTThreadSelf());
567
568 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
569 AssertPtr(pCtx);
570
571 int rc;
572
573 bool fShutdown = false;
574 for (;;)
575 {
576 RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
577 rc = RTLocalIpcServerListen(pCtx->hServer, &hClientSession);
578 if (RT_FAILURE(rc))
579 {
580 if (rc == VERR_CANCELLED)
581 {
582 LogFlow(("Cancelled\n"));
583 fShutdown = true;
584 }
585 else
586 LogRelFunc(("Listening failed with rc=%Rrc\n", rc));
587 }
588
589 if (fShutdown)
590 break;
591 rc = vboxIPCSessionCreate(pCtx, hClientSession);
592 if (RT_FAILURE(rc))
593 {
594 LogRelFunc(("Creating new IPC server session failed with rc=%Rrc\n", rc));
595 /* Keep going. */
596 }
597
598 if (*pfShutdown)
599 break;
600 }
601
602 LogFlowFuncLeaveRC(rc);
603 return rc;
604}
605
606/**
607 * The service description.
608 */
609VBOXSERVICEDESC g_SvcDescIPC =
610{
611 /* pszName. */
612 "IPC",
613 /* pszDescription. */
614 "Inter-Process Communication",
615 /* methods */
616 VBoxIPCInit,
617 VBoxIPCWorker,
618 NULL /* pfnStop */,
619 VBoxIPCDestroy
620};
621
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