VirtualBox

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

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

Main/VirtualBox+Machine+Session: separate out the client death detection functionality into separate objects

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.4 KB
Line 
1/** @file
2 *
3 * VirtualBox API client crash token handling
4 */
5
6/*
7 * Copyright (C) 2004-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <iprt/asm.h>
19#include <iprt/assert.h>
20#include <iprt/log.h>
21#include <iprt/semaphore.h>
22#include <iprt/process.h>
23
24#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
25# include <errno.h>
26# include <sys/types.h>
27# include <sys/stat.h>
28# include <sys/ipc.h>
29# include <sys/sem.h>
30#endif
31
32#include <VBox/com/defs.h>
33
34#include <vector>
35
36#include "VirtualBoxBase.h"
37#include "AutoCaller.h"
38#include "ClientToken.h"
39#include "MachineImpl.h"
40
41Machine::ClientToken::ClientToken()
42{
43 AssertReleaseFailed();
44}
45
46Machine::ClientToken::~ClientToken()
47{
48#if defined(RT_OS_WINDOWS)
49 if (mClientToken)
50 ::CloseHandle(mClientToken);
51#elif defined(RT_OS_OS2)
52 if (mClientToken != NULLHANDLE)
53 ::DosCloseMutexSem(mClientToken);
54#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
55 if (mClientToken >= 0)
56 ::semctl(mClientToken, 0, IPC_RMID);
57# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
58 mClientTokenId = "0";
59# endif /* VBOX_WITH_NEW_SYS_V_KEYGEN */
60#else
61# error "Port me!"
62#endif
63 mClientToken = CTTOKENARG;
64}
65
66Machine::ClientToken::ClientToken(const ComObjPtr<Machine> &pMachine) :
67 mMachine(pMachine)
68{
69#if defined(RT_OS_WINDOWS)
70 Bstr tokenId = pMachine->mData->m_strConfigFileFull;
71 for (size_t i = 0; i < tokenId.length(); i++)
72 if (tokenId.raw()[i] == '\\')
73 tokenId.raw()[i] = '/';
74 mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw());
75 mClientTokenId = tokenId;
76 AssertMsg(mClientToken,
77 ("Cannot create token '%s', err=%d",
78 mClientTokenId.c_str(), ::GetLastError()));
79#elif defined(RT_OS_OS2)
80 Utf8Str ipcSem = Utf8StrFmt("\\SEM32\\VBOX\\VM\\{%RTuuid}",
81 pMachine->mData->mUuid.raw());
82 mClientTokenId = ipcSem;
83 APIRET arc = ::DosCreateMutexSem((PSZ)ipcSem.c_str(), &mClientToken, 0, FALSE);
84 AssertMsg(arc == NO_ERROR,
85 ("Cannot create token '%s', arc=%ld",
86 ipcSem.c_str(), arc));
87#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
88# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
89# if defined(RT_OS_FREEBSD) && (HC_ARCH_BITS == 64)
90 /** @todo Check that this still works correctly. */
91 AssertCompileSize(key_t, 8);
92# else
93 AssertCompileSize(key_t, 4);
94# endif
95 key_t key;
96 mClientToken = -1;
97 mClientTokenId = "0";
98 for (uint32_t i = 0; i < 1 << 24; i++)
99 {
100 key = ((uint32_t)'V' << 24) | i;
101 int sem = ::semget(key, 1, S_IRUSR | S_IWUSR | IPC_CREAT | IPC_EXCL);
102 if (sem >= 0 || (errno != EEXIST && errno != EACCES))
103 {
104 mClientToken = sem;
105 if (sem >= 0)
106 mClientTokenId = BstrFmt("%u", key);
107 break;
108 }
109 }
110# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
111 Utf8Str semName = pMachine->mData->m_strConfigFileFull;
112 char *pszSemName = NULL;
113 RTStrUtf8ToCurrentCP(&pszSemName, semName);
114 key_t key = ::ftok(pszSemName, 'V');
115 RTStrFree(pszSemName);
116
117 mClientToken = ::semget(key, 1, S_IRWXU | S_IRWXG | S_IRWXO | IPC_CREAT);
118# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
119
120 int errnoSave = errno;
121 if (mClientToken < 0 && errnoSave == ENOSYS)
122 {
123 mMachine->setError(E_FAIL,
124 tr("Cannot create IPC semaphore. Most likely your host kernel lacks "
125 "support for SysV IPC. Check the host kernel configuration for "
126 "CONFIG_SYSVIPC=y"));
127 mClientToken = CTTOKENARG;
128 return;
129 }
130 /* ENOSPC can also be the result of VBoxSVC crashes without properly freeing
131 * the token */
132 if (mClientToken < 0 && errnoSave == ENOSPC)
133 {
134#ifdef RT_OS_LINUX
135 mMachine->setError(E_FAIL,
136 tr("Cannot create IPC semaphore because the system limit for the "
137 "maximum number of semaphore sets (SEMMNI), or the system wide "
138 "maximum number of semaphores (SEMMNS) would be exceeded. The "
139 "current set of SysV IPC semaphores can be determined from "
140 "the file /proc/sysvipc/sem"));
141#else
142 mMachine->setError(E_FAIL,
143 tr("Cannot create IPC semaphore because the system-imposed limit "
144 "on the maximum number of allowed semaphores or semaphore "
145 "identifiers system-wide would be exceeded"));
146#endif
147 mClientToken = CTTOKENARG;
148 return;
149 }
150 AssertMsgReturnVoid(mClientToken >= 0, ("Cannot create token, errno=%d", errnoSave));
151 /* set the initial value to 1 */
152 int rv = ::semctl(mClientToken, 0, SETVAL, 1);
153 errnoSave = errno;
154 if (rv != 0)
155 {
156 ::semctl(mClientToken, 0, IPC_RMID);
157 mClientToken = CTTOKENARG;
158 AssertMsgFailedReturnVoid(("Cannot init token, errno=%d", errnoSave));
159 }
160#else
161# error "Port me!"
162#endif
163}
164
165bool Machine::ClientToken::isReady()
166{
167 return mClientToken != CTTOKENARG;
168}
169
170void Machine::ClientToken::getId(Utf8Str &strId)
171{
172 strId = mClientTokenId;
173}
174
175CTTOKENTYPE Machine::ClientToken::getToken()
176{
177 return mClientToken;
178}
179
180bool Machine::ClientToken::release()
181{
182 bool terminated = false;
183
184#if defined(RT_OS_WINDOWS)
185 AssertMsg(mClientToken, ("semaphore must be created"));
186
187 /* release the token */
188 ::ReleaseMutex(mClientToken);
189 terminated = true;
190#elif defined(RT_OS_OS2)
191 AssertMsg(mClientToken, ("semaphore must be created"));
192
193 /* release the token */
194 ::DosReleaseMutexSem(mClientToken);
195 terminated = true;
196#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
197 AssertMsg(mClientToken >= 0, ("semaphore must be created"));
198 int val = ::semctl(mClientToken, 0, GETVAL);
199 if (val > 0)
200 {
201 /* the semaphore is signaled, meaning the session is terminated */
202 terminated = true;
203 }
204#else
205# error "Port me!"
206#endif
207 return terminated;
208}
209
210/* 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