VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/ClientToken.cpp@ 69498

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

backed out r118835 as it incorrectly updated the 'This file is based on' file headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.2 KB
Line 
1/* $Id: ClientToken.cpp 69498 2017-10-28 15:07:25Z vboxsync $ */
2/** @file
3 *
4 * VirtualBox API client session crash token handling
5 */
6
7/*
8 * Copyright (C) 2004-2016 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
20#include <iprt/asm.h>
21#include <iprt/assert.h>
22#include <VBox/log.h>
23#include <iprt/semaphore.h>
24#include <iprt/process.h>
25
26#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
27# include <errno.h>
28# include <sys/types.h>
29# include <sys/stat.h>
30# include <sys/ipc.h>
31# include <sys/sem.h>
32#endif
33
34#include <VBox/com/defs.h>
35
36#include <vector>
37
38#include "VirtualBoxBase.h"
39#include "AutoCaller.h"
40#include "ClientToken.h"
41#include "MachineImpl.h"
42
43Machine::ClientToken::ClientToken()
44{
45 AssertReleaseFailed();
46}
47
48Machine::ClientToken::~ClientToken()
49{
50#if defined(RT_OS_WINDOWS)
51 if (mClientToken)
52 {
53 LogFlowFunc(("Closing mClientToken=%p\n", mClientToken));
54 ::CloseHandle(mClientToken);
55 }
56#elif defined(RT_OS_OS2)
57 if (mClientToken != NULLHANDLE)
58 ::DosCloseMutexSem(mClientToken);
59#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
60 if (mClientToken >= 0)
61 ::semctl(mClientToken, 0, IPC_RMID);
62# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
63 mClientTokenId = "0";
64# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
65#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
66 /* release the token, uses reference counting */
67 if (mClientToken)
68 {
69 if (!mClientTokenPassed)
70 mClientToken->Release();
71 mClientToken = NULL;
72 }
73#else
74# error "Port me!"
75#endif
76 mClientToken = CTTOKENARG;
77}
78
79Machine::ClientToken::ClientToken(const ComObjPtr<Machine> &pMachine,
80 SessionMachine *pSessionMachine) :
81 mMachine(pMachine)
82{
83#if defined(RT_OS_WINDOWS)
84 NOREF(pSessionMachine);
85 Bstr tokenId = pMachine->mData->m_strConfigFileFull;
86 for (size_t i = 0; i < tokenId.length(); i++)
87 if (tokenId.raw()[i] == '\\')
88 tokenId.raw()[i] = '/';
89 mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw());
90 mClientTokenId = tokenId;
91 AssertMsg(mClientToken,
92 ("Cannot create token '%s', err=%d",
93 mClientTokenId.c_str(), ::GetLastError()));
94#elif defined(RT_OS_OS2)
95 NOREF(pSessionMachine);
96 Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}",
97 pMachine->mData->mUuid.raw());
98 mClientTokenId = ipcSem;
99 APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mClientToken, 0, FALSE);
100 AssertMsg(arc == NO_ERROR,
101 ("Cannot create token '%s', arc=%ld",
102 ipcSem.c_str(), arc));
103#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
104 NOREF(pSessionMachine);
105# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
106# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64)
107 /** @todo Check that this still works correctly. */
108 AssertCompileSize(key_t, 8);
109# else
110 AssertCompileSize(key_t, 4);
111# endif
112 key_t key;
113 mClientToken = -1;
114 mClientTokenId = "0";
115 for (uint32_t i = 0; i < 1 << 24; i++)
116 {
117 key = ((uint32_t)'V' << 24) | i;
118 int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
119 if (sem >= 0 || (errno != EEXIST && errno != EACCES))
120 {
121 mClientToken = sem;
122 if (sem >= 0)
123 mClientTokenId = BstrFmt("%u", key);
124 break;
125 }
126 }
127# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
128 Utf8Str semName = pMachine->mData->m_strConfigFileFull;
129 char *pszSemName = NULL;
130 RTStrUtf8ToCurrentCP(&pszSemName, semName);
131 key_t key = ::ftok(pszSemName, 'V');
132 RTStrFree(pszSemName);
133
134 mClientToken = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT);
135# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
136
137 int errnoSave = errno;
138 if (mClientToken < 0 && errnoSave == ENOSYS)
139 {
140 mMachine->setError(E_FAIL,
141 tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
142 "support for SysV IPC. Check the host kernel configuration for "
143 "CONFIG_SYSVIPC=y"));
144 mClientToken = CTTOKENARG;
145 return;
146 }
147 /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
148 * the token */
149 if (mClientToken < 0 && errnoSave == ENOSPC)
150 {
151#ifdef RT_OS_LINUX
152 mMachine->setError(E_FAIL,
153 tr("Cannot create IPC semaphore because the system limit for the "
154 "maximum number of semaphore sets (SEMMNI), or the system wide "
155 "maximum number of semaphores (SEMMNS) would be exceeded. The "
156 "current set of SysV IPC semaphores can be determined from "
157 "the file /proc/sysvipc/sem"));
158#else
159 mMachine->setError(E_FAIL,
160 tr("Cannot create IPC semaphore because the system-imposed limit "
161 "on the maximum number of allowed semaphores or semaphore "
162 "identifiers system-wide would be exceeded"));
163#endif
164 mClientToken = CTTOKENARG;
165 return;
166 }
167 AssertMsgReturnVoid(mClientToken >= 0, ("Cannot create token, errno=%d", errnoSave));
168 /* set the initial value to 1 */
169 int rv = ::semctl(mClientToken, 0, SETVAL, 1);
170 errnoSave = errno;
171 if (rv != 0)
172 {
173 ::semctl(mClientToken, 0, IPC_RMID);
174 mClientToken = CTTOKENARG;
175 AssertMsgFailedReturnVoid(("Cannot init token, errno=%d", errnoSave));
176 }
177#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
178 ComObjPtr<MachineToken> pToken;
179 HRESULT rc = pToken.createObject();
180 if (SUCCEEDED(rc))
181 {
182 rc = pToken->init(pSessionMachine);
183 if (SUCCEEDED(rc))
184 {
185 mClientToken = pToken;
186 if (mClientToken)
187 {
188 rc = mClientToken->AddRef();
189 if (FAILED(rc))
190 mClientToken = NULL;
191 }
192 }
193 }
194 pToken.setNull();
195 mClientTokenPassed = false;
196 /* mClientTokenId isn't really used */
197 mClientTokenId = pMachine->mData->m_strConfigFileFull;
198 AssertMsg(mClientToken,
199 ("Cannot create token '%s', rc=%Rhrc",
200 mClientTokenId.c_str(), rc));
201#else
202# error "Port me!"
203#endif
204}
205
206bool Machine::ClientToken::isReady()
207{
208 return mClientToken != CTTOKENARG;
209}
210
211void Machine::ClientToken::getId(Utf8Str &strId)
212{
213 strId = mClientTokenId;
214}
215
216CTTOKENTYPE Machine::ClientToken::getToken()
217{
218#ifdef VBOX_WITH_GENERIC_SESSION_WATCHER
219 mClientTokenPassed = true;
220#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
221 return mClientToken;
222}
223
224#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
225bool Machine::ClientToken::release()
226{
227 bool terminated = false;
228
229#if defined(RT_OS_WINDOWS)
230 AssertMsg(mClientToken, ("semaphore must be created"));
231
232 /* release the token */
233 ::ReleaseMutex(mClientToken);
234 terminated = true;
235#elif defined(RT_OS_OS2)
236 AssertMsg(mClientToken, ("semaphore must be created"));
237
238 /* release the token */
239 ::DosReleaseMutexSem(mClientToken);
240 terminated = true;
241#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
242 AssertMsg(mClientToken >= 0, ("semaphore must be created"));
243 int val = ::semctl(mClientToken, 0, GETVAL);
244 if (val > 0)
245 {
246 /* the semaphore is signaled, meaning the session is terminated */
247 terminated = true;
248 }
249#elif defined(VBOX_WITH_GENERIC_SESSION_WATCHER)
250 /** @todo r=klaus never tested, this code is not reached */
251 AssertMsg(mClientToken, ("token must be created"));
252 /* release the token, uses reference counting */
253 if (mClientToken)
254 {
255 if (!mClientTokenPassed)
256 mClientToken->Release();
257 mClientToken = NULL;
258 }
259 terminated = true;
260#else
261# error "Port me!"
262#endif
263 return terminated;
264}
265#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */
266
267/* 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