VirtualBox

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

Last change on this file since 73768 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use