VirtualBox

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

Last change on this file since 47195 was 47195, checked in by vboxsync, 11 years ago

VBoxTray/IPC: Now using RTLocalIpc (work in progress).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.9 KB
Line 
1/* $Id: VBoxIPC.cpp 47195 2013-07-16 14:48:43Z 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-2013 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19#include <windows.h>
20#include "VBoxTray.h"
21#include "VBoxTrayMsg.h"
22#include "VBoxHelpers.h"
23#include "VBoxIPC.h"
24
25#include <iprt/asm.h>
26#include <iprt/assert.h>
27#include <iprt/critsect.h>
28#include <iprt/err.h>
29#include <iprt/list.h>
30#include <iprt/localipc.h>
31#include <iprt/mem.h>
32#include <VBoxGuestInternal.h>
33
34
35
36
37
38/**
39 * IPC context data.
40 */
41typedef struct VBOXIPCCONTEXT
42{
43 /** Pointer to the service environment. */
44 const VBOXSERVICEENV *pEnv;
45 /** Handle for the local IPC server. */
46 RTLOCALIPCSERVER hServer;
47 /** Critical section serializing access to the session list, the state,
48 * the response event, the session event, and the thread event. */
49 RTCRITSECT CritSect;
50 /** List of all active IPC sessions. */
51 RTLISTANCHOR SessionList;
52
53} VBOXIPCCONTEXT, *PVBOXIPCCONTEXT;
54static VBOXIPCCONTEXT gCtx = {0};
55
56/**
57 * IPC per-session thread data.
58 */
59typedef struct VBOXIPCSESSION
60{
61 /** The list node required to be part of the
62 * IPC session list. */
63 RTLISTNODE Node;
64 /** Pointer to the IPC context data. */
65 PVBOXIPCCONTEXT volatile pCtx;
66 /** The local ipc client handle. */
67 RTLOCALIPCSESSION volatile hSession;
68 /** Indicate that the thread should terminate ASAP. */
69 bool volatile fTerminate;
70 /** The thread handle. */
71 RTTHREAD hThread;
72
73} VBOXIPCSESSION, *PVBOXIPCSESSION;
74
75int vboxIPCSessionDestroyLocked(PVBOXIPCCONTEXT pCtx, PVBOXIPCSESSION pSession);
76
77/**
78 * Initializes the IPC communication.
79 *
80 * @return IPRT status code.
81 * @param pEnv The IPC service's environment.
82 * @param ppInstance The instance pointer which refer to this object.
83 * @param pfStartThread Pointer to flag whether the IPC service can be started or not.
84 */
85int VBoxIPCInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
86{
87 AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
88 /** ppInstance not used here. */
89 AssertPtrReturn(pfStartThread, VERR_INVALID_POINTER);
90
91 LogFlowFuncEnter();
92
93 *pfStartThread = false;
94
95 gCtx.pEnv = pEnv;
96 gCtx.hServer = NIL_RTLOCALIPCSERVER;
97
98 int rc = RTCritSectInit(&gCtx.CritSect);
99 if (RT_SUCCESS(rc))
100 {
101 rc = RTLocalIpcServerCreate(&gCtx.hServer, "VBoxTrayIPCSvc", RTLOCALIPC_FLAGS_MULTI_SESSION);
102 if (RT_FAILURE(rc))
103 {
104 LogRelFunc(("Creating local IPC server failed with rc=%Rrc\n", rc));
105 return rc;
106 }
107
108 RTListInit(&gCtx.SessionList);
109
110 *pfStartThread = true;
111 }
112
113 return rc;
114}
115
116void VBoxIPCStop(const VBOXSERVICEENV *pEnv, void *pInstance)
117{
118 AssertPtr(pEnv);
119 AssertPtr(pInstance);
120
121 LogFunc(("Stopping pInstance=%p\n", pInstance));
122
123 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
124 AssertPtr(pCtx);
125
126 if (pCtx->hServer != NIL_RTLOCALIPCSERVER)
127 {
128 int rc2 = RTLocalIpcServerCancel(pCtx->hServer);
129 if (RT_FAILURE(rc2))
130 LogFunc(("Cancelling current listening call failed with rc=%Rrc\n", rc2));
131 }
132}
133
134void VBoxIPCDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
135{
136 AssertPtr(pEnv);
137 AssertPtr(pInstance);
138
139 LogFunc(("Destroying pInstance=%p\n", pInstance));
140
141 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
142 AssertPtr(pCtx);
143
144 int rc = RTCritSectEnter(&pCtx->CritSect);
145 if (RT_SUCCESS(rc))
146 {
147 PVBOXIPCSESSION pSession;
148 RTListForEach(&pCtx->SessionList, pSession, VBOXIPCSESSION, Node)
149 {
150 int rc2 = vboxIPCSessionDestroyLocked(pCtx, pSession);
151 if (RT_FAILURE(rc2))
152 {
153 LogFunc(("Destroying IPC session %p failed with rc=%Rrc\n",
154 pSession, rc2));
155 /* Keep going. */
156 }
157 }
158
159 RTLocalIpcServerDestroy(pCtx->hServer);
160
161 int rc2 = RTCritSectLeave(&pCtx->CritSect);
162 AssertRC(rc2);
163
164 rc2 = RTCritSectDelete(&pCtx->CritSect);
165 AssertRC(rc2);
166 }
167
168 LogFunc(("Destroyed pInstance=%p, rc=%Rrc\n",
169 pInstance, rc));
170}
171
172/**
173 * Services a client session.
174 *
175 * @returns VINF_SUCCESS.
176 * @param hThread The thread handle.
177 * @param pvSession Pointer to the session instance data.
178 */
179static DECLCALLBACK(int) vboxIPCSessionThread(RTTHREAD hThread, void *pvSession)
180{
181 PVBOXIPCSESSION pThis = (PVBOXIPCSESSION)pvSession;
182 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
183 RTLOCALIPCSESSION hSession = pThis->hSession;
184 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
185
186 LogFunc(("pThis=%p\n", pThis));
187
188 /*
189 * Process client requests until it quits or we're cancelled on termination.
190 */
191 while (!ASMAtomicUoReadBool(&pThis->fTerminate))
192 {
193 int rc = RTLocalIpcSessionWaitForData(hSession, 1000 /* Timeout in ms. */);
194 if (RT_FAILURE(rc))
195 {
196 if (rc == VERR_CANCELLED)
197 {
198 LogFunc(("Waiting for data cancelled\n"));
199 rc = VINF_SUCCESS;
200 break;
201 }
202 else if (rc != VERR_TIMEOUT)
203 {
204 LogFunc(("Waiting for data failed, rc=%Rrc\n", rc));
205 break;
206 }
207 }
208
209 /** @todo Implement handler. */
210 }
211
212 /*
213 * Clean up the session.
214 */
215 PVBOXIPCCONTEXT pCtx = ASMAtomicReadPtrT(&pThis->pCtx, PVBOXIPCCONTEXT);
216 if (pCtx)
217 RTCritSectEnter(&pCtx->CritSect);
218 else
219 AssertMsgFailed(("Session %p: No context found\n", pThis));
220
221 ASMAtomicXchgHandle(&pThis->hSession, NIL_RTLOCALIPCSESSION, &hSession);
222 if (hSession != NIL_RTLOCALIPCSESSION)
223 RTLocalIpcSessionClose(hSession);
224 else
225 AssertMsgFailed(("Session %p: No/invalid session handle\n", pThis));
226
227 if (pCtx)
228 {
229 //RTSemEventSignal(pCtx->hSessionEvent);
230 RTCritSectLeave(&pCtx->CritSect);
231 }
232
233 LogFunc(("pThis=%p terminated\n", pThis));
234 return VINF_SUCCESS;
235}
236
237static int vboxIPCSessionCreate(PVBOXIPCCONTEXT pCtx, RTLOCALIPCSESSION hSession)
238{
239 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
240 AssertReturn(hSession != NIL_RTLOCALIPCSESSION, VERR_INVALID_PARAMETER);
241
242 int rc = RTCritSectEnter(&pCtx->CritSect);
243 if (RT_SUCCESS(rc))
244 {
245 PVBOXIPCSESSION pSession = (PVBOXIPCSESSION)RTMemAllocZ(sizeof(VBOXIPCSESSION));
246 if (pSession)
247 {
248 pSession->pCtx = pCtx;
249 pSession->hSession = hSession;
250 pSession->fTerminate = false;
251 pSession->hThread = NIL_RTTHREAD;
252
253 /* Start IPC session thread. */
254 LogFlowFunc(("Creating thread for session %p ...\n", pSession));
255 rc = RTThreadCreate(&pSession->hThread, vboxIPCSessionThread, pSession, 0,
256 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBXTRYIPCSESS");
257 if (RT_SUCCESS(rc))
258 {
259 /* Add session thread to session IPC list. */
260 RTListAppend(&pCtx->SessionList, &pSession->Node);
261 }
262 else
263 {
264 int rc2 = RTLocalIpcSessionClose(hSession);
265 if (RT_FAILURE(rc2))
266 LogFunc(("Failed closing session %p, rc=%Rrc\n", pSession, rc2));
267
268 LogFunc(("Failed to create thread for session %p, rc=%Rrc\n", pSession, rc));
269 RTMemFree(pSession);
270 }
271 }
272 else
273 rc = VERR_NO_MEMORY;
274
275 int rc2 = RTCritSectLeave(&pCtx->CritSect);
276 AssertRC(rc2);
277 }
278
279 return rc;
280}
281
282static int vboxIPCSessionDestroyLocked(PVBOXIPCCONTEXT pCtx, PVBOXIPCSESSION pSession)
283{
284 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
285 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
286
287 pSession->hThread = NIL_RTTHREAD;
288
289 RTLOCALIPCSESSION hSession;
290 ASMAtomicXchgHandle(&pSession->hSession, NIL_RTLOCALIPCSESSION, &hSession);
291 if (hSession != NIL_RTLOCALIPCSESSION)
292 RTLocalIpcSessionClose(hSession);
293
294 RTListNodeRemove(&pSession->Node);
295
296 RTMemFree(pSession);
297 pSession = NULL;
298
299 return VINF_SUCCESS;
300}
301
302/**
303 * Thread function to wait for and process seamless mode change
304 * requests
305 */
306unsigned __stdcall VBoxIPCThread(void *pInstance)
307{
308 LogFlowFuncEnter();
309
310 PVBOXIPCCONTEXT pCtx = (PVBOXIPCCONTEXT)pInstance;
311 AssertPtr(pCtx);
312
313 bool fShutdown = false;
314 for (;;)
315 {
316 RTLOCALIPCSESSION hClientSession = NIL_RTLOCALIPCSESSION;
317 int rc = RTLocalIpcServerListen(pCtx->hServer, &hClientSession);
318 if (RT_FAILURE(rc))
319 {
320 if (rc == VERR_CANCELLED)
321 {
322 LogFlow(("Cancelled\n"));
323 fShutdown = true;
324 }
325 else
326 LogRelFunc(("Listening failed with rc=%Rrc\n", rc));
327 }
328
329 if (fShutdown)
330 break;
331 rc = vboxIPCSessionCreate(pCtx, hClientSession);
332 if (RT_FAILURE(rc))
333 {
334 LogRelFunc(("Creating new IPC server session failed with rc=%Rrc\n", rc));
335 /* Keep going. */
336 }
337
338 AssertPtr(pCtx->pEnv);
339 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 0 /* No waiting */) == WAIT_OBJECT_0)
340 break;
341 }
342
343 LogFlowFuncLeave();
344 return 0;
345}
346
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