VirtualBox

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

© 2023 Oracle
ContactPrivacy policyTerms of Use