VirtualBox

source: vbox/trunk/src/VBox/Main/webservice/vboxweb.h@ 63940

Last change on this file since 63940 was 61361, checked in by vboxsync, 9 years ago

Main/webservice: switch to using monotonic time for sessin expiration, and add statistics logging for session and MOR count

  • Property filesplitter.c set to Makefile.kmk
  • Property svn:eol-style set to native
File size: 12.4 KB
Line 
1/*
2 * vboxweb.h:
3 * header file for "real" web server code.
4 *
5 * Copyright (C) 2006-2016 Oracle Corporation
6 *
7 * This file is part of VirtualBox Open Source Edition (OSE), as
8 * available from http://www.virtualbox.org. This file is free software;
9 * you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License (GPL) as published by the Free Software
11 * Foundation, in version 2 as it comes in the "COPYING" file of the
12 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
13 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
14 */
15
16#define LOG_GROUP LOG_GROUP_WEBSERVICE
17#include <VBox/log.h>
18#include <VBox/err.h>
19
20#include <VBox/com/VirtualBox.h>
21#include <VBox/com/Guid.h>
22#include <VBox/com/AutoLock.h>
23
24#include <iprt/asm.h>
25
26#include <string>
27
28/****************************************************************************
29 *
30 * debug macro
31 *
32 ****************************************************************************/
33
34#define WEBDEBUG(a) do { if (g_fVerbose) { LogRel(a); } } while (0)
35
36/****************************************************************************
37 *
38 * typedefs
39 *
40 ****************************************************************************/
41
42// type used by gSOAP-generated code
43typedef std::string WSDLT_ID; // combined managed object ref (websession ID plus object ID)
44typedef std::string vbox__uuid;
45
46/****************************************************************************
47 *
48 * global variables
49 *
50 ****************************************************************************/
51
52extern bool g_fVerbose;
53
54extern util::WriteLockHandle *g_pWebsessionsLockHandle;
55
56extern const WSDLT_ID g_EmptyWSDLID;
57
58/****************************************************************************
59 *
60 * SOAP exceptions
61 *
62 ****************************************************************************/
63
64extern void RaiseSoapInvalidObjectFault(struct soap *soap, WSDLT_ID obj);
65
66extern void RaiseSoapRuntimeFault(struct soap *soap, const WSDLT_ID &idThis, const char *pcszMethodName, HRESULT apirc, IUnknown *pObj, const com::Guid &iid);
67
68/****************************************************************************
69 *
70 * conversion helpers
71 *
72 ****************************************************************************/
73
74extern std::string ConvertComString(const com::Bstr &bstr);
75
76extern std::string ConvertComString(const com::Guid &bstr);
77
78extern std::string Base64EncodeByteArray(ComSafeArrayIn(BYTE, aData));
79
80extern void Base64DecodeByteArray(struct soap *soap, const std::string& aStr, ComSafeArrayOut(BYTE, aData), const WSDLT_ID &idThis, const char *pszMethodName, IUnknown *pObj, const com::Guid &iid);
81
82/****************************************************************************
83 *
84 * managed object reference classes
85 *
86 ****************************************************************************/
87
88class WebServiceSessionPrivate;
89class ManagedObjectRef;
90
91/**
92 * An instance of this gets created for every client that logs onto the
93 * webservice (via the special IWebsessionManager::logon() SOAP API) and
94 * maintains the managed object references for that websession.
95 */
96class WebServiceSession
97{
98 friend class ManagedObjectRef;
99
100 private:
101 uint64_t _uWebsessionID;
102 uint64_t _uNextObjectID;
103 WebServiceSessionPrivate *_pp; // opaque data struct (defined in vboxweb.cpp)
104 bool _fDestructing;
105
106 uint32_t _tLastObjectLookup;
107
108 // hide the copy constructor because we're not copyable
109 WebServiceSession(const WebServiceSession &copyFrom);
110
111 public:
112 WebServiceSession();
113
114 ~WebServiceSession();
115
116 int authenticate(const char *pcszUsername,
117 const char *pcszPassword,
118 IVirtualBox **ppVirtualBox);
119
120 ManagedObjectRef* findRefFromPtr(const IUnknown *pObject);
121
122 uint64_t getID() const
123 {
124 return _uWebsessionID;
125 }
126
127 uint64_t createObjectID()
128 {
129 uint64_t id = ASMAtomicIncU64(&_uNextObjectID);
130 return id - 1;
131 }
132
133 void touch();
134
135 uint32_t getLastObjectLookup() const
136 {
137 return _tLastObjectLookup;
138 }
139
140 static WebServiceSession* findWebsessionFromRef(const WSDLT_ID &id);
141
142 size_t CountRefs();
143};
144
145/**
146 * ManagedObjectRef is used to map COM pointers to object IDs
147 * within a websession. Such object IDs are 64-bit integers.
148 *
149 * When a webservice method call is invoked on an object, it
150 * has an opaque string called a "managed object reference". Such
151 * a string consists of a websession ID combined with an object ID.
152 *
153 */
154class ManagedObjectRef
155{
156 protected:
157 // owning websession:
158 WebServiceSession &_websession;
159
160
161 IUnknown *_pobjUnknown; // pointer to IUnknown interface for this MOR
162
163 void *_pobjInterface; // pointer to COM interface represented by _guidInterface, for which this MOR
164 // was created; this may be an IUnknown or something more specific
165 com::Guid _guidInterface; // the interface which _pvObj represents
166
167 const char *_pcszInterface; // string representation of that interface (e.g. "IMachine")
168
169 // keys:
170 uint64_t _id;
171 uintptr_t _ulp;
172
173 // long ID as string
174 WSDLT_ID _strID;
175
176 public:
177 ManagedObjectRef(WebServiceSession &websession,
178 IUnknown *pobjUnknown,
179 void *pobjInterface,
180 const com::Guid &guidInterface,
181 const char *pcszInterface);
182 ~ManagedObjectRef();
183
184 uint64_t getID()
185 {
186 return _id;
187 }
188
189 /**
190 * Returns the contained COM pointer and the UUID of the COM interface
191 * which it supports.
192 * @param
193 * @return
194 */
195 const com::Guid& getPtr(void **ppobjInterface,
196 IUnknown **ppobjUnknown)
197 {
198 *ppobjInterface = _pobjInterface;
199 *ppobjUnknown = _pobjUnknown;
200 return _guidInterface;
201 }
202
203 /**
204 * Returns the ID of this managed object reference to string
205 * form, for returning with SOAP data or similar.
206 *
207 * @return The ID in string form.
208 */
209 const WSDLT_ID& getWSDLID() const
210 {
211 return _strID;
212 }
213
214 const char* getInterfaceName() const
215 {
216 return _pcszInterface;
217 }
218
219 static int findRefFromId(const WSDLT_ID &id,
220 ManagedObjectRef **pRef,
221 bool fNullAllowed);
222};
223
224/**
225 * Template function that resolves a managed object reference to a COM pointer
226 * of the template class T.
227 *
228 * This gets called only from tons of generated code in methodmaps.cpp to
229 * resolve objects in *input* parameters to COM methods (i.e. translate
230 * MOR strings to COM objects which should exist already).
231 *
232 * This is a template function so that we can support ComPtr's for arbitrary
233 * interfaces and automatically verify that the managed object reference on
234 * the internal stack actually is of the expected interface. We also now avoid
235 * calling QueryInterface for the case that the interface desired by the caller
236 * is the same as the interface for which the MOR was originally created. In
237 * that case, the lookup is very fast.
238 *
239 * @param soap
240 * @param id in: integer managed object reference, as passed in by web service client
241 * @param pComPtr out: reference to COM pointer object that receives the com pointer,
242 * if SOAP_OK is returned
243 * @param fNullAllowed in: if true, then this func returns a NULL COM pointer if an
244 * empty MOR is passed in (i.e. NULL pointers are allowed). If false,
245 * then this fails; this will be false when called for the "this"
246 * argument of method calls, which really shouldn't be NULL.
247 * @return error code or SOAP_OK if no error
248 */
249template <class T>
250int findComPtrFromId(struct soap *soap,
251 const WSDLT_ID &id,
252 ComPtr<T> &pComPtr,
253 bool fNullAllowed)
254{
255 // findRefFromId requires thelock
256 util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
257
258 int rc;
259 ManagedObjectRef *pRef;
260 if ((rc = ManagedObjectRef::findRefFromId(id, &pRef, fNullAllowed)))
261 // error:
262 RaiseSoapInvalidObjectFault(soap, id);
263 else
264 {
265 if (fNullAllowed && pRef == NULL)
266 {
267 WEBDEBUG((" %s(): returning NULL object as permitted\n", __FUNCTION__));
268 pComPtr.setNull();
269 return 0;
270 }
271
272 const com::Guid &guidCaller = COM_IIDOF(T);
273
274 // pRef->getPtr returns both a void* for its specific interface pointer as well as a generic IUnknown*
275 void *pobjInterface;
276 IUnknown *pobjUnknown;
277 const com::Guid &guidInterface = pRef->getPtr(&pobjInterface, &pobjUnknown);
278
279 if (guidInterface == guidCaller)
280 {
281 // same interface: then no QueryInterface needed
282 WEBDEBUG((" %s(): returning original %s*=0x%lX (IUnknown*=0x%lX)\n", __FUNCTION__, pRef->getInterfaceName(), pobjInterface, pobjUnknown));
283 pComPtr = (T*)pobjInterface; // this calls AddRef() once
284 return 0;
285 }
286
287 // QueryInterface tests whether p actually supports the templated T interface desired by caller
288 T *pT;
289 pobjUnknown->QueryInterface(guidCaller.ref(), (void**)&pT); // this adds a reference count
290 if (pT)
291 {
292 // assign to caller's ComPtr<T>; use asOutParam() to avoid adding another reference, QueryInterface() already added one
293 WEBDEBUG((" %s(): returning pointer 0x%lX for queried interface %RTuuid (IUnknown*=0x%lX)\n", __FUNCTION__, pT, guidCaller.raw(), pobjUnknown));
294 *(pComPtr.asOutParam()) = pT;
295 return 0;
296 }
297
298 WEBDEBUG((" Interface not supported for object reference %s, which is of class %s\n", id.c_str(), pRef->getInterfaceName()));
299 rc = VERR_WEB_UNSUPPORTED_INTERFACE;
300 RaiseSoapInvalidObjectFault(soap, id); // @todo better message
301 }
302
303 return rc;
304}
305
306/**
307 * Creates a new managed object reference for the given COM pointer. If one
308 * already exists for the given pointer, then that reference's ID is returned.
309 *
310 * This gets called from tons of generated code in methodmaps.cpp to resolve
311 * objects *returned* from COM methods (i.e. create MOR strings from COM
312 * objects which might have been newly created).
313 *
314 * @param idParent managed object reference of calling object; used to extract
315 * websession ID
316 * @param pc COM object for which to create a reference
317 * @return existing or new managed object reference
318 */
319template <class T>
320const WSDLT_ID& createOrFindRefFromComPtr(const WSDLT_ID &idParent,
321 const char *pcszInterface,
322 const ComPtr<T> &pc)
323{
324 // NULL comptr should return NULL MOR
325 if (pc.isNull())
326 {
327 WEBDEBUG((" createOrFindRefFromComPtr(): returning empty MOR for NULL COM pointer\n"));
328 return g_EmptyWSDLID;
329 }
330
331 util::AutoWriteLock lock(g_pWebsessionsLockHandle COMMA_LOCKVAL_SRC_POS);
332 WebServiceSession *pWebsession;
333 if ((pWebsession = WebServiceSession::findWebsessionFromRef(idParent)))
334 {
335 ManagedObjectRef *pRef;
336
337 // we need an IUnknown pointer for the MOR
338 ComPtr<IUnknown> pobjUnknown = pc;
339
340 if ( ((pRef = pWebsession->findRefFromPtr(pobjUnknown)))
341 || ((pRef = new ManagedObjectRef(*pWebsession,
342 pobjUnknown, // IUnknown *pobjUnknown
343 pc, // void *pobjInterface
344 COM_IIDOF(T),
345 pcszInterface)))
346 )
347 return pRef->getWSDLID();
348 }
349
350 // websession has expired, return an empty MOR instead of allocating a
351 // new reference which couldn't be used anyway.
352 return g_EmptyWSDLID;
353}
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