VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp@ 78425

Last change on this file since 78425 was 77436, checked in by vboxsync, 6 years ago

Main: Eradicate the use of BSTR in regular API code, there were leaks in almost every occurrence. Also do some Bstr->Utf8Str shuffling to reduce the number of conversions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.7 KB
Line 
1/* $Id: ClientTokenHolder.cpp 77436 2019-02-22 17:40:00Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox API client session token holder (in the client process)
5 */
6
7/*
8 * Copyright (C) 2006-2019 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#define LOG_GROUP LOG_GROUP_MAIN_SESSION
20#include "LoggingNew.h"
21
22#include <iprt/asm.h>
23#include <iprt/assert.h>
24#include <iprt/log.h>
25#include <iprt/semaphore.h>
26#include <iprt/process.h>
27
28#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
29# include <errno.h>
30# include <sys/types.h>
31# include <sys/stat.h>
32# include <sys/ipc.h>
33# include <sys/sem.h>
34#endif
35
36#include <VBox/com/defs.h>
37
38#include "ClientTokenHolder.h"
39#include "SessionImpl.h"
40
41
42#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
43/** client token holder thread */
44static DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD hThreadSelf, void *pvUser);
45#endif
46
47
48Session::ClientTokenHolder::ClientTokenHolder()
49{
50 AssertReleaseFailed();
51}
52
53Session::ClientTokenHolder::~ClientTokenHolder()
54{
55 /* release the client token */
56#if defined(RT_OS_WINDOWS)
57
58 if (mSem && mThreadSem)
59 {
60 /*
61 * tell the thread holding the token to release it;
62 * it will close mSem handle
63 */
64 ::SetEvent(mSem);
65 /* wait for the thread to finish */
66 ::WaitForSingleObject(mThreadSem, INFINITE);
67 ::CloseHandle(mThreadSem);
68
69 mThreadSem = NULL;
70 mSem = NULL;
71 mThread = NIL_RTTHREAD;
72 }
73
74#elif defined(RT_OS_OS2)
75
76 if (mThread != NIL_RTTHREAD)
77 {
78 Assert(mSem != NIL_RTSEMEVENT);
79
80 /* tell the thread holding the token to release it */
81 int vrc = RTSemEventSignal(mSem);
82 AssertRC(vrc == NO_ERROR);
83
84 /* wait for the thread to finish */
85 vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT);
86 Assert(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED);
87
88 mThread = NIL_RTTHREAD;
89 }
90
91 if (mSem != NIL_RTSEMEVENT)
92 {
93 RTSemEventDestroy(mSem);
94 mSem = NIL_RTSEMEVENT;
95 }
96
97#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
98
99 if (mSem >= 0)
100 {
101 ::sembuf sop = { 0, 1, SEM_UNDO };
102 ::semop(mSem, &sop, 1);
103
104 mSem = -1;
105 }
106
107#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
108
109 if (!mToken.isNull())
110 {
111 mToken->Abandon();
112 mToken.setNull();
113 }
114
115#else
116# error "Port me!"
117#endif
118}
119
120#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
121Session::ClientTokenHolder::ClientTokenHolder(const Utf8Str &strTokenId) :
122 mClientTokenId(strTokenId)
123#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
124Session::ClientTokenHolder::ClientTokenHolder(IToken *aToken) :
125 mToken(aToken)
126#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
127{
128#ifdef CTHSEMTYPE
129 mSem = CTHSEMARG;
130#endif
131#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
132 mThread = NIL_RTTHREAD;
133#endif
134
135#if defined(RT_OS_WINDOWS)
136 mThreadSem = CTHTHREADSEMARG;
137
138 /*
139 * Since there is no guarantee that the constructor and destructor will be
140 * called in the same thread, we need a separate thread to hold the token.
141 */
142
143 mThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL);
144 AssertMsgReturnVoid(mThreadSem,
145 ("Cannot create an event sem, err=%d", ::GetLastError()));
146
147 void *data[3];
148 data[0] = (void*)strTokenId.c_str();
149 data[1] = (void*)mThreadSem;
150 data[2] = 0; /* will get an output from the thread */
151
152 /* create a thread to hold the token until signalled to release it */
153 int vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
154 AssertRCReturnVoid(vrc);
155
156 /* wait until thread init is completed */
157 DWORD wrc = ::WaitForSingleObject(mThreadSem, INFINITE);
158 AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError()));
159 Assert(data[2]);
160
161 if (wrc == WAIT_OBJECT_0 && data[2])
162 {
163 /* memorize the event sem we should signal in close() */
164 mSem = (HANDLE)data[2];
165 }
166 else
167 {
168 ::CloseHandle(mThreadSem);
169 mThreadSem = NULL;
170 }
171#elif defined(RT_OS_OS2)
172 /*
173 * Since there is no guarantee that the constructor and destructor will be
174 * called in the same thread, we need a separate thread to hold the token.
175 */
176
177 int vrc = RTSemEventCreate(&mSem);
178 AssertRCReturnVoid(vrc);
179
180 void *data[3];
181 data[0] = (void*)strTokenId.c_str();
182 data[1] = (void*)mSem;
183 data[2] = (void*)false; /* will get the thread result here */
184
185 /* create a thread to hold the token until signalled to release it */
186 vrc = RTThreadCreate(&mThread, ClientTokenHolderThread, (void *) data,
187 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
188 AssertRCReturnVoid(vrc);
189 /* wait until thread init is completed */
190 vrc = RTThreadUserWait(mThread, RT_INDEFINITE_WAIT);
191 AssertReturnVoid(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED);
192
193 /* the thread must succeed */
194 AssertReturnVoid((bool)data[2]);
195
196#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
197
198# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
199 key_t key = RTStrToUInt32(strTokenId.c_str());
200 AssertMsgReturnVoid(key != 0,
201 ("Key value of 0 is not valid for client token"));
202# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
203 char *pszSemName = NULL;
204 RTStrUtf8ToCurrentCP(&pszSemName, strTokenId);
205 key_t key = ::ftok(pszSemName, 'V');
206 RTStrFree(pszSemName);
207# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
208 int s = ::semget(key, 0, 0);
209 AssertMsgReturnVoid(s >= 0,
210 ("Cannot open semaphore, errno=%d", errno));
211
212 /* grab the semaphore */
213 ::sembuf sop = { 0, -1, SEM_UNDO };
214 int rv = ::semop(s, &sop, 1);
215 AssertMsgReturnVoid(rv == 0,
216 ("Cannot grab semaphore, errno=%d", errno));
217 mSem = s;
218
219#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
220
221 /* nothing to do */
222
223#else
224# error "Port me!"
225#endif
226}
227
228bool Session::ClientTokenHolder::isReady()
229{
230#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
231 return mSem != CTHSEMARG;
232#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
233 return !mToken.isNull();
234#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
235}
236
237#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
238/** client token holder thread */
239DECLCALLBACK(int) ClientTokenHolderThread(RTTHREAD hThreadSelf, void *pvUser)
240{
241 RT_NOREF(hThreadSelf);
242 LogFlowFuncEnter();
243
244 Assert(pvUser);
245
246 void **data = (void **)pvUser;
247
248# if defined(RT_OS_WINDOWS)
249 Utf8Str strSessionId = (const char *)data[0];
250 HANDLE initDoneSem = (HANDLE)data[1];
251
252 HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, Bstr(strSessionId).raw());
253 AssertMsg(mutex, ("cannot open token, err=%d\n", ::GetLastError()));
254
255 if (mutex)
256 {
257 /* grab the token */
258 DWORD wrc = ::WaitForSingleObject(mutex, 0);
259 AssertMsg(wrc == WAIT_OBJECT_0, ("cannot grab token, err=%d\n", wrc));
260 if (wrc == WAIT_OBJECT_0)
261 {
262 HANDLE finishSem = ::CreateEvent(NULL, FALSE, FALSE, NULL);
263 AssertMsg(finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
264 if (finishSem)
265 {
266 data[2] = (void*)finishSem;
267 /* signal we're done with init */
268 ::SetEvent(initDoneSem);
269 /* wait until we're signaled to release the token */
270 ::WaitForSingleObject(finishSem, INFINITE);
271 /* release the token */
272 LogFlow(("ClientTokenHolderThread(): releasing token...\n"));
273 BOOL fRc = ::ReleaseMutex(mutex);
274 AssertMsg(fRc, ("cannot release token, err=%d\n", ::GetLastError())); NOREF(fRc);
275 ::CloseHandle(mutex);
276 ::CloseHandle(finishSem);
277 }
278 }
279 }
280
281 /* signal we're done */
282 ::SetEvent(initDoneSem);
283# elif defined(RT_OS_OS2)
284 Utf8Str strSessionId = (const char *)data[0];
285 RTSEMEVENT finishSem = (RTSEMEVENT)data[1];
286
287 LogFlowFunc(("strSessionId='%s', finishSem=%p\n", strSessionId.c_str(), finishSem));
288
289 HMTX mutex = NULLHANDLE;
290 APIRET arc = ::DosOpenMutexSem((PSZ)strSessionId.c_str(), &mutex);
291 AssertMsg(arc == NO_ERROR, ("cannot open token, arc=%ld\n", arc));
292
293 if (arc == NO_ERROR)
294 {
295 /* grab the token */
296 LogFlowFunc(("grabbing token...\n"));
297 arc = ::DosRequestMutexSem(mutex, SEM_IMMEDIATE_RETURN);
298 AssertMsg(arc == NO_ERROR, ("cannot grab token, arc=%ld\n", arc));
299 if (arc == NO_ERROR)
300 {
301 /* store the answer */
302 data[2] = (void*)true;
303 /* signal we're done */
304 int vrc = RTThreadUserSignal(Thread);
305 AssertRC(vrc);
306
307 /* wait until we're signaled to release the token */
308 LogFlowFunc(("waiting for termination signal..\n"));
309 vrc = RTSemEventWait(finishSem, RT_INDEFINITE_WAIT);
310 Assert(arc == ERROR_INTERRUPT || ERROR_TIMEOUT);
311
312 /* release the token */
313 LogFlowFunc(("releasing token...\n"));
314 arc = ::DosReleaseMutexSem(mutex);
315 AssertMsg(arc == NO_ERROR, ("cannot release token, arc=%ld\n", arc));
316 }
317 ::DosCloseMutexSem(mutex);
318 }
319
320 /* store the answer */
321 data[1] = (void*)false;
322 /* signal we're done */
323 int vrc = RTThreadUserSignal(Thread);
324 AssertRC(vrc);
325# else
326# error "Port me!"
327# endif
328
329 LogFlowFuncLeave();
330
331 return 0;
332}
333#endif
334
335/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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