VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.4 KB
RevLine 
[34085]1/* $Id: VBoxIPC.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[47195]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.
[34085]6 */
7
8/*
[98103]9 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
[34085]10 *
[96407]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
[34085]28 */
[63100]29
[63549]30
[63100]31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
[47195]34#include <iprt/asm.h>
[34085]35#include <iprt/assert.h>
[47195]36#include <iprt/critsect.h>
[76474]37#include <iprt/errcore.h>
[47960]38#include <iprt/ldr.h>
[47195]39#include <iprt/list.h>
40#include <iprt/localipc.h>
[95961]41#include <iprt/log.h>
[34097]42#include <iprt/mem.h>
[58306]43#include <iprt/process.h>
[95961]44#include <iprt/win/windows.h>
[58306]45
[95961]46#include "VBoxTray.h"
47#include "VBoxTrayMsg.h"
48#include "VBoxHelpers.h"
49#include "VBoxIPC.h"
[34357]50
[95961]51
[63100]52/*********************************************************************************************************************************
53* Structures and Typedefs *
54*********************************************************************************************************************************/
[47195]55/**
56 * IPC context data.
57 */
58typedef struct VBOXIPCCONTEXT
[34085]59{
[47195]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;
[34085]69
70} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
71
[47977]72/** Function pointer for GetLastInputInfo(). */
73typedef BOOL (WINAPI *PFNGETLASTINPUTINFO)(PLASTINPUTINFO);
74
[47195]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;
[34357]91
[47195]92} VBOXIPCSESSION, *PVBOXIPCSESSION;
93
[47977]94
[63100]95/*********************************************************************************************************************************
96* Global Variables *
97*********************************************************************************************************************************/
98static VBOXIPCCONTEXT g_Ctx = { NULL, NIL_RTLOCALIPCSERVER };
99static PFNGETLASTINPUTINFO g_pfnGetLastInputInfo = NULL;
[47195]100
[63100]101
102/*********************************************************************************************************************************
103* Internal Functions *
104*********************************************************************************************************************************/
105static int vboxIPCSessionStop(PVBOXIPCSESSION pSession);
106
107
108
[96451]109/**
110 * Handles VBOXTRAYIPCMSGTYPE_RESTART.
111 */
[47960]112static int vboxIPCHandleVBoxTrayRestart(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
[47211]113{
[96451]114 RT_NOREF(pSession, pHdr);
[47211]115
116 /** @todo Not implemented yet; don't return an error here. */
117 return VINF_SUCCESS;
118}
119
[96451]120/**
121 * Handles VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG.
122 */
[47960]123static int vboxIPCHandleShowBalloonMsg(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
[47211]124{
[96451]125 /*
126 * Unmarshal and validate the data.
127 */
128 union
[47211]129 {
[96451]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);
[47211]135
[96451]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;
[47211]179}
180
[96451]181/**
182 * Handles VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT.
183 */
[47960]184static int vboxIPCHandleUserLastInput(PVBOXIPCSESSION pSession, PVBOXTRAYIPCHEADER pHdr)
[47211]185{
[96451]186 RT_NOREF(pHdr);
[47211]187
188 int rc = VINF_SUCCESS;
[96451]189 VBOXTRAYIPCREPLY_USER_LAST_INPUT_T Reply = { UINT32_MAX };
[63100]190 if (g_pfnGetLastInputInfo)
[47211]191 {
[96451]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;
[47960]197 else
198 rc = RTErrConvertFromWin32(GetLastError());
[47211]199 }
200
[96451]201 int rc2 = RTLocalIpcSessionWrite(pSession->hSession, &Reply, sizeof(Reply));
[47960]202 if (RT_SUCCESS(rc))
203 rc = rc2;
204
[47211]205 return rc;
206}
207
[34357]208/**
[47195]209 * Initializes the IPC communication.
[34357]210 *
211 * @return IPRT status code.
[47195]212 * @param pEnv The IPC service's environment.
[57741]213 * @param ppInstance The instance pointer which refers to this object.
[34357]214 */
[57741]215DECLCALLBACK(int) VBoxIPCInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
[34085]216{
[47195]217 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
[57741]218 AssertPtrReturn(ppInstance, VERR_INVALID_POINTER);
[47195]219
220 LogFlowFuncEnter();
221
[57741]222 PVBOXIPCCONTEXT pCtx = &g_Ctx; /* Only one instance at the moment. */
223 AssertPtr(pCtx);
[47195]224
[57741]225 int rc = RTCritSectInit(&pCtx->CritSect);
[47195]226 if (RT_SUCCESS(rc))
[34085]227 {
[64291]228 char szPipeName[512 + sizeof(VBOXTRAY_IPC_PIPE_PREFIX)];
[64292]229 memcpy(szPipeName, VBOXTRAY_IPC_PIPE_PREFIX, sizeof(VBOXTRAY_IPC_PIPE_PREFIX));
[58306]230 rc = RTProcQueryUsername(NIL_RTPROCESS,
[64291]231 &szPipeName[sizeof(VBOXTRAY_IPC_PIPE_PREFIX) - 1],
232 sizeof(szPipeName) - sizeof(VBOXTRAY_IPC_PIPE_PREFIX) + 1,
[58306]233 NULL /*pcbUser*/);
[64326]234 AssertRC(rc);
[47232]235 if (RT_SUCCESS(rc))
[34097]236 {
[64292]237 rc = RTLocalIpcServerCreate(&pCtx->hServer, szPipeName, RTLOCALIPC_FLAGS_NATIVE_NAME);
[64326]238 AssertRC(rc);
[47232]239 if (RT_SUCCESS(rc))
240 {
[64291]241 pCtx->pEnv = pEnv;
242 RTListInit(&pCtx->SessionList);
[47232]243
[64291]244 *ppInstance = pCtx;
[47232]245
[64291]246 /* GetLastInputInfo only is available starting at Windows 2000 -- might fail. */
[96600]247 g_pfnGetLastInputInfo = (PFNGETLASTINPUTINFO)RTLdrGetSystemSymbol("User32.dll", "GetLastInputInfo");
[47232]248
[64291]249 LogRelFunc(("Local IPC server now running at \"%s\"\n", szPipeName));
250 return VINF_SUCCESS;
251 }
[64285]252
[34097]253 }
[47195]254
[57741]255 RTCritSectDelete(&pCtx->CritSect);
[34085]256 }
[47195]257
[47232]258 LogRelFunc(("Creating local IPC server failed with rc=%Rrc\n", rc));
[34085]259 return rc;
260}
261
[57741]262DECLCALLBACK(void) VBoxIPCStop(void *pInstance)
[34357]263{
[64326]264 /* Can be NULL if VBoxIPCInit failed. */
265 if (!pInstance)
266 return;
[47211]267 AssertPtrReturnVoid(pInstance);
[34357]268
[51469]269 LogFlowFunc(("Stopping pInstance=%p\n", pInstance));
[47195]270
[50039]271 /* Shut down local IPC server. */
[47195]272 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
273 AssertPtr(pCtx);
274
275 if (pCtx->hServer != NIL_RTLOCALIPCSERVER)
[34085]276 {
[47195]277 int rc2 = RTLocalIpcServerCancel(pCtx->hServer);
278 if (RT_FAILURE(rc2))
[51469]279 LogFlowFunc(("Cancelling current listening call failed with rc=%Rrc\n", rc2));
[34085]280 }
[50039]281
282 /* Stop all remaining session threads. */
283 int rc = RTCritSectEnter(&pCtx->CritSect);
284 if (RT_SUCCESS(rc))
285 {
286 PVBOXIPCSESSION pSession;
287 RTListForEach(&pCtx->SessionList, pSession, VBOXIPCSESSION, Node)
288 {
289 int rc2 = vboxIPCSessionStop(pSession);
290 if (RT_FAILURE(rc2))
291 {
[51469]292 LogFlowFunc(("Stopping IPC session %p failed with rc=%Rrc\n",
[50039]293 pSession, rc2));
294 /* Keep going. */
295 }
296 }
297 }
[34085]298}
299
[57741]300DECLCALLBACK(void) VBoxIPCDestroy(void *pInstance)
[34085]301{
[50039]302 AssertPtrReturnVoid(pInstance);
[34085]303
[51469]304 LogFlowFunc(("Destroying pInstance=%p\n", pInstance));
[47195]305
306 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
307 AssertPtr(pCtx);
308
[50039]309 /* Shut down local IPC server. */
[47195]310 int rc = RTCritSectEnter(&pCtx->CritSect);
[34085]311 if (RT_SUCCESS(rc))
312 {
[50039]313 rc = RTLocalIpcServerDestroy(pCtx->hServer);
314 if (RT_FAILURE(rc))
[51469]315 LogFlowFunc(("Unable to destroy IPC server, rc=%Rrc\n", rc));
[50039]316
317 int rc2 = RTCritSectLeave(&pCtx->CritSect);
318 if (RT_SUCCESS(rc))
319 rc = rc2;
320 }
321
[51469]322 LogFlowFunc(("Waiting for remaining IPC sessions to shut down ...\n"));
[50039]323
324 /* Wait for all IPC session threads to shut down. */
325 bool fListIsEmpty = true;
326 do
327 {
328 int rc2 = RTCritSectEnter(&pCtx->CritSect);
329 if (RT_SUCCESS(rc2))
[47195]330 {
[50039]331 fListIsEmpty = RTListIsEmpty(&pCtx->SessionList);
332 rc2 = RTCritSectLeave(&pCtx->CritSect);
[50040]333
334 if (!fListIsEmpty) /* Don't hog CPU while waiting. */
335 RTThreadSleep(100);
[47195]336 }
337
[50039]338 if (RT_FAILURE(rc2))
339 break;
[47195]340
[50039]341 } while (!fListIsEmpty);
[47195]342
[50039]343 AssertMsg(fListIsEmpty,
344 ("Session thread list is not empty when it should\n"));
[34085]345
[51469]346 LogFlowFunc(("All remaining IPC sessions shut down\n"));
[50039]347
348 int rc2 = RTCritSectDelete(&pCtx->CritSect);
349 if (RT_SUCCESS(rc))
350 rc = rc2;
351
[51469]352 LogFlowFunc(("Destroyed pInstance=%p, rc=%Rrc\n",
[47195]353 pInstance, rc));
[34357]354}
355
356/**
[47195]357 * Services a client session.
[34357]358 *
[47195]359 * @returns VINF_SUCCESS.
[63100]360 * @param hThreadSelf The thread handle.
[47195]361 * @param pvSession Pointer to the session instance data.
[34357]362 */
[63100]363static DECLCALLBACK(int) vboxIPCSessionThread(RTTHREAD hThreadSelf, void *pvSession)
[34085]364{
[63100]365 RT_NOREF(hThreadSelf);
[47195]366 PVBOXIPCSESSION pThis = (PVBOXIPCSESSION)pvSession;
367 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
368 RTLOCALIPCSESSION hSession = pThis->hSession;
369 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
[34085]370
[51469]371 LogFlowFunc(("pThis=%p\n", pThis));
[34085]372
[47211]373 int rc = VINF_SUCCESS;
374
[47195]375 /*
376 * Process client requests until it quits or we're cancelled on termination.
377 */
[47211]378 while ( !ASMAtomicUoReadBool(&pThis->fTerminate)
379 && RT_SUCCESS(rc))
[34085]380 {
[47211]381 /* The next call will be cancelled via VBoxIPCStop if needed. */
382 rc = RTLocalIpcSessionWaitForData(hSession, RT_INDEFINITE_WAIT);
[96451]383 if (RT_SUCCESS(rc))
[34097]384 {
[96451]385 /*
386 * Read the message header.
387 */
388 VBOXTRAYIPCHEADER Hdr = {0};
389 rc = RTLocalIpcSessionRead(hSession, &Hdr, sizeof(Hdr), NULL /*pcbRead - exact, blocking*/);
390 if (RT_FAILURE(rc))
391 break;
392
393 /*
394 * Validate the message header.
395 *
396 * Disconnecting the client if invalid or something we don't grok.
397 * Currently all clients are one-shots, so there is no need to get
398 * in complicated recovery code if we don't understand one another.
399 */
400 if ( Hdr.uMagic != VBOXTRAY_IPC_HDR_MAGIC
401 || Hdr.uVersion != VBOXTRAY_IPC_HDR_VERSION)
[34097]402 {
[96451]403 LogRelFunc(("Session %p: Invalid header magic/version: %#x, %#x, %#x, %#x\n",
[96663]404 pThis, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload));
[96451]405 rc = VERR_INVALID_MAGIC;
[47195]406 break;
[34097]407 }
[96451]408 if (Hdr.cbPayload > VBOXTRAY_IPC_MAX_PAYLOAD)
409 {
410 LogRelFunc(("Session %p: Payload to big: %#x, %#x, %#x, %#x - max %#x\n",
[96663]411 pThis, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload, VBOXTRAY_IPC_MAX_PAYLOAD));
[96451]412 rc = VERR_TOO_MUCH_DATA;
413 break;
414 }
[96663]415 if ( Hdr.enmMsgType <= VBOXTRAYIPCMSGTYPE_INVALID
416 || Hdr.enmMsgType >= VBOXTRAYIPCMSGTYPE_END)
[96451]417 {
418 LogRelFunc(("Session %p: Unknown message: %#x, %#x, %#x, %#x\n",
[96663]419 pThis, Hdr.uMagic, Hdr.uVersion, Hdr.enmMsgType, Hdr.cbPayload));
[96451]420 rc = VERR_INVALID_FUNCTION;
421 break;
422 }
[47234]423
[96451]424 /*
425 * Handle the message.
426 */
427 switch (Hdr.enmMsgType)
[47195]428 {
[96451]429 case VBOXTRAYIPCMSGTYPE_RESTART:
430 rc = vboxIPCHandleVBoxTrayRestart(pThis, &Hdr);
431 break;
[47211]432
[96451]433 case VBOXTRAYIPCMSGTYPE_SHOW_BALLOON_MSG:
434 rc = vboxIPCHandleShowBalloonMsg(pThis, &Hdr);
435 break;
[47211]436
[96451]437 case VBOXTRAYIPCMSGTYPE_USER_LAST_INPUT:
438 rc = vboxIPCHandleUserLastInput(pThis, &Hdr);
439 break;
[47211]440
[96451]441 default:
442 AssertFailedBreakStmt(rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE);
[47234]443 }
[96451]444 if (RT_FAILURE(rc))
445 LogFlowFunc(("Session %p: Handling command %RU32 failed with rc=%Rrc\n", pThis, Hdr.enmMsgType, rc));
[34097]446 }
[96451]447 else if (rc == VERR_CANCELLED)
448 {
449 LogFlowFunc(("Session %p: Waiting for data cancelled\n", pThis));
450 rc = VINF_SUCCESS;
451 break;
452 }
453 else
454 LogFlowFunc(("Session %p: Waiting for session data failed with rc=%Rrc\n", pThis, rc));
[47195]455 }
456
[96451]457 LogFlowFunc(("Session %p: Handler ended with rc=%Rrc\n", pThis, rc));
[47211]458
[47195]459 /*
[50039]460 * Close the session.
461 */
462 int rc2 = RTLocalIpcSessionClose(hSession);
463 if (RT_FAILURE(rc2))
[51469]464 LogFlowFunc(("Session %p: Failed closing session %p, rc=%Rrc\n", pThis, rc2));
[50039]465
466 /*
[47195]467 * Clean up the session.
468 */
469 PVBOXIPCCONTEXT pCtx = ASMAtomicReadPtrT(&pThis->pCtx, PVBOXIPCCONTEXT);
[47211]470 AssertMsg(pCtx, ("Session %p: No context found\n", pThis));
[50039]471 rc2 = RTCritSectEnter(&pCtx->CritSect);
472 if (RT_SUCCESS(rc2))
[47211]473 {
[50039]474 /* Remove this session from the session list. */
475 RTListNodeRemove(&pThis->Node);
[47195]476
[50039]477 rc2 = RTCritSectLeave(&pCtx->CritSect);
[47211]478 if (RT_SUCCESS(rc))
479 rc = rc2;
[47195]480 }
481
[96451]482 LogFlowFunc(("Session %p: Terminated with rc=%Rrc, freeing ...\n", pThis, rc));
[50039]483
484 RTMemFree(pThis);
485 pThis = NULL;
486
[47211]487 return rc;
[47195]488}
489
490static int vboxIPCSessionCreate(PVBOXIPCCONTEXT pCtx, RTLOCALIPCSESSION hSession)
491{
492 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
493 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
494
495 int rc = RTCritSectEnter(&pCtx->CritSect);
496 if (RT_SUCCESS(rc))
497 {
498 PVBOXIPCSESSION pSession = (PVBOXIPCSESSION)RTMemAllocZ(sizeof(VBOXIPCSESSION));
499 if (pSession)
[34097]500 {
[57741]501 pSession->pCtx = pCtx;
502 pSession->hSession = hSession;
[47195]503 pSession->fTerminate = false;
[57741]504 pSession->hThread = NIL_RTTHREAD;
[47195]505
506 /* Start IPC session thread. */
507 LogFlowFunc(("Creating thread for session %p ...\n", pSession));
[50039]508 rc = RTThreadCreate(&pSession->hThread, vboxIPCSessionThread,
509 pSession /* pvUser */, 0 /* Default stack size */,
[57741]510 RTTHREADTYPE_DEFAULT, 0 /* Flags */, "IPCSESSION");
[47195]511 if (RT_SUCCESS(rc))
512 {
513 /* Add session thread to session IPC list. */
514 RTListAppend(&pCtx->SessionList, &pSession->Node);
515 }
[34097]516 else
517 {
[47195]518 int rc2 = RTLocalIpcSessionClose(hSession);
519 if (RT_FAILURE(rc2))
[51469]520 LogFlowFunc(("Failed closing session %p, rc=%Rrc\n", pSession, rc2));
[47195]521
[51469]522 LogFlowFunc(("Failed to create thread for session %p, rc=%Rrc\n", pSession, rc));
[47195]523 RTMemFree(pSession);
[34097]524 }
525 }
[47195]526 else
527 rc = VERR_NO_MEMORY;
528
529 int rc2 = RTCritSectLeave(&pCtx->CritSect);
530 AssertRC(rc2);
[34085]531 }
[47195]532
[34085]533 return rc;
534}
535
[50039]536static int vboxIPCSessionStop(PVBOXIPCSESSION pSession)
[34085]537{
[47195]538 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
[47960]539
[50039]540 ASMAtomicWriteBool(&pSession->fTerminate, true);
[34085]541
[47195]542 RTLOCALIPCSESSION hSession;
543 ASMAtomicXchgHandle(&pSession->hSession, NIL_RTLOCALIPCSESSION, &hSession);
[50039]544 if (hSession)
545 return RTLocalIpcSessionClose(hSession);
[47195]546
[50039]547 return VINF_SUCCESS;
[34085]548}
549
550/**
551 * Thread function to wait for and process seamless mode change
552 * requests
553 */
[57741]554DECLCALLBACK(int) VBoxIPCWorker(void *pInstance, bool volatile *pfShutdown)
[34085]555{
[57741]556 AssertPtr(pInstance);
557 LogFlowFunc(("pInstance=%p\n", pInstance));
558
[47195]559 LogFlowFuncEnter();
[34085]560
[57741]561 /*
562 * Tell the control thread that it can continue
563 * spawning services.
564 */
565 RTThreadUserSignal(RTThreadSelf());
566
[34085]567 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
568 AssertPtr(pCtx);
569
[57741]570 int rc;
571
[47195]572 bool fShutdown = false;
573 for (;;)
[34085]574 {
[47195]575 RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
[57741]576 rc = RTLocalIpcServerListen(pCtx->hServer, &hClientSession);
[47195]577 if (RT_FAILURE(rc))
[34085]578 {
[47195]579 if (rc == VERR_CANCELLED)
[34085]580 {
[47195]581 LogFlow(("Cancelled\n"));
582 fShutdown = true;
[34085]583 }
[47195]584 else
585 LogRelFunc(("Listening failed with rc=%Rrc\n", rc));
586 }
[34085]587
[47195]588 if (fShutdown)
589 break;
590 rc = vboxIPCSessionCreate(pCtx, hClientSession);
591 if (RT_FAILURE(rc))
592 {
593 LogRelFunc(("Creating new IPC server session failed with rc=%Rrc\n", rc));
594 /* Keep going. */
[34085]595 }
596
[57741]597 if (*pfShutdown)
[47195]598 break;
599 }
[34085]600
[57741]601 LogFlowFuncLeaveRC(rc);
602 return rc;
[34085]603}
604
[57741]605/**
606 * The service description.
607 */
608VBOXSERVICEDESC g_SvcDescIPC =
609{
610 /* pszName. */
611 "IPC",
612 /* pszDescription. */
613 "Inter-Process Communication",
614 /* methods */
615 VBoxIPCInit,
616 VBoxIPCWorker,
617 NULL /* pfnStop */,
618 VBoxIPCDestroy
619};
620
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use