VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp@ 47631

Last change on this file since 47631 was 47627, checked in by vboxsync, 11 years ago

Main/GuestCtrl: Reduced locking times, more error checking, adjusted logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 92.8 KB
Line 
1
2/* $Id: GuestSessionImpl.cpp 47627 2013-08-09 08:31:24Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest session handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 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
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include "GuestImpl.h"
24#include "GuestSessionImpl.h"
25#include "GuestCtrlImplPrivate.h"
26#include "VirtualBoxErrorInfoImpl.h"
27
28#include "Global.h"
29#include "AutoCaller.h"
30#include "ProgressImpl.h"
31#include "VBoxEvents.h"
32#include "VMMDev.h"
33
34#include <memory> /* For auto_ptr. */
35
36#include <iprt/cpp/utils.h> /* For unconst(). */
37#include <iprt/env.h>
38#include <iprt/file.h> /* For CopyTo/From. */
39
40#include <VBox/com/array.h>
41#include <VBox/com/listeners.h>
42#include <VBox/version.h>
43
44#ifdef LOG_GROUP
45 #undef LOG_GROUP
46#endif
47#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
48#include <VBox/log.h>
49
50
51/**
52 * Base class representing an internal
53 * asynchronous session task.
54 */
55class GuestSessionTaskInternal
56{
57public:
58
59 GuestSessionTaskInternal(GuestSession *pSession)
60 : mSession(pSession),
61 mRC(VINF_SUCCESS) { }
62
63 virtual ~GuestSessionTaskInternal(void) { }
64
65 int rc(void) const { return mRC; }
66 bool isOk(void) const { return RT_SUCCESS(mRC); }
67 const ComObjPtr<GuestSession> &Session(void) const { return mSession; }
68
69protected:
70
71 const ComObjPtr<GuestSession> mSession;
72 int mRC;
73};
74
75/**
76 * Class for asynchronously opening a guest session.
77 */
78class GuestSessionTaskInternalOpen : public GuestSessionTaskInternal
79{
80public:
81
82 GuestSessionTaskInternalOpen(GuestSession *pSession)
83 : GuestSessionTaskInternal(pSession) { }
84};
85
86/**
87 * Internal listener class to serve events in an
88 * active manner, e.g. without polling delays.
89 */
90class GuestSessionListener
91{
92public:
93
94 GuestSessionListener(void)
95 {
96 }
97
98 HRESULT init(GuestSession *pSession)
99 {
100 mSession = pSession;
101 return S_OK;
102 }
103
104 void uninit(void)
105 {
106 mSession.setNull();
107 }
108
109 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
110 {
111 switch (aType)
112 {
113 case VBoxEventType_OnGuestSessionStateChanged:
114 {
115 Assert(!mSession.isNull());
116 int rc2 = mSession->signalWaitEvents(aType, aEvent);
117#ifdef DEBUG_andy
118 LogFlowFunc(("Signalling events of type=%ld, session=%p resulted in rc=%Rrc\n",
119 aType, mSession, rc2));
120#endif
121 break;
122 }
123
124 default:
125 AssertMsgFailed(("Unhandled event %ld\n", aType));
126 break;
127 }
128
129 return S_OK;
130 }
131
132private:
133
134 ComObjPtr<GuestSession> mSession;
135};
136typedef ListenerImpl<GuestSessionListener, GuestSession*> GuestSessionListenerImpl;
137
138VBOX_LISTENER_DECLARE(GuestSessionListenerImpl)
139
140// constructor / destructor
141/////////////////////////////////////////////////////////////////////////////
142
143DEFINE_EMPTY_CTOR_DTOR(GuestSession)
144
145HRESULT GuestSession::FinalConstruct(void)
146{
147 LogFlowThisFunc(("\n"));
148 return BaseFinalConstruct();
149}
150
151void GuestSession::FinalRelease(void)
152{
153 LogFlowThisFuncEnter();
154 uninit();
155 BaseFinalRelease();
156 LogFlowThisFuncLeave();
157}
158
159// public initializer/uninitializer for internal purposes only
160/////////////////////////////////////////////////////////////////////////////
161
162/**
163 * Initializes a guest session but does *not* open in on the guest side
164 * yet. This needs to be done via the openSession() / openSessionAsync calls.
165 *
166 * @return IPRT status code.
167 ** @todo Docs!
168 */
169int GuestSession::init(Guest *pGuest, const GuestSessionStartupInfo &ssInfo,
170 const GuestCredentials &guestCreds)
171{
172 LogFlowThisFunc(("pGuest=%p, ssInfo=%p, guestCreds=%p\n",
173 pGuest, &ssInfo, &guestCreds));
174
175 /* Enclose the state transition NotReady->InInit->Ready. */
176 AutoInitSpan autoInitSpan(this);
177 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
178
179#ifndef VBOX_WITH_GUEST_CONTROL
180 autoInitSpan.setSucceeded();
181 return VINF_SUCCESS;
182#else
183 AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
184
185 mParent = pGuest;
186
187 /* Copy over startup info. */
188 /** @todo Use an overloaded copy operator. Later. */
189 mData.mSession.mID = ssInfo.mID;
190 mData.mSession.mIsInternal = ssInfo.mIsInternal;
191 mData.mSession.mName = ssInfo.mName;
192 mData.mSession.mOpenFlags = ssInfo.mOpenFlags;
193 mData.mSession.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
194
195 /** @todo Use an overloaded copy operator. Later. */
196 mData.mCredentials.mUser = guestCreds.mUser;
197 mData.mCredentials.mPassword = guestCreds.mPassword;
198 mData.mCredentials.mDomain = guestCreds.mDomain;
199
200 mData.mRC = VINF_SUCCESS;
201 mData.mStatus = GuestSessionStatus_Undefined;
202 mData.mNumObjects = 0;
203
204 HRESULT hr;
205
206 int rc = queryInfo();
207 if (RT_SUCCESS(rc))
208 {
209 hr = unconst(mEventSource).createObject();
210 if (FAILED(hr))
211 rc = VERR_NO_MEMORY;
212 else
213 {
214 hr = mEventSource->init(static_cast<IGuestSession*>(this));
215 if (FAILED(hr))
216 rc = VERR_COM_UNEXPECTED;
217 }
218 }
219
220 if (RT_SUCCESS(rc))
221 {
222 try
223 {
224 GuestSessionListener *pListener = new GuestSessionListener();
225 ComObjPtr<GuestSessionListenerImpl> thisListener;
226 hr = thisListener.createObject();
227 if (SUCCEEDED(hr))
228 hr = thisListener->init(pListener, this);
229
230 if (SUCCEEDED(hr))
231 {
232 com::SafeArray <VBoxEventType_T> eventTypes;
233 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
234 hr = mEventSource->RegisterListener(thisListener,
235 ComSafeArrayAsInParam(eventTypes),
236 TRUE /* Active listener */);
237 if (SUCCEEDED(hr))
238 {
239 mLocalListener = thisListener;
240
241 rc = RTCritSectInit(&mWaitEventCritSect);
242 AssertRC(rc);
243 }
244 else
245 rc = VERR_COM_UNEXPECTED;
246 }
247 else
248 rc = VERR_COM_UNEXPECTED;
249 }
250 catch(std::bad_alloc &)
251 {
252 rc = VERR_NO_MEMORY;
253 }
254 }
255
256 if (RT_SUCCESS(rc))
257 {
258 /* Confirm a successful initialization when it's the case. */
259 autoInitSpan.setSucceeded();
260 }
261 else
262 autoInitSpan.setFailed();
263
264 LogFlowThisFunc(("mName=%s, mID=%RU32, mIsInternal=%RTbool, rc=%Rrc\n",
265 mData.mSession.mName.c_str(), mData.mSession.mID, mData.mSession.mIsInternal, rc));
266 return rc;
267#endif /* VBOX_WITH_GUEST_CONTROL */
268}
269
270/**
271 * Uninitializes the instance.
272 * Called from FinalRelease().
273 */
274void GuestSession::uninit(void)
275{
276 LogFlowThisFuncEnter();
277
278 /* Enclose the state transition Ready->InUninit->NotReady. */
279 AutoUninitSpan autoUninitSpan(this);
280 if (autoUninitSpan.uninitDone())
281 return;
282
283 int rc = VINF_SUCCESS;
284
285#ifdef VBOX_WITH_GUEST_CONTROL
286 LogFlowThisFunc(("Closing directories (%RU64 total)\n",
287 mData.mDirectories.size()));
288 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
289 itDirs != mData.mDirectories.end(); ++itDirs)
290 {
291 (*itDirs)->Release();
292 }
293 mData.mDirectories.clear();
294
295 LogFlowThisFunc(("Closing files (%RU64 total)\n",
296 mData.mFiles.size()));
297 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
298 itFiles != mData.mFiles.end(); ++itFiles)
299 {
300 itFiles->second->Release();
301 }
302 mData.mFiles.clear();
303
304 LogFlowThisFunc(("Closing processes (%RU64 total)\n",
305 mData.mProcesses.size()));
306 for (SessionProcesses::iterator itProcs = mData.mProcesses.begin();
307 itProcs != mData.mProcesses.end(); ++itProcs)
308 {
309 itProcs->second->Release();
310 }
311 mData.mProcesses.clear();
312
313 LogFlowThisFunc(("mNumObjects=%RU32\n", mData.mNumObjects));
314
315 baseUninit();
316
317 mEventSource->UnregisterListener(mLocalListener);
318 unconst(mEventSource).setNull();
319
320#endif /* VBOX_WITH_GUEST_CONTROL */
321 LogFlowFuncLeaveRC(rc);
322}
323
324// implementation of public getters/setters for attributes
325/////////////////////////////////////////////////////////////////////////////
326
327STDMETHODIMP GuestSession::COMGETTER(User)(BSTR *aUser)
328{
329#ifndef VBOX_WITH_GUEST_CONTROL
330 ReturnComNotImplemented();
331#else
332 LogFlowThisFuncEnter();
333
334 CheckComArgOutPointerValid(aUser);
335
336 AutoCaller autoCaller(this);
337 if (FAILED(autoCaller.rc())) return autoCaller.rc();
338
339 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
340
341 mData.mCredentials.mUser.cloneTo(aUser);
342
343 LogFlowThisFuncLeave();
344 return S_OK;
345#endif /* VBOX_WITH_GUEST_CONTROL */
346}
347
348STDMETHODIMP GuestSession::COMGETTER(Domain)(BSTR *aDomain)
349{
350#ifndef VBOX_WITH_GUEST_CONTROL
351 ReturnComNotImplemented();
352#else
353 LogFlowThisFuncEnter();
354
355 CheckComArgOutPointerValid(aDomain);
356
357 AutoCaller autoCaller(this);
358 if (FAILED(autoCaller.rc())) return autoCaller.rc();
359
360 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
361
362 mData.mCredentials.mDomain.cloneTo(aDomain);
363
364 LogFlowThisFuncLeave();
365 return S_OK;
366#endif /* VBOX_WITH_GUEST_CONTROL */
367}
368
369STDMETHODIMP GuestSession::COMGETTER(Name)(BSTR *aName)
370{
371#ifndef VBOX_WITH_GUEST_CONTROL
372 ReturnComNotImplemented();
373#else
374 LogFlowThisFuncEnter();
375
376 CheckComArgOutPointerValid(aName);
377
378 AutoCaller autoCaller(this);
379 if (FAILED(autoCaller.rc())) return autoCaller.rc();
380
381 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
382
383 mData.mSession.mName.cloneTo(aName);
384
385 LogFlowThisFuncLeave();
386 return S_OK;
387#endif /* VBOX_WITH_GUEST_CONTROL */
388}
389
390STDMETHODIMP GuestSession::COMGETTER(Id)(ULONG *aId)
391{
392#ifndef VBOX_WITH_GUEST_CONTROL
393 ReturnComNotImplemented();
394#else
395 LogFlowThisFuncEnter();
396
397 CheckComArgOutPointerValid(aId);
398
399 AutoCaller autoCaller(this);
400 if (FAILED(autoCaller.rc())) return autoCaller.rc();
401
402 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
403
404 *aId = mData.mSession.mID;
405
406 LogFlowThisFuncLeave();
407 return S_OK;
408#endif /* VBOX_WITH_GUEST_CONTROL */
409}
410
411STDMETHODIMP GuestSession::COMGETTER(Status)(GuestSessionStatus_T *aStatus)
412{
413#ifndef VBOX_WITH_GUEST_CONTROL
414 ReturnComNotImplemented();
415#else
416 LogFlowThisFuncEnter();
417
418 CheckComArgOutPointerValid(aStatus);
419
420 AutoCaller autoCaller(this);
421 if (FAILED(autoCaller.rc())) return autoCaller.rc();
422
423 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
424
425 *aStatus = mData.mStatus;
426
427 LogFlowThisFuncLeave();
428 return S_OK;
429#endif /* VBOX_WITH_GUEST_CONTROL */
430}
431
432STDMETHODIMP GuestSession::COMGETTER(Timeout)(ULONG *aTimeout)
433{
434#ifndef VBOX_WITH_GUEST_CONTROL
435 ReturnComNotImplemented();
436#else
437 LogFlowThisFuncEnter();
438
439 CheckComArgOutPointerValid(aTimeout);
440
441 AutoCaller autoCaller(this);
442 if (FAILED(autoCaller.rc())) return autoCaller.rc();
443
444 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
445
446 *aTimeout = mData.mTimeout;
447
448 LogFlowThisFuncLeave();
449 return S_OK;
450#endif /* VBOX_WITH_GUEST_CONTROL */
451}
452
453STDMETHODIMP GuestSession::COMSETTER(Timeout)(ULONG aTimeout)
454{
455#ifndef VBOX_WITH_GUEST_CONTROL
456 ReturnComNotImplemented();
457#else
458 LogFlowThisFuncEnter();
459
460 AutoCaller autoCaller(this);
461 if (FAILED(autoCaller.rc())) return autoCaller.rc();
462
463 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
464
465 mData.mTimeout = aTimeout;
466
467 LogFlowThisFuncLeave();
468 return S_OK;
469#endif /* VBOX_WITH_GUEST_CONTROL */
470}
471
472STDMETHODIMP GuestSession::COMGETTER(ProtocolVersion)(ULONG *aVersion)
473{
474#ifndef VBOX_WITH_GUEST_CONTROL
475 ReturnComNotImplemented();
476#else
477 LogFlowThisFuncEnter();
478
479 CheckComArgOutPointerValid(aVersion);
480
481 AutoCaller autoCaller(this);
482 if (FAILED(autoCaller.rc())) return autoCaller.rc();
483
484 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
485
486 *aVersion = mData.mProtocolVersion;
487
488 LogFlowThisFuncLeave();
489 return S_OK;
490#endif /* VBOX_WITH_GUEST_CONTROL */
491}
492
493STDMETHODIMP GuestSession::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
494{
495#ifndef VBOX_WITH_GUEST_CONTROL
496 ReturnComNotImplemented();
497#else
498 LogFlowThisFuncEnter();
499
500 CheckComArgOutSafeArrayPointerValid(aEnvironment);
501
502 AutoCaller autoCaller(this);
503 if (FAILED(autoCaller.rc())) return autoCaller.rc();
504
505 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
506
507 size_t cEnvVars = mData.mEnvironment.Size();
508 LogFlowThisFunc(("[%s]: cEnvVars=%RU32\n",
509 mData.mSession.mName.c_str(), cEnvVars));
510 com::SafeArray<BSTR> environment(cEnvVars);
511
512 for (size_t i = 0; i < cEnvVars; i++)
513 {
514 Bstr strEnv(mData.mEnvironment.Get(i));
515 strEnv.cloneTo(&environment[i]);
516 }
517 environment.detachTo(ComSafeArrayOutArg(aEnvironment));
518
519 LogFlowThisFuncLeave();
520 return S_OK;
521#endif /* VBOX_WITH_GUEST_CONTROL */
522}
523
524STDMETHODIMP GuestSession::COMSETTER(Environment)(ComSafeArrayIn(IN_BSTR, aValues))
525{
526#ifndef VBOX_WITH_GUEST_CONTROL
527 ReturnComNotImplemented();
528#else
529 LogFlowThisFuncEnter();
530
531 AutoCaller autoCaller(this);
532 if (FAILED(autoCaller.rc())) return autoCaller.rc();
533
534 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
535
536 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aValues));
537
538 int rc = VINF_SUCCESS;
539 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
540 {
541 Utf8Str strEnv(environment[i]);
542 if (!strEnv.isEmpty()) /* Silently skip empty entries. */
543 rc = mData.mEnvironment.Set(strEnv);
544 }
545
546 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
547 LogFlowFuncLeaveRC(hr);
548 return hr;
549#endif /* VBOX_WITH_GUEST_CONTROL */
550}
551
552STDMETHODIMP GuestSession::COMGETTER(Processes)(ComSafeArrayOut(IGuestProcess *, aProcesses))
553{
554#ifndef VBOX_WITH_GUEST_CONTROL
555 ReturnComNotImplemented();
556#else
557 LogFlowThisFuncEnter();
558
559 CheckComArgOutSafeArrayPointerValid(aProcesses);
560
561 AutoCaller autoCaller(this);
562 if (FAILED(autoCaller.rc())) return autoCaller.rc();
563
564 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
565
566 SafeIfaceArray<IGuestProcess> collection(mData.mProcesses);
567 collection.detachTo(ComSafeArrayOutArg(aProcesses));
568
569 LogFlowFunc(("mProcesses=%zu\n", collection.size()));
570 return S_OK;
571#endif /* VBOX_WITH_GUEST_CONTROL */
572}
573
574STDMETHODIMP GuestSession::COMGETTER(Directories)(ComSafeArrayOut(IGuestDirectory *, aDirectories))
575{
576#ifndef VBOX_WITH_GUEST_CONTROL
577 ReturnComNotImplemented();
578#else
579 LogFlowThisFuncEnter();
580
581 CheckComArgOutSafeArrayPointerValid(aDirectories);
582
583 AutoCaller autoCaller(this);
584 if (FAILED(autoCaller.rc())) return autoCaller.rc();
585
586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
587
588 SafeIfaceArray<IGuestDirectory> collection(mData.mDirectories);
589 collection.detachTo(ComSafeArrayOutArg(aDirectories));
590
591 LogFlowFunc(("mDirectories=%zu\n", collection.size()));
592 return S_OK;
593#endif /* VBOX_WITH_GUEST_CONTROL */
594}
595
596STDMETHODIMP GuestSession::COMGETTER(Files)(ComSafeArrayOut(IGuestFile *, aFiles))
597{
598#ifndef VBOX_WITH_GUEST_CONTROL
599 ReturnComNotImplemented();
600#else
601 LogFlowThisFuncEnter();
602
603 CheckComArgOutSafeArrayPointerValid(aFiles);
604
605 AutoCaller autoCaller(this);
606 if (FAILED(autoCaller.rc())) return autoCaller.rc();
607
608 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
609
610 SafeIfaceArray<IGuestFile> collection(mData.mFiles);
611 collection.detachTo(ComSafeArrayOutArg(aFiles));
612
613 LogFlowFunc(("mFiles=%zu\n", collection.size()));
614 return S_OK;
615#endif /* VBOX_WITH_GUEST_CONTROL */
616}
617
618STDMETHODIMP GuestSession::COMGETTER(EventSource)(IEventSource ** aEventSource)
619{
620#ifndef VBOX_WITH_GUEST_CONTROL
621 ReturnComNotImplemented();
622#else
623 LogFlowThisFuncEnter();
624
625 CheckComArgOutPointerValid(aEventSource);
626
627 AutoCaller autoCaller(this);
628 if (FAILED(autoCaller.rc())) return autoCaller.rc();
629
630 // no need to lock - lifetime constant
631 mEventSource.queryInterfaceTo(aEventSource);
632
633 LogFlowThisFuncLeave();
634 return S_OK;
635#endif /* VBOX_WITH_GUEST_CONTROL */
636}
637
638// private methods
639///////////////////////////////////////////////////////////////////////////////
640
641int GuestSession::closeSession(uint32_t uFlags, uint32_t uTimeoutMS, int *pGuestRc)
642{
643 LogFlowThisFunc(("uFlags=%x, uTimeoutMS=%RU32\n", uFlags, uTimeoutMS));
644
645 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
646
647 /* Guest Additions < 4.3 don't support closing dedicated
648 guest sessions, skip. */
649 if (mData.mProtocolVersion < 2)
650 {
651 LogFlowThisFunc(("Installed Guest Additions don't support closing dedicated sessions, skipping\n"));
652 return VINF_SUCCESS;
653 }
654
655 /** @todo uFlags validation. */
656
657 if (mData.mStatus != GuestSessionStatus_Started)
658 return VINF_SUCCESS;
659
660 int vrc;
661
662 GuestWaitEvent *pEvent = NULL;
663 std::list < VBoxEventType_T > eventTypes;
664 try
665 {
666 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
667
668 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
669 eventTypes, &pEvent);
670 }
671 catch (std::bad_alloc)
672 {
673 vrc = VERR_NO_MEMORY;
674 }
675
676 if (RT_FAILURE(vrc))
677 return vrc;
678
679 LogFlowThisFunc(("Sending closing request to guest session ID=%RU32, uFlags=%x\n",
680 mData.mSession.mID, uFlags));
681
682 VBOXHGCMSVCPARM paParms[4];
683 int i = 0;
684 paParms[i++].setUInt32(pEvent->ContextID());
685 paParms[i++].setUInt32(uFlags);
686
687 alock.release(); /* Drop the write lock before waiting. */
688
689 vrc = sendCommand(HOST_SESSION_CLOSE, i, paParms);
690 if (RT_SUCCESS(vrc))
691 vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Terminate, uTimeoutMS,
692 NULL /* Session status */, pGuestRc);
693
694 unregisterWaitEvent(pEvent);
695
696 LogFlowFuncLeaveRC(vrc);
697 return vrc;
698}
699
700int GuestSession::directoryRemoveFromList(GuestDirectory *pDirectory)
701{
702 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
703
704 for (SessionDirectories::iterator itDirs = mData.mDirectories.begin();
705 itDirs != mData.mDirectories.end(); ++itDirs)
706 {
707 if (pDirectory == (*itDirs))
708 {
709 Bstr strName;
710 HRESULT hr = (*itDirs)->COMGETTER(DirectoryName)(strName.asOutParam());
711 ComAssertComRC(hr);
712
713 Assert(mData.mDirectories.size());
714 LogFlowFunc(("Removing directory \"%s\" (Session: %RU32) (now total %ld directories)\n",
715 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mDirectories.size() - 1));
716
717 mData.mDirectories.erase(itDirs);
718 return VINF_SUCCESS;
719 }
720 }
721
722 return VERR_NOT_FOUND;
723}
724
725int GuestSession::directoryCreateInternal(const Utf8Str &strPath, uint32_t uMode, uint32_t uFlags, int *pGuestRc)
726{
727 /* pGuestRc is optional. */
728
729 LogFlowThisFunc(("strPath=%s, uMode=%x, uFlags=%x\n",
730 strPath.c_str(), uMode, uFlags));
731
732 GuestProcessStartupInfo procInfo;
733 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
734 procInfo.mFlags = ProcessCreateFlag_Hidden;
735
736 int vrc = VINF_SUCCESS;
737
738 /* Construct arguments. */
739 if (uFlags & DirectoryCreateFlag_Parents)
740 procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
741 if (uMode)
742 {
743 procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
744
745 char szMode[16];
746 if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
747 {
748 procInfo.mArguments.push_back(Utf8Str(szMode));
749 }
750 else
751 vrc = VERR_BUFFER_OVERFLOW;
752 }
753 procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
754
755 if (RT_SUCCESS(vrc))
756 {
757 int guestRc;
758 GuestProcessTool procTool;
759 vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
760 if (RT_SUCCESS(vrc))
761 {
762 if (RT_SUCCESS(guestRc))
763 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
764 }
765
766 if (RT_SUCCESS(vrc))
767 {
768 if (RT_SUCCESS(guestRc))
769 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
770 }
771
772 if ( vrc == VERR_GSTCTL_GUEST_ERROR
773 && pGuestRc)
774 {
775 *pGuestRc = guestRc;
776 }
777 }
778
779 LogFlowFuncLeaveRC(vrc);
780 return vrc;
781}
782
783int GuestSession::directoryQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
784{
785 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
786
787 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
788 if (RT_SUCCESS(vrc))
789 {
790 vrc = objData.mType == FsObjType_Directory
791 ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
792 }
793
794 LogFlowFuncLeaveRC(vrc);
795 return vrc;
796}
797
798int GuestSession::objectCreateTempInternal(const Utf8Str &strTemplate, const Utf8Str &strPath,
799 bool fDirectory, const Utf8Str &strName, int *pGuestRc)
800{
801 GuestProcessStartupInfo procInfo;
802 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
803 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
804 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
805 if (fDirectory)
806 procInfo.mArguments.push_back(Utf8Str("-d"));
807 if (strPath.length()) /* Otherwise use /tmp or equivalent. */
808 {
809 procInfo.mArguments.push_back(Utf8Str("-t"));
810 procInfo.mArguments.push_back(strPath);
811 }
812 procInfo.mArguments.push_back(strTemplate);
813
814 GuestProcessTool procTool; int guestRc;
815 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
816 if (RT_SUCCESS(vrc))
817 {
818 if (RT_SUCCESS(guestRc))
819 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
820 }
821
822 if (RT_SUCCESS(vrc))
823 {
824 if (RT_SUCCESS(guestRc))
825 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
826 }
827
828 if ( vrc == VERR_GSTCTL_GUEST_ERROR
829 && pGuestRc)
830 {
831 *pGuestRc = guestRc;
832 }
833
834 LogFlowFuncLeaveRC(vrc);
835 return vrc;
836}
837
838int GuestSession::directoryOpenInternal(const Utf8Str &strPath, const Utf8Str &strFilter,
839 uint32_t uFlags, ComObjPtr<GuestDirectory> &pDirectory)
840{
841 LogFlowThisFunc(("strPath=%s, strPath=%s, uFlags=%x\n",
842 strPath.c_str(), strFilter.c_str(), uFlags));
843
844 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
845
846 /* Create the directory object. */
847 HRESULT hr = pDirectory.createObject();
848 if (FAILED(hr))
849 return VERR_COM_UNEXPECTED;
850
851 int vrc = pDirectory->init(this /* Parent */,
852 strPath, strFilter, uFlags);
853 if (RT_FAILURE(vrc))
854 return vrc;
855
856 /* Add the created directory to our vector. */
857 mData.mDirectories.push_back(pDirectory);
858
859 LogFlowFunc(("Added new directory \"%s\" (Session: %RU32)\n",
860 strPath.c_str(), mData.mSession.mID));
861
862 LogFlowFuncLeaveRC(vrc);
863 return vrc;
864}
865
866int GuestSession::dispatchToFile(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
867{
868 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
869
870 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
871 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
872
873 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
874
875 uint32_t uFileID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
876#ifdef DEBUG
877 LogFlowFunc(("uFileID=%RU32 (%RU32 total)\n",
878 uFileID, mData.mFiles.size()));
879#endif
880 int rc;
881 SessionFiles::const_iterator itFile
882 = mData.mFiles.find(uFileID);
883 if (itFile != mData.mFiles.end())
884 {
885 ComObjPtr<GuestFile> pFile(itFile->second);
886 Assert(!pFile.isNull());
887
888 alock.release();
889
890 rc = pFile->callbackDispatcher(pCtxCb, pSvcCb);
891 }
892 else
893 rc = VERR_NOT_FOUND;
894
895 LogFlowFuncLeaveRC(rc);
896 return rc;
897}
898
899int GuestSession::dispatchToProcess(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
900{
901 LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
902
903 AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
904 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
905
906 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
907
908 uint32_t uProcessID = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pCtxCb->uContextID);
909#ifdef DEBUG
910 LogFlowFunc(("uProcessID=%RU32 (%RU32 total)\n",
911 uProcessID, mData.mProcesses.size()));
912#endif
913 int rc;
914 SessionProcesses::const_iterator itProc
915 = mData.mProcesses.find(uProcessID);
916 if (itProc != mData.mProcesses.end())
917 {
918 ComObjPtr<GuestProcess> pProcess(itProc->second);
919 Assert(!pProcess.isNull());
920
921 /* Set protocol version so that pSvcCb can
922 * be interpreted right. */
923 pCtxCb->uProtocol = mData.mProtocolVersion;
924
925 alock.release();
926 rc = pProcess->callbackDispatcher(pCtxCb, pSvcCb);
927 }
928 else
929 rc = VERR_NOT_FOUND;
930
931 LogFlowFuncLeaveRC(rc);
932 return rc;
933}
934
935int GuestSession::dispatchToThis(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
936{
937 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
938 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
939
940 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
941
942#ifdef DEBUG
943 LogFlowThisFunc(("sessionID=%RU32, CID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
944 mData.mSession.mID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
945#endif
946
947 int rc = VINF_SUCCESS;
948 switch (pCbCtx->uFunction)
949 {
950 case GUEST_DISCONNECTED:
951 /** @todo Handle closing all guest objects. */
952 break;
953
954 case GUEST_SESSION_NOTIFY:
955 {
956 rc = onSessionStatusChange(pCbCtx, pSvcCb);
957 break;
958 }
959
960 default:
961 /* Silently skip unknown callbacks. */
962 rc = VERR_NOT_SUPPORTED;
963 break;
964 }
965
966 LogFlowFuncLeaveRC(rc);
967 return rc;
968}
969
970inline bool GuestSession::fileExists(uint32_t uFileID, ComObjPtr<GuestFile> *pFile)
971{
972 SessionFiles::const_iterator it = mData.mFiles.find(uFileID);
973 if (it != mData.mFiles.end())
974 {
975 if (pFile)
976 *pFile = it->second;
977 return true;
978 }
979 return false;
980}
981
982int GuestSession::fileRemoveFromList(GuestFile *pFile)
983{
984 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
985
986 for (SessionFiles::iterator itFiles = mData.mFiles.begin();
987 itFiles != mData.mFiles.end(); ++itFiles)
988 {
989 if (pFile == itFiles->second)
990 {
991 /* Make sure to consume the pointer before the one of thfe
992 * iterator gets released. */
993 ComObjPtr<GuestFile> pCurFile = pFile;
994
995 Bstr strName;
996 HRESULT hr = pCurFile->COMGETTER(FileName)(strName.asOutParam());
997 ComAssertComRC(hr);
998
999 Assert(mData.mNumObjects);
1000 LogFlowThisFunc(("Removing guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
1001 Utf8Str(strName).c_str(), mData.mSession.mID, mData.mFiles.size() - 1, mData.mNumObjects - 1));
1002
1003 itFiles->second->Release();
1004
1005 mData.mFiles.erase(itFiles);
1006 mData.mNumObjects--;
1007
1008 alock.release(); /* Release lock before firing off event. */
1009
1010 fireGuestFileRegisteredEvent(mEventSource, this, pCurFile,
1011 false /* Unregistered */);
1012 return VINF_SUCCESS;
1013 }
1014 }
1015
1016 return VERR_NOT_FOUND;
1017}
1018
1019int GuestSession::fileRemoveInternal(const Utf8Str &strPath, int *pGuestRc)
1020{
1021 GuestProcessStartupInfo procInfo;
1022 GuestProcessStream streamOut;
1023
1024 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_RM);
1025 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1026 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1027 procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
1028
1029 GuestProcessTool procTool; int guestRc;
1030 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
1031 if (RT_SUCCESS(vrc))
1032 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
1033
1034 if (RT_SUCCESS(vrc))
1035 {
1036 if (RT_SUCCESS(guestRc))
1037 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
1038 }
1039
1040 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1041 && pGuestRc)
1042 {
1043 *pGuestRc = guestRc;
1044 }
1045
1046 LogFlowFuncLeaveRC(vrc);
1047 return vrc;
1048}
1049
1050int GuestSession::fileOpenInternal(const GuestFileOpenInfo &openInfo, ComObjPtr<GuestFile> &pFile, int *pGuestRc)
1051{
1052 LogFlowThisFunc(("strPath=%s, strOpenMode=%s, strDisposition=%s, uCreationMode=%x, iOffset=%RI64\n",
1053 openInfo.mFileName.c_str(), openInfo.mOpenMode.c_str(), openInfo.mDisposition.c_str(),
1054 openInfo.mCreationMode, openInfo.mInitialOffset));
1055
1056 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1057
1058 int rc = VERR_MAX_PROCS_REACHED;
1059 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1060 return rc;
1061
1062 /* Create a new (host-based) file ID and assign it. */
1063 uint32_t uNewFileID = 0;
1064 ULONG uTries = 0;
1065
1066 for (;;)
1067 {
1068 /* Is the file ID already used? */
1069 if (!fileExists(uNewFileID, NULL /* pProgress */))
1070 {
1071 /* Callback with context ID was not found. This means
1072 * we can use this context ID for our new callback we want
1073 * to add below. */
1074 rc = VINF_SUCCESS;
1075 break;
1076 }
1077 uNewFileID++;
1078 if (uNewFileID == VBOX_GUESTCTRL_MAX_OBJECTS)
1079 uNewFileID = 0;
1080
1081 if (++uTries == UINT32_MAX)
1082 break; /* Don't try too hard. */
1083 }
1084
1085 if (RT_FAILURE(rc))
1086 return rc;
1087
1088 /* Create the directory object. */
1089 HRESULT hr = pFile.createObject();
1090 if (FAILED(hr))
1091 return VERR_COM_UNEXPECTED;
1092
1093 Console *pConsole = mParent->getConsole();
1094 AssertPtr(pConsole);
1095
1096 rc = pFile->init(pConsole, this /* GuestSession */,
1097 uNewFileID, openInfo);
1098 if (RT_FAILURE(rc))
1099 return rc;
1100
1101 int guestRc;
1102 rc = pFile->openFile(&guestRc);
1103 if (RT_SUCCESS(rc))
1104 {
1105 /* Add the created file to our vector. */
1106 mData.mFiles[uNewFileID] = pFile;
1107 mData.mNumObjects++;
1108 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1109
1110 LogFlowFunc(("Added new guest file \"%s\" (Session: %RU32) (now total %ld files, %ld objects)\n",
1111 openInfo.mFileName.c_str(), mData.mSession.mID, mData.mFiles.size(), mData.mNumObjects));
1112
1113 alock.release(); /* Release lock before firing off event. */
1114
1115 fireGuestFileRegisteredEvent(mEventSource, this, pFile,
1116 true /* Registered */);
1117 }
1118
1119 if (pGuestRc)
1120 *pGuestRc = guestRc;
1121
1122 LogFlowFuncLeaveRC(rc);
1123 return rc;
1124}
1125
1126int GuestSession::fileQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
1127{
1128 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1129
1130 int vrc = fsQueryInfoInternal(strPath, objData, pGuestRc);
1131 if (RT_SUCCESS(vrc))
1132 {
1133 vrc = objData.mType == FsObjType_File
1134 ? VINF_SUCCESS : VERR_NOT_A_FILE;
1135 }
1136
1137 LogFlowFuncLeaveRC(vrc);
1138 return vrc;
1139}
1140
1141int GuestSession::fileQuerySizeInternal(const Utf8Str &strPath, int64_t *pllSize, int *pGuestRc)
1142{
1143 AssertPtrReturn(pllSize, VERR_INVALID_POINTER);
1144
1145 GuestFsObjData objData;
1146 int vrc = fileQueryInfoInternal(strPath, objData, pGuestRc);
1147 if (RT_SUCCESS(vrc))
1148 *pllSize = objData.mObjectSize;
1149
1150 return vrc;
1151}
1152
1153int GuestSession::fsQueryInfoInternal(const Utf8Str &strPath, GuestFsObjData &objData, int *pGuestRc)
1154{
1155 LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
1156
1157 /** @todo Merge this with IGuestFile::queryInfo(). */
1158 GuestProcessStartupInfo procInfo;
1159 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_STAT);
1160 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
1161
1162 /* Construct arguments. */
1163 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
1164 procInfo.mArguments.push_back(strPath);
1165
1166 GuestProcessTool procTool; int guestRc;
1167 int vrc = procTool.Init(this, procInfo, false /* Async */, &guestRc);
1168 if (RT_SUCCESS(vrc))
1169 vrc = procTool.Wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
1170 if (RT_SUCCESS(vrc))
1171 {
1172 guestRc = procTool.TerminatedOk(NULL /* Exit code */);
1173 if (RT_SUCCESS(guestRc))
1174 {
1175 GuestProcessStreamBlock curBlock;
1176 vrc = procTool.GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, curBlock);
1177 /** @todo Check for more / validate blocks! */
1178 if (RT_SUCCESS(vrc))
1179 vrc = objData.FromStat(curBlock);
1180 }
1181 }
1182
1183 if ( vrc == VERR_GSTCTL_GUEST_ERROR
1184 && pGuestRc)
1185 {
1186 *pGuestRc = guestRc;
1187 }
1188
1189 LogFlowFuncLeaveRC(vrc);
1190 return vrc;
1191}
1192
1193const GuestCredentials& GuestSession::getCredentials(void)
1194{
1195 return mData.mCredentials;
1196}
1197
1198const GuestEnvironment& GuestSession::getEnvironment(void)
1199{
1200 return mData.mEnvironment;
1201}
1202
1203Utf8Str GuestSession::getName(void)
1204{
1205 return mData.mSession.mName;
1206}
1207
1208/* static */
1209Utf8Str GuestSession::guestErrorToString(int guestRc)
1210{
1211 Utf8Str strError;
1212
1213 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
1214 switch (guestRc)
1215 {
1216 case VERR_INVALID_VM_HANDLE:
1217 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
1218 break;
1219
1220 case VERR_HGCM_SERVICE_NOT_FOUND:
1221 strError += Utf8StrFmt(tr("The guest execution service is not available"));
1222 break;
1223
1224 case VERR_AUTHENTICATION_FAILURE:
1225 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
1226 break;
1227
1228 case VERR_TIMEOUT:
1229 strError += Utf8StrFmt(tr("The guest did not respond within time"));
1230 break;
1231
1232 case VERR_CANCELLED:
1233 strError += Utf8StrFmt(tr("The session operation was canceled"));
1234 break;
1235
1236 case VERR_PERMISSION_DENIED:
1237 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
1238 break;
1239
1240 case VERR_MAX_PROCS_REACHED:
1241 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
1242 break;
1243
1244 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
1245 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
1246 break;
1247
1248 case VERR_NOT_FOUND:
1249 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
1250 break;
1251
1252 default:
1253 strError += Utf8StrFmt("%Rrc", guestRc);
1254 break;
1255 }
1256
1257 return strError;
1258}
1259
1260/**
1261 * Checks if this session is ready state where it can handle
1262 * all session-bound actions (like guest processes, guest files).
1263 * Only used by official API methods. Will set an external
1264 * error when not ready.
1265 */
1266HRESULT GuestSession::isReadyExternal(void)
1267{
1268 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1269
1270 /** @todo Be a bit more informative. */
1271 if (mData.mStatus != GuestSessionStatus_Started)
1272 return setError(E_UNEXPECTED, tr("Session is not in started state"));
1273
1274 return S_OK;
1275}
1276
1277/** No locking! */
1278int GuestSession::onSessionStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
1279{
1280 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
1281 /* pCallback is optional. */
1282 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
1283
1284 if (pSvcCbData->mParms < 3)
1285 return VERR_INVALID_PARAMETER;
1286
1287 CALLBACKDATA_SESSION_NOTIFY dataCb;
1288 /* pSvcCb->mpaParms[0] always contains the context ID. */
1289 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uType);
1290 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uResult);
1291
1292 LogFlowThisFunc(("ID=%RU32, uType=%RU32, guestRc=%Rrc\n",
1293 mData.mSession.mID, dataCb.uType, dataCb.uResult));
1294
1295 int vrc = VINF_SUCCESS;
1296
1297 GuestSessionStatus_T sessionStatus = GuestSessionStatus_Undefined;
1298
1299 int guestRc = dataCb.uResult; /** @todo uint32_t vs. int. */
1300 switch (dataCb.uType)
1301 {
1302 case GUEST_SESSION_NOTIFYTYPE_ERROR:
1303 sessionStatus = GuestSessionStatus_Error;
1304 break;
1305
1306 case GUEST_SESSION_NOTIFYTYPE_STARTED:
1307 sessionStatus = GuestSessionStatus_Started;
1308 break;
1309
1310 case GUEST_SESSION_NOTIFYTYPE_TEN:
1311 case GUEST_SESSION_NOTIFYTYPE_TES:
1312 case GUEST_SESSION_NOTIFYTYPE_TEA:
1313 sessionStatus = GuestSessionStatus_Terminated;
1314 break;
1315
1316 case GUEST_SESSION_NOTIFYTYPE_TOK:
1317 sessionStatus = GuestSessionStatus_TimedOutKilled;
1318 break;
1319
1320 case GUEST_SESSION_NOTIFYTYPE_TOA:
1321 sessionStatus = GuestSessionStatus_TimedOutAbnormally;
1322 break;
1323
1324 case GUEST_SESSION_NOTIFYTYPE_DWN:
1325 sessionStatus = GuestSessionStatus_Down;
1326 break;
1327
1328 case GUEST_SESSION_NOTIFYTYPE_UNDEFINED:
1329 default:
1330 vrc = VERR_NOT_SUPPORTED;
1331 break;
1332 }
1333
1334 if (RT_SUCCESS(vrc))
1335 {
1336 if (RT_FAILURE(guestRc))
1337 sessionStatus = GuestSessionStatus_Error;
1338 }
1339
1340 /* Set the session status. */
1341 if (RT_SUCCESS(vrc))
1342 vrc = setSessionStatus(sessionStatus, guestRc);
1343
1344 LogFlowThisFunc(("ID=%RU32, guestRc=%Rrc\n", mData.mSession.mID, guestRc));
1345
1346 LogFlowFuncLeaveRC(vrc);
1347 return vrc;
1348}
1349
1350int GuestSession::startSessionInternal(int *pGuestRc)
1351{
1352 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1353
1354 LogFlowThisFunc(("mID=%RU32, mName=%s, uProtocolVersion=%RU32, openFlags=%x, openTimeoutMS=%RU32\n",
1355 mData.mSession.mID, mData.mSession.mName.c_str(), mData.mProtocolVersion,
1356 mData.mSession.mOpenFlags, mData.mSession.mOpenTimeoutMS));
1357
1358 /* Guest Additions < 4.3 don't support opening dedicated
1359 guest sessions. Simply return success here. */
1360 if (mData.mProtocolVersion < 2)
1361 {
1362 mData.mStatus = GuestSessionStatus_Started;
1363
1364 LogFlowThisFunc(("Installed Guest Additions don't support opening dedicated sessions, skipping\n"));
1365 return VINF_SUCCESS;
1366 }
1367
1368 if (mData.mStatus != GuestSessionStatus_Undefined)
1369 return VINF_SUCCESS;
1370
1371 /** @todo mData.mSession.uFlags validation. */
1372
1373 /* Set current session status. */
1374 mData.mStatus = GuestSessionStatus_Starting;
1375
1376 int vrc;
1377
1378 GuestWaitEvent *pEvent = NULL;
1379 std::list < VBoxEventType_T > eventTypes;
1380 try
1381 {
1382 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
1383
1384 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1385 eventTypes, &pEvent);
1386 }
1387 catch (std::bad_alloc)
1388 {
1389 vrc = VERR_NO_MEMORY;
1390 }
1391
1392 if (RT_FAILURE(vrc))
1393 return vrc;
1394
1395 VBOXHGCMSVCPARM paParms[8];
1396
1397 int i = 0;
1398 paParms[i++].setUInt32(pEvent->ContextID());
1399 paParms[i++].setUInt32(mData.mProtocolVersion);
1400 paParms[i++].setPointer((void*)mData.mCredentials.mUser.c_str(),
1401 (ULONG)mData.mCredentials.mUser.length() + 1);
1402 paParms[i++].setPointer((void*)mData.mCredentials.mPassword.c_str(),
1403 (ULONG)mData.mCredentials.mPassword.length() + 1);
1404 paParms[i++].setPointer((void*)mData.mCredentials.mDomain.c_str(),
1405 (ULONG)mData.mCredentials.mDomain.length() + 1);
1406 paParms[i++].setUInt32(mData.mSession.mOpenFlags);
1407
1408 alock.release(); /* Drop write lock before sending. */
1409
1410 vrc = sendCommand(HOST_SESSION_CREATE, i, paParms);
1411 if (RT_SUCCESS(vrc))
1412 vrc = waitForStatusChange(pEvent, GuestSessionWaitForFlag_Start,
1413 30 * 1000 /* 30s timeout */,
1414 NULL /* Session status */, pGuestRc);
1415
1416 unregisterWaitEvent(pEvent);
1417
1418 LogFlowFuncLeaveRC(vrc);
1419 return vrc;
1420}
1421
1422int GuestSession::startSessionAsync(void)
1423{
1424 LogFlowThisFuncEnter();
1425
1426 int vrc;
1427
1428 try
1429 {
1430 /* Asynchronously open the session on the guest by kicking off a
1431 * worker thread. */
1432 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(new GuestSessionTaskInternalOpen(this));
1433 AssertReturn(pTask->isOk(), pTask->rc());
1434
1435 vrc = RTThreadCreate(NULL, GuestSession::startSessionThread,
1436 (void *)pTask.get(), 0,
1437 RTTHREADTYPE_MAIN_WORKER, 0,
1438 "gctlSesStart");
1439 if (RT_SUCCESS(vrc))
1440 {
1441 /* pTask is now owned by openSessionThread(), so release it. */
1442 pTask.release();
1443 }
1444 }
1445 catch(std::bad_alloc &)
1446 {
1447 vrc = VERR_NO_MEMORY;
1448 }
1449
1450 LogFlowFuncLeaveRC(vrc);
1451 return vrc;
1452}
1453
1454/* static */
1455DECLCALLBACK(int) GuestSession::startSessionThread(RTTHREAD Thread, void *pvUser)
1456{
1457 LogFlowFunc(("pvUser=%p\n", pvUser));
1458
1459 std::auto_ptr<GuestSessionTaskInternalOpen> pTask(static_cast<GuestSessionTaskInternalOpen*>(pvUser));
1460 AssertPtr(pTask.get());
1461
1462 const ComObjPtr<GuestSession> pSession(pTask->Session());
1463 Assert(!pSession.isNull());
1464
1465 AutoCaller autoCaller(pSession);
1466 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1467
1468 int vrc = pSession->startSessionInternal(NULL /* Guest rc, ignored */);
1469 /* Nothing to do here anymore. */
1470
1471 LogFlowFuncLeaveRC(vrc);
1472 return vrc;
1473}
1474
1475int GuestSession::processRemoveFromList(GuestProcess *pProcess)
1476{
1477 AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
1478
1479 LogFlowThisFunc(("pProcess=%p\n", pProcess));
1480
1481 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1482
1483 int rc = VERR_NOT_FOUND;
1484
1485 ULONG uPID;
1486 HRESULT hr = pProcess->COMGETTER(PID)(&uPID);
1487 ComAssertComRC(hr);
1488
1489 LogFlowFunc(("Closing process (PID=%RU32) ...\n", uPID));
1490
1491 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1492 while (itProcs != mData.mProcesses.end())
1493 {
1494 if (pProcess == itProcs->second)
1495 {
1496 /* Make sure to consume the pointer before the one of thfe
1497 * iterator gets released. */
1498 ComObjPtr<GuestProcess> pCurProcess = pProcess;
1499
1500 hr = pCurProcess->COMGETTER(PID)(&uPID);
1501 ComAssertComRC(hr);
1502
1503 Assert(mData.mNumObjects);
1504 LogFlowFunc(("Removing process ID=%RU32 (Session: %RU32), guest PID=%RU32 (now total %ld processes, %ld objects)\n",
1505 pProcess->getObjectID(), mData.mSession.mID, uPID, mData.mProcesses.size() - 1, mData.mNumObjects - 1));
1506
1507 pProcess->cancelWaitEvents();
1508 pProcess->Release();
1509
1510 mData.mProcesses.erase(itProcs);
1511 mData.mNumObjects--;
1512
1513 alock.release(); /* Release lock before firing off event. */
1514
1515 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pCurProcess,
1516 uPID, false /* Process unregistered */);
1517 rc = VINF_SUCCESS;
1518 break;
1519 }
1520
1521 itProcs++;
1522 }
1523
1524 LogFlowFuncLeaveRC(rc);
1525 return rc;
1526}
1527
1528/**
1529 * Creates but does *not* start the process yet. See GuestProcess::startProcess() or
1530 * GuestProcess::startProcessAsync() for that.
1531 *
1532 * @return IPRT status code.
1533 * @param procInfo
1534 * @param pProcess
1535 */
1536int GuestSession::processCreateExInteral(GuestProcessStartupInfo &procInfo, ComObjPtr<GuestProcess> &pProcess)
1537{
1538 LogFlowFunc(("mCmd=%s, mFlags=%x, mTimeoutMS=%RU32\n",
1539 procInfo.mCommand.c_str(), procInfo.mFlags, procInfo.mTimeoutMS));
1540#ifdef DEBUG
1541 if (procInfo.mArguments.size())
1542 {
1543 LogFlowFunc(("Arguments:"));
1544 ProcessArguments::const_iterator it = procInfo.mArguments.begin();
1545 while (it != procInfo.mArguments.end())
1546 {
1547 LogFlow((" %s", (*it).c_str()));
1548 it++;
1549 }
1550 LogFlow(("\n"));
1551 }
1552#endif
1553
1554 /* Validate flags. */
1555 if (procInfo.mFlags)
1556 {
1557 if ( !(procInfo.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
1558 && !(procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1559 && !(procInfo.mFlags & ProcessCreateFlag_Hidden)
1560 && !(procInfo.mFlags & ProcessCreateFlag_NoProfile)
1561 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1562 && !(procInfo.mFlags & ProcessCreateFlag_WaitForStdErr))
1563 {
1564 return VERR_INVALID_PARAMETER;
1565 }
1566 }
1567
1568 if ( (procInfo.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1569 && ( (procInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1570 || (procInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1571 )
1572 )
1573 {
1574 return VERR_INVALID_PARAMETER;
1575 }
1576
1577 /* Adjust timeout. If set to 0, we define
1578 * an infinite timeout. */
1579 if (procInfo.mTimeoutMS == 0)
1580 procInfo.mTimeoutMS = UINT32_MAX;
1581
1582 /** @tood Implement process priority + affinity. */
1583
1584 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1585
1586 int rc = VERR_MAX_PROCS_REACHED;
1587 if (mData.mNumObjects >= VBOX_GUESTCTRL_MAX_OBJECTS)
1588 return rc;
1589
1590 /* Create a new (host-based) process ID and assign it. */
1591 uint32_t uNewProcessID = 0;
1592 ULONG uTries = 0;
1593
1594 for (;;)
1595 {
1596 /* Is the context ID already used? */
1597 if (!processExists(uNewProcessID, NULL /* pProgress */))
1598 {
1599 /* Callback with context ID was not found. This means
1600 * we can use this context ID for our new callback we want
1601 * to add below. */
1602 rc = VINF_SUCCESS;
1603 break;
1604 }
1605 uNewProcessID++;
1606 if (uNewProcessID == VBOX_GUESTCTRL_MAX_OBJECTS)
1607 uNewProcessID = 0;
1608
1609 if (++uTries == VBOX_GUESTCTRL_MAX_OBJECTS)
1610 break; /* Don't try too hard. */
1611 }
1612
1613 if (RT_FAILURE(rc))
1614 return rc;
1615
1616 /* Create the process object. */
1617 HRESULT hr = pProcess.createObject();
1618 if (FAILED(hr))
1619 return VERR_COM_UNEXPECTED;
1620
1621 rc = pProcess->init(mParent->getConsole() /* Console */, this /* Session */,
1622 uNewProcessID, procInfo);
1623 if (RT_FAILURE(rc))
1624 return rc;
1625
1626 /* Add the created process to our map. */
1627 mData.mProcesses[uNewProcessID] = pProcess;
1628 mData.mNumObjects++;
1629 Assert(mData.mNumObjects <= VBOX_GUESTCTRL_MAX_OBJECTS);
1630
1631 fireGuestProcessRegisteredEvent(mEventSource, this /* Session */, pProcess,
1632 0 /* PID */, true /* Process registered */);
1633
1634 LogFlowFunc(("Added new process (Session: %RU32) with process ID=%RU32 (now total %ld processes, %ld objects)\n",
1635 mData.mSession.mID, uNewProcessID, mData.mProcesses.size(), mData.mNumObjects));
1636
1637 return rc;
1638}
1639
1640inline bool GuestSession::processExists(uint32_t uProcessID, ComObjPtr<GuestProcess> *pProcess)
1641{
1642 SessionProcesses::const_iterator it = mData.mProcesses.find(uProcessID);
1643 if (it != mData.mProcesses.end())
1644 {
1645 if (pProcess)
1646 *pProcess = it->second;
1647 return true;
1648 }
1649 return false;
1650}
1651
1652inline int GuestSession::processGetByPID(ULONG uPID, ComObjPtr<GuestProcess> *pProcess)
1653{
1654 AssertReturn(uPID, false);
1655 /* pProcess is optional. */
1656
1657 SessionProcesses::iterator itProcs = mData.mProcesses.begin();
1658 for (; itProcs != mData.mProcesses.end(); itProcs++)
1659 {
1660 ComObjPtr<GuestProcess> pCurProc = itProcs->second;
1661 AutoCaller procCaller(pCurProc);
1662 if (procCaller.rc())
1663 return VERR_COM_INVALID_OBJECT_STATE;
1664
1665 ULONG uCurPID;
1666 HRESULT hr = pCurProc->COMGETTER(PID)(&uCurPID);
1667 ComAssertComRC(hr);
1668
1669 if (uCurPID == uPID)
1670 {
1671 if (pProcess)
1672 *pProcess = pCurProc;
1673 return VINF_SUCCESS;
1674 }
1675 }
1676
1677 return VERR_NOT_FOUND;
1678}
1679
1680int GuestSession::sendCommand(uint32_t uFunction,
1681 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
1682{
1683 LogFlowThisFuncEnter();
1684
1685#ifndef VBOX_GUESTCTRL_TEST_CASE
1686 ComObjPtr<Console> pConsole = mParent->getConsole();
1687 Assert(!pConsole.isNull());
1688
1689 /* Forward the information to the VMM device. */
1690 VMMDev *pVMMDev = pConsole->getVMMDev();
1691 AssertPtr(pVMMDev);
1692
1693 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
1694 int vrc = pVMMDev->hgcmHostCall(HGCMSERVICE_NAME, uFunction, uParms, paParms);
1695 if (RT_FAILURE(vrc))
1696 {
1697 /** @todo What to do here? */
1698 }
1699#else
1700 /* Not needed within testcases. */
1701 int vrc = VINF_SUCCESS;
1702#endif
1703 LogFlowFuncLeaveRC(vrc);
1704 return vrc;
1705}
1706
1707/* static */
1708HRESULT GuestSession::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
1709{
1710 AssertPtr(pInterface);
1711 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
1712
1713 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestSession::guestErrorToString(guestRc).c_str());
1714}
1715
1716/* Does not do locking; caller is responsible for that! */
1717int GuestSession::setSessionStatus(GuestSessionStatus_T sessionStatus, int sessionRc)
1718{
1719 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, sessionRc=%Rrc\n",
1720 mData.mStatus, sessionStatus, sessionRc));
1721
1722 if (sessionStatus == GuestSessionStatus_Error)
1723 {
1724 AssertMsg(RT_FAILURE(sessionRc), ("Guest rc must be an error (%Rrc)\n", sessionRc));
1725 /* Do not allow overwriting an already set error. If this happens
1726 * this means we forgot some error checking/locking somewhere. */
1727 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
1728 }
1729 else
1730 AssertMsg(RT_SUCCESS(sessionRc), ("Guest rc must not be an error (%Rrc)\n", sessionRc));
1731
1732 if (mData.mStatus != sessionStatus)
1733 {
1734 mData.mStatus = sessionStatus;
1735 mData.mRC = sessionRc;
1736
1737 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
1738 HRESULT hr = errorInfo.createObject();
1739 ComAssertComRC(hr);
1740 int rc2 = errorInfo->initEx(VBOX_E_IPRT_ERROR, sessionRc,
1741 COM_IIDOF(IGuestSession), getComponentName(),
1742 guestErrorToString(sessionRc));
1743 AssertRC(rc2);
1744
1745 fireGuestSessionStateChangedEvent(mEventSource, this,
1746 mData.mSession.mID, sessionStatus, errorInfo);
1747 }
1748
1749 return VINF_SUCCESS;
1750}
1751
1752int GuestSession::signalWaiters(GuestSessionWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
1753{
1754 /*LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
1755 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));*/
1756
1757 /* Note: No write locking here -- already done in the caller. */
1758
1759 int vrc = VINF_SUCCESS;
1760 /*if (mData.mWaitEvent)
1761 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);*/
1762 LogFlowFuncLeaveRC(vrc);
1763 return vrc;
1764}
1765
1766int GuestSession::startTaskAsync(const Utf8Str &strTaskDesc,
1767 GuestSessionTask *pTask, ComObjPtr<Progress> &pProgress)
1768{
1769 LogFlowThisFunc(("strTaskDesc=%s, pTask=%p\n", strTaskDesc.c_str(), pTask));
1770
1771 AssertPtrReturn(pTask, VERR_INVALID_POINTER);
1772
1773 /* Create the progress object. */
1774 HRESULT hr = pProgress.createObject();
1775 if (FAILED(hr))
1776 return VERR_COM_UNEXPECTED;
1777
1778 hr = pProgress->init(static_cast<IGuestSession*>(this),
1779 Bstr(strTaskDesc).raw(),
1780 TRUE /* aCancelable */);
1781 if (FAILED(hr))
1782 return VERR_COM_UNEXPECTED;
1783
1784 /* Initialize our worker task. */
1785 std::auto_ptr<GuestSessionTask> task(pTask);
1786
1787 int rc = task->RunAsync(strTaskDesc, pProgress);
1788 if (RT_FAILURE(rc))
1789 return rc;
1790
1791 /* Don't destruct on success. */
1792 task.release();
1793
1794 LogFlowFuncLeaveRC(rc);
1795 return rc;
1796}
1797
1798/**
1799 * Queries/collects information prior to establishing a guest session.
1800 * This is necessary to know which guest control protocol version to use,
1801 * among other things (later).
1802 *
1803 * @return IPRT status code.
1804 */
1805int GuestSession::queryInfo(void)
1806{
1807 /*
1808 * Try querying the guest control protocol version running on the guest.
1809 * This is done using the Guest Additions version
1810 */
1811 ComObjPtr<Guest> pGuest = mParent;
1812 Assert(!pGuest.isNull());
1813
1814 uint32_t uVerAdditions = pGuest->getAdditionsVersion();
1815 uint32_t uVBoxMajor = VBOX_FULL_VERSION_GET_MAJOR(uVerAdditions);
1816 uint32_t uVBoxMinor = VBOX_FULL_VERSION_GET_MINOR(uVerAdditions);
1817
1818#if 0
1819 /* Hardcode the to-used protocol version; nice for testing side effects. */
1820 mData.mProtocolVersion = 2;
1821#else
1822 mData.mProtocolVersion = (
1823 /* VBox 5.0 and up. */
1824 uVBoxMajor >= 5
1825 /* VBox 4.3 and up. */
1826 || (uVBoxMajor == 4 && uVBoxMinor >= 3))
1827 ? 2 /* Guest control 2.0. */
1828 : 1; /* Legacy guest control (VBox < 4.3). */
1829 /* Build revision is ignored. */
1830#endif
1831
1832 LogFlowThisFunc(("uVerAdditions=%RU32 (%RU32.%RU32), mProtocolVersion=%RU32\n",
1833 uVerAdditions, uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
1834
1835 /* Tell the user but don't bitch too often. */
1836 static short s_gctrlLegacyWarning = 0;
1837 if ( mData.mProtocolVersion < 2
1838 && s_gctrlLegacyWarning++ < 3) /** @todo Find a bit nicer text. */
1839 LogRel((tr("Warning: Guest Additions are older (%ld.%ld) than host capabilities for guest control, please upgrade them. Using protocol version %ld now\n"),
1840 uVBoxMajor, uVBoxMinor, mData.mProtocolVersion));
1841
1842 return VINF_SUCCESS;
1843}
1844
1845int GuestSession::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestSessionWaitResult_T &waitResult, int *pGuestRc)
1846{
1847 LogFlowThisFuncEnter();
1848
1849 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1850
1851 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
1852 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
1853
1854 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1855
1856 /* Did some error occur before? Then skip waiting and return. */
1857 if (mData.mStatus == GuestSessionStatus_Error)
1858 {
1859 waitResult = GuestSessionWaitResult_Error;
1860 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest session indicated an error\n", mData.mRC));
1861 if (pGuestRc)
1862 *pGuestRc = mData.mRC; /* Return last set error. */
1863 return VERR_GSTCTL_GUEST_ERROR;
1864 }
1865
1866 /* Guest Additions < 4.3 don't support session handling, skip. */
1867 if (mData.mProtocolVersion < 2)
1868 {
1869 waitResult = GuestSessionWaitResult_WaitFlagNotSupported;
1870
1871 LogFlowThisFunc(("Installed Guest Additions don't support waiting for dedicated sessions, skipping\n"));
1872 return VINF_SUCCESS;
1873 }
1874
1875 waitResult = GuestSessionWaitResult_None;
1876 if (fWaitFlags & GuestSessionWaitForFlag_Terminate)
1877 {
1878 switch (mData.mStatus)
1879 {
1880 case GuestSessionStatus_Terminated:
1881 case GuestSessionStatus_Down:
1882 waitResult = GuestSessionWaitResult_Terminate;
1883 break;
1884
1885 case GuestSessionStatus_TimedOutKilled:
1886 case GuestSessionStatus_TimedOutAbnormally:
1887 waitResult = GuestSessionWaitResult_Timeout;
1888 break;
1889
1890 case GuestSessionStatus_Error:
1891 /* Handled above. */
1892 break;
1893
1894 case GuestSessionStatus_Started:
1895 waitResult = GuestSessionWaitResult_Start;
1896 break;
1897
1898 case GuestSessionStatus_Undefined:
1899 case GuestSessionStatus_Starting:
1900 /* Do the waiting below. */
1901 break;
1902
1903 default:
1904 AssertMsgFailed(("Unhandled session status %ld\n", mData.mStatus));
1905 return VERR_NOT_IMPLEMENTED;
1906 }
1907 }
1908 else if (fWaitFlags & GuestSessionWaitForFlag_Start)
1909 {
1910 switch (mData.mStatus)
1911 {
1912 case GuestSessionStatus_Started:
1913 case GuestSessionStatus_Terminating:
1914 case GuestSessionStatus_Terminated:
1915 case GuestSessionStatus_Down:
1916 waitResult = GuestSessionWaitResult_Start;
1917 break;
1918
1919 case GuestSessionStatus_Error:
1920 waitResult = GuestSessionWaitResult_Error;
1921 break;
1922
1923 case GuestSessionStatus_TimedOutKilled:
1924 case GuestSessionStatus_TimedOutAbnormally:
1925 waitResult = GuestSessionWaitResult_Timeout;
1926 break;
1927
1928 case GuestSessionStatus_Undefined:
1929 case GuestSessionStatus_Starting:
1930 /* Do the waiting below. */
1931 break;
1932
1933 default:
1934 AssertMsgFailed(("Unhandled session status %ld\n", mData.mStatus));
1935 return VERR_NOT_IMPLEMENTED;
1936 }
1937 }
1938
1939 LogFlowThisFunc(("sessionStatus=%ld, sessionRc=%Rrc, waitResult=%ld\n",
1940 mData.mStatus, mData.mRC, waitResult));
1941
1942 /* No waiting needed? Return immediately using the last set error. */
1943 if (waitResult != GuestSessionWaitResult_None)
1944 {
1945 if (pGuestRc)
1946 *pGuestRc = mData.mRC; /* Return last set error (if any). */
1947 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1948 }
1949
1950 int vrc;
1951
1952 GuestWaitEvent *pEvent = NULL;
1953 std::list < VBoxEventType_T > eventTypes;
1954 try
1955 {
1956 eventTypes.push_back(VBoxEventType_OnGuestSessionStateChanged);
1957
1958 vrc = registerWaitEvent(mData.mSession.mID, 0 /* Object ID */,
1959 eventTypes, &pEvent);
1960 }
1961 catch (std::bad_alloc)
1962 {
1963 vrc = VERR_NO_MEMORY;
1964 }
1965
1966 if (RT_FAILURE(vrc))
1967 return vrc;
1968
1969 alock.release(); /* Release lock before waiting. */
1970
1971 GuestSessionStatus_T sessionStatus;
1972 vrc = waitForStatusChange(pEvent, fWaitFlags,
1973 uTimeoutMS, &sessionStatus, pGuestRc);
1974 if (RT_SUCCESS(vrc))
1975 {
1976 switch (sessionStatus)
1977 {
1978 case GuestSessionStatus_Started:
1979 waitResult = GuestSessionWaitResult_Start;
1980 break;
1981
1982 case GuestSessionStatus_Terminated:
1983 waitResult = GuestSessionWaitResult_Terminate;
1984 break;
1985
1986 case GuestSessionStatus_TimedOutKilled:
1987 case GuestSessionStatus_TimedOutAbnormally:
1988 waitResult = GuestSessionWaitResult_Timeout;
1989 break;
1990
1991 case GuestSessionStatus_Down:
1992 waitResult = GuestSessionWaitResult_Terminate;
1993 break;
1994
1995 case GuestSessionStatus_Error:
1996 waitResult = GuestSessionWaitResult_Error;
1997 break;
1998
1999 default:
2000 waitResult = GuestSessionWaitResult_Status;
2001 break;
2002 }
2003 }
2004
2005 unregisterWaitEvent(pEvent);
2006
2007 LogFlowFuncLeaveRC(vrc);
2008 return vrc;
2009}
2010
2011int GuestSession::waitForStatusChange(GuestWaitEvent *pEvent, uint32_t fWaitFlags, uint32_t uTimeoutMS,
2012 GuestSessionStatus_T *pSessionStatus, int *pGuestRc)
2013{
2014 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2015
2016 VBoxEventType_T evtType;
2017 ComPtr<IEvent> pIEvent;
2018 int vrc = waitForEvent(pEvent, uTimeoutMS,
2019 &evtType, pIEvent.asOutParam());
2020 if (RT_SUCCESS(vrc))
2021 {
2022 Assert(evtType == VBoxEventType_OnGuestSessionStateChanged);
2023
2024 ComPtr<IGuestSessionStateChangedEvent> pChangedEvent = pIEvent;
2025 Assert(!pChangedEvent.isNull());
2026
2027 GuestSessionStatus_T sessionStatus;
2028 pChangedEvent->COMGETTER(Status)(&sessionStatus);
2029 if (pSessionStatus)
2030 *pSessionStatus = sessionStatus;
2031
2032 ComPtr<IVirtualBoxErrorInfo> errorInfo;
2033 HRESULT hr = pChangedEvent->COMGETTER(Error)(errorInfo.asOutParam());
2034 ComAssertComRC(hr);
2035
2036 LONG lGuestRc;
2037 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
2038 ComAssertComRC(hr);
2039 if (RT_FAILURE((int)lGuestRc))
2040 vrc = VERR_GSTCTL_GUEST_ERROR;
2041 if (pGuestRc)
2042 *pGuestRc = (int)lGuestRc;
2043
2044 LogFlowThisFunc(("Status changed event for session ID=%RU32, new status is: %ld (%Rrc)\n",
2045 mData.mSession.mID, sessionStatus,
2046 RT_SUCCESS((int)lGuestRc) ? VINF_SUCCESS : (int)lGuestRc));
2047 }
2048
2049 LogFlowFuncLeaveRC(vrc);
2050 return vrc;
2051}
2052
2053// implementation of public methods
2054/////////////////////////////////////////////////////////////////////////////
2055
2056STDMETHODIMP GuestSession::Close(void)
2057{
2058#ifndef VBOX_WITH_GUEST_CONTROL
2059 ReturnComNotImplemented();
2060#else
2061 LogFlowThisFuncEnter();
2062
2063 AutoCaller autoCaller(this);
2064 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2065
2066 /* Close session on guest. */
2067 int guestRc = VINF_SUCCESS;
2068 int rc = closeSession(0 /* Flags */, 30 * 1000 /* Timeout */,
2069 &guestRc);
2070 /* On failure don't return here, instead do all the cleanup
2071 * work first and then return an error. */
2072
2073 /* Remove ourselves from the session list. */
2074 int rc2 = mParent->sessionRemove(this);
2075 if (RT_SUCCESS(rc))
2076 rc = rc2;
2077
2078 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
2079 rc, guestRc));
2080 if (RT_FAILURE(rc))
2081 {
2082 if (rc == VERR_GSTCTL_GUEST_ERROR)
2083 return GuestSession::setErrorExternal(this, guestRc);
2084
2085 return setError(VBOX_E_IPRT_ERROR,
2086 tr("Closing guest session failed with %Rrc"), rc);
2087 }
2088
2089 return S_OK;
2090#endif /* VBOX_WITH_GUEST_CONTROL */
2091}
2092
2093STDMETHODIMP GuestSession::CopyFrom(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
2094{
2095#ifndef VBOX_WITH_GUEST_CONTROL
2096 ReturnComNotImplemented();
2097#else
2098 CheckComArgStrNotEmptyOrNull(aSource);
2099 CheckComArgStrNotEmptyOrNull(aDest);
2100 CheckComArgOutPointerValid(aProgress);
2101
2102 LogFlowThisFuncEnter();
2103
2104 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
2105 return setError(E_INVALIDARG, tr("No source specified"));
2106 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
2107 return setError(E_INVALIDARG, tr("No destination specified"));
2108
2109 AutoCaller autoCaller(this);
2110 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2111
2112 uint32_t fFlags = CopyFileFlag_None;
2113 if (aFlags)
2114 {
2115 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
2116 for (size_t i = 0; i < flags.size(); i++)
2117 fFlags |= flags[i];
2118 }
2119
2120 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2121
2122 HRESULT hr = S_OK;
2123
2124 try
2125 {
2126 ComObjPtr<Progress> pProgress;
2127 SessionTaskCopyFrom *pTask = new SessionTaskCopyFrom(this /* GuestSession */,
2128 Utf8Str(aSource), Utf8Str(aDest), fFlags);
2129 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from guest to \"%ls\" on the host"), aSource, aDest),
2130 pTask, pProgress);
2131 if (RT_SUCCESS(rc))
2132 {
2133 /* Return progress to the caller. */
2134 hr = pProgress.queryInterfaceTo(aProgress);
2135 }
2136 else
2137 hr = setError(VBOX_E_IPRT_ERROR,
2138 tr("Starting task for copying file \"%ls\" from guest to \"%ls\" on the host failed: %Rrc"), rc);
2139 }
2140 catch(std::bad_alloc &)
2141 {
2142 hr = E_OUTOFMEMORY;
2143 }
2144
2145 return hr;
2146#endif /* VBOX_WITH_GUEST_CONTROL */
2147}
2148
2149STDMETHODIMP GuestSession::CopyTo(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(CopyFileFlag_T, aFlags), IProgress **aProgress)
2150{
2151#ifndef VBOX_WITH_GUEST_CONTROL
2152 ReturnComNotImplemented();
2153#else
2154 CheckComArgStrNotEmptyOrNull(aSource);
2155 CheckComArgStrNotEmptyOrNull(aDest);
2156 CheckComArgOutPointerValid(aProgress);
2157
2158 LogFlowThisFuncEnter();
2159
2160 if (RT_UNLIKELY((aSource) == NULL || *(aSource) == '\0'))
2161 return setError(E_INVALIDARG, tr("No source specified"));
2162 if (RT_UNLIKELY((aDest) == NULL || *(aDest) == '\0'))
2163 return setError(E_INVALIDARG, tr("No destination specified"));
2164
2165 AutoCaller autoCaller(this);
2166 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2167
2168 uint32_t fFlags = CopyFileFlag_None;
2169 if (aFlags)
2170 {
2171 com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
2172 for (size_t i = 0; i < flags.size(); i++)
2173 fFlags |= flags[i];
2174 }
2175
2176 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2177
2178 HRESULT hr = S_OK;
2179
2180 try
2181 {
2182 ComObjPtr<Progress> pProgress;
2183 SessionTaskCopyTo *pTask = new SessionTaskCopyTo(this /* GuestSession */,
2184 Utf8Str(aSource), Utf8Str(aDest), fFlags);
2185 AssertPtrReturn(pTask, E_OUTOFMEMORY);
2186 int rc = startTaskAsync(Utf8StrFmt(tr("Copying \"%ls\" from host to \"%ls\" on the guest"), aSource, aDest),
2187 pTask, pProgress);
2188 if (RT_SUCCESS(rc))
2189 {
2190 /* Return progress to the caller. */
2191 hr = pProgress.queryInterfaceTo(aProgress);
2192 }
2193 else
2194 hr = setError(VBOX_E_IPRT_ERROR,
2195 tr("Starting task for copying file \"%ls\" from host to \"%ls\" on the guest failed: %Rrc"), rc);
2196 }
2197 catch(std::bad_alloc &)
2198 {
2199 hr = E_OUTOFMEMORY;
2200 }
2201
2202 return hr;
2203#endif /* VBOX_WITH_GUEST_CONTROL */
2204}
2205
2206STDMETHODIMP GuestSession::DirectoryCreate(IN_BSTR aPath, ULONG aMode,
2207 ComSafeArrayIn(DirectoryCreateFlag_T, aFlags))
2208{
2209#ifndef VBOX_WITH_GUEST_CONTROL
2210 ReturnComNotImplemented();
2211#else
2212 LogFlowThisFuncEnter();
2213
2214 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2215 return setError(E_INVALIDARG, tr("No directory to create specified"));
2216
2217 AutoCaller autoCaller(this);
2218 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2219
2220 uint32_t fFlags = DirectoryCreateFlag_None;
2221 if (aFlags)
2222 {
2223 com::SafeArray<DirectoryCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2224 for (size_t i = 0; i < flags.size(); i++)
2225 fFlags |= flags[i];
2226
2227 if (fFlags)
2228 {
2229 if (!(fFlags & DirectoryCreateFlag_Parents))
2230 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), fFlags);
2231 }
2232 }
2233
2234 HRESULT hr = S_OK;
2235
2236 ComObjPtr <GuestDirectory> pDirectory; int guestRc;
2237 int rc = directoryCreateInternal(Utf8Str(aPath), (uint32_t)aMode, fFlags, &guestRc);
2238 if (RT_FAILURE(rc))
2239 {
2240 switch (rc)
2241 {
2242 case VERR_GSTCTL_GUEST_ERROR:
2243 hr = GuestProcess::setErrorExternal(this, guestRc);
2244 break;
2245
2246 case VERR_INVALID_PARAMETER:
2247 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Invalid parameters given"));
2248 break;
2249
2250 case VERR_BROKEN_PIPE:
2251 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Unexpectedly aborted"));
2252 break;
2253
2254 case VERR_CANT_CREATE:
2255 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: Could not create directory"));
2256 break;
2257
2258 default:
2259 hr = setError(VBOX_E_IPRT_ERROR, tr("Directory creation failed: %Rrc"), rc);
2260 break;
2261 }
2262 }
2263
2264 return hr;
2265#endif /* VBOX_WITH_GUEST_CONTROL */
2266}
2267
2268STDMETHODIMP GuestSession::DirectoryCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, BSTR *aDirectory)
2269{
2270#ifndef VBOX_WITH_GUEST_CONTROL
2271 ReturnComNotImplemented();
2272#else
2273 LogFlowThisFuncEnter();
2274
2275 if (RT_UNLIKELY((aTemplate) == NULL || *(aTemplate) == '\0'))
2276 return setError(E_INVALIDARG, tr("No template specified"));
2277 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2278 return setError(E_INVALIDARG, tr("No directory name specified"));
2279 CheckComArgOutPointerValid(aDirectory);
2280
2281 AutoCaller autoCaller(this);
2282 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2283
2284 HRESULT hr = S_OK;
2285
2286 Utf8Str strName; int guestRc;
2287 int rc = objectCreateTempInternal(Utf8Str(aTemplate),
2288 Utf8Str(aPath),
2289 true /* Directory */, strName, &guestRc);
2290 if (RT_SUCCESS(rc))
2291 {
2292 strName.cloneTo(aDirectory);
2293 }
2294 else
2295 {
2296 switch (rc)
2297 {
2298 case VERR_GSTCTL_GUEST_ERROR:
2299 hr = GuestProcess::setErrorExternal(this, guestRc);
2300 break;
2301
2302 default:
2303 hr = setError(VBOX_E_IPRT_ERROR, tr("Temporary directory creation \"%s\" with template \"%s\" failed: %Rrc"),
2304 Utf8Str(aPath).c_str(), Utf8Str(aTemplate).c_str(), rc);
2305 break;
2306 }
2307 }
2308
2309 return hr;
2310#endif /* VBOX_WITH_GUEST_CONTROL */
2311}
2312
2313STDMETHODIMP GuestSession::DirectoryExists(IN_BSTR aPath, BOOL *aExists)
2314{
2315#ifndef VBOX_WITH_GUEST_CONTROL
2316 ReturnComNotImplemented();
2317#else
2318 LogFlowThisFuncEnter();
2319
2320 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2321 return setError(E_INVALIDARG, tr("No directory to check existence for specified"));
2322 CheckComArgOutPointerValid(aExists);
2323
2324 AutoCaller autoCaller(this);
2325 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2326
2327 HRESULT hr = S_OK;
2328
2329 GuestFsObjData objData; int guestRc;
2330 int rc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2331 if (RT_SUCCESS(rc))
2332 {
2333 *aExists = objData.mType == FsObjType_Directory;
2334 }
2335 else
2336 {
2337 switch (rc)
2338 {
2339 case VERR_GSTCTL_GUEST_ERROR:
2340 hr = GuestProcess::setErrorExternal(this, guestRc);
2341 break;
2342
2343 default:
2344 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory existence \"%s\" failed: %Rrc"),
2345 Utf8Str(aPath).c_str(), rc);
2346 break;
2347 }
2348 }
2349
2350 return hr;
2351#endif /* VBOX_WITH_GUEST_CONTROL */
2352}
2353
2354STDMETHODIMP GuestSession::DirectoryOpen(IN_BSTR aPath, IN_BSTR aFilter, ComSafeArrayIn(DirectoryOpenFlag_T, aFlags), IGuestDirectory **aDirectory)
2355{
2356#ifndef VBOX_WITH_GUEST_CONTROL
2357 ReturnComNotImplemented();
2358#else
2359 LogFlowThisFuncEnter();
2360
2361 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2362 return setError(E_INVALIDARG, tr("No directory to open specified"));
2363 if (RT_UNLIKELY((aFilter) != NULL && *(aFilter) != '\0'))
2364 return setError(E_INVALIDARG, tr("Directory filters are not implemented yet"));
2365 CheckComArgOutPointerValid(aDirectory);
2366
2367 AutoCaller autoCaller(this);
2368 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2369
2370 uint32_t fFlags = DirectoryOpenFlag_None;
2371 if (aFlags)
2372 {
2373 com::SafeArray<DirectoryOpenFlag_T> flags(ComSafeArrayInArg(aFlags));
2374 for (size_t i = 0; i < flags.size(); i++)
2375 fFlags |= flags[i];
2376
2377 if (fFlags)
2378 return setError(E_INVALIDARG, tr("Open flags (%#x) not implemented yet"), fFlags);
2379 }
2380
2381 HRESULT hr = S_OK;
2382
2383 ComObjPtr <GuestDirectory> pDirectory;
2384 int rc = directoryOpenInternal(Utf8Str(aPath), Utf8Str(aFilter), fFlags, pDirectory);
2385 if (RT_SUCCESS(rc))
2386 {
2387 /* Return directory object to the caller. */
2388 hr = pDirectory.queryInterfaceTo(aDirectory);
2389 }
2390 else
2391 {
2392 switch (rc)
2393 {
2394 case VERR_INVALID_PARAMETER:
2395 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed; invalid parameters given",
2396 Utf8Str(aPath).c_str()));
2397 break;
2398
2399 default:
2400 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening directory \"%s\" failed: %Rrc"),
2401 Utf8Str(aPath).c_str(),rc);
2402 break;
2403 }
2404 }
2405
2406 return hr;
2407#endif /* VBOX_WITH_GUEST_CONTROL */
2408}
2409
2410STDMETHODIMP GuestSession::DirectoryQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2411{
2412#ifndef VBOX_WITH_GUEST_CONTROL
2413 ReturnComNotImplemented();
2414#else
2415 LogFlowThisFuncEnter();
2416
2417 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2418 return setError(E_INVALIDARG, tr("No directory to query information for specified"));
2419 CheckComArgOutPointerValid(aInfo);
2420
2421 AutoCaller autoCaller(this);
2422 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2423
2424 HRESULT hr = S_OK;
2425
2426 GuestFsObjData objData; int guestRc;
2427 int vrc = directoryQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2428 if (RT_SUCCESS(vrc))
2429 {
2430 if (objData.mType == FsObjType_Directory)
2431 {
2432 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2433 hr = pFsObjInfo.createObject();
2434 if (FAILED(hr)) return hr;
2435
2436 vrc = pFsObjInfo->init(objData);
2437 if (RT_SUCCESS(vrc))
2438 {
2439 hr = pFsObjInfo.queryInterfaceTo(aInfo);
2440 if (FAILED(hr)) return hr;
2441 }
2442 }
2443 }
2444
2445 if (RT_FAILURE(vrc))
2446 {
2447 switch (vrc)
2448 {
2449 case VERR_GSTCTL_GUEST_ERROR:
2450 hr = GuestProcess::setErrorExternal(this, guestRc);
2451 break;
2452
2453 case VERR_NOT_A_DIRECTORY:
2454 hr = setError(VBOX_E_IPRT_ERROR, tr("Element \"%s\" exists but is not a directory",
2455 Utf8Str(aPath).c_str()));
2456 break;
2457
2458 default:
2459 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying directory information for \"%s\" failed: %Rrc"),
2460 Utf8Str(aPath).c_str(), vrc);
2461 break;
2462 }
2463 }
2464
2465 return hr;
2466#endif /* VBOX_WITH_GUEST_CONTROL */
2467}
2468
2469STDMETHODIMP GuestSession::DirectoryRemove(IN_BSTR aPath)
2470{
2471#ifndef VBOX_WITH_GUEST_CONTROL
2472 ReturnComNotImplemented();
2473#else
2474 LogFlowThisFuncEnter();
2475
2476 AutoCaller autoCaller(this);
2477 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2478
2479 ReturnComNotImplemented();
2480#endif /* VBOX_WITH_GUEST_CONTROL */
2481}
2482
2483STDMETHODIMP GuestSession::DirectoryRemoveRecursive(IN_BSTR aPath, ComSafeArrayIn(DirectoryRemoveRecFlag_T, aFlags), IProgress **aProgress)
2484{
2485#ifndef VBOX_WITH_GUEST_CONTROL
2486 ReturnComNotImplemented();
2487#else
2488 LogFlowThisFuncEnter();
2489
2490 AutoCaller autoCaller(this);
2491 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2492
2493 ReturnComNotImplemented();
2494#endif /* VBOX_WITH_GUEST_CONTROL */
2495}
2496
2497STDMETHODIMP GuestSession::DirectoryRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2498{
2499#ifndef VBOX_WITH_GUEST_CONTROL
2500 ReturnComNotImplemented();
2501#else
2502 LogFlowThisFuncEnter();
2503
2504 AutoCaller autoCaller(this);
2505 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2506
2507 ReturnComNotImplemented();
2508#endif /* VBOX_WITH_GUEST_CONTROL */
2509}
2510
2511STDMETHODIMP GuestSession::DirectorySetACL(IN_BSTR aPath, IN_BSTR aACL)
2512{
2513#ifndef VBOX_WITH_GUEST_CONTROL
2514 ReturnComNotImplemented();
2515#else
2516 LogFlowThisFuncEnter();
2517
2518 AutoCaller autoCaller(this);
2519 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2520
2521 ReturnComNotImplemented();
2522#endif /* VBOX_WITH_GUEST_CONTROL */
2523}
2524
2525STDMETHODIMP GuestSession::EnvironmentClear(void)
2526{
2527#ifndef VBOX_WITH_GUEST_CONTROL
2528 ReturnComNotImplemented();
2529#else
2530 LogFlowThisFuncEnter();
2531
2532 AutoCaller autoCaller(this);
2533 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2534
2535 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2536
2537 mData.mEnvironment.Clear();
2538
2539 LogFlowThisFuncLeave();
2540 return S_OK;
2541#endif /* VBOX_WITH_GUEST_CONTROL */
2542}
2543
2544STDMETHODIMP GuestSession::EnvironmentGet(IN_BSTR aName, BSTR *aValue)
2545{
2546#ifndef VBOX_WITH_GUEST_CONTROL
2547 ReturnComNotImplemented();
2548#else
2549 LogFlowThisFuncEnter();
2550
2551 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2552 return setError(E_INVALIDARG, tr("No value name specified"));
2553
2554 CheckComArgOutPointerValid(aValue);
2555
2556 AutoCaller autoCaller(this);
2557 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2558
2559 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2560
2561 Bstr strValue(mData.mEnvironment.Get(Utf8Str(aName)));
2562 strValue.cloneTo(aValue);
2563
2564 LogFlowThisFuncLeave();
2565 return S_OK;
2566#endif /* VBOX_WITH_GUEST_CONTROL */
2567}
2568
2569STDMETHODIMP GuestSession::EnvironmentSet(IN_BSTR aName, IN_BSTR aValue)
2570{
2571#ifndef VBOX_WITH_GUEST_CONTROL
2572 ReturnComNotImplemented();
2573#else
2574 LogFlowThisFuncEnter();
2575
2576 if (RT_UNLIKELY((aName) == NULL || *(aName) == '\0'))
2577 return setError(E_INVALIDARG, tr("No value name specified"));
2578
2579 AutoCaller autoCaller(this);
2580 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2581
2582 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2583
2584 int rc = mData.mEnvironment.Set(Utf8Str(aName), Utf8Str(aValue));
2585
2586 HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
2587 LogFlowFuncLeaveRC(hr);
2588 return hr;
2589#endif /* VBOX_WITH_GUEST_CONTROL */
2590}
2591
2592STDMETHODIMP GuestSession::EnvironmentUnset(IN_BSTR aName)
2593{
2594#ifndef VBOX_WITH_GUEST_CONTROL
2595 ReturnComNotImplemented();
2596#else
2597 LogFlowThisFuncEnter();
2598
2599 AutoCaller autoCaller(this);
2600 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2601
2602 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2603
2604 mData.mEnvironment.Unset(Utf8Str(aName));
2605
2606 LogFlowThisFuncLeave();
2607 return S_OK;
2608#endif /* VBOX_WITH_GUEST_CONTROL */
2609}
2610
2611STDMETHODIMP GuestSession::FileCreateTemp(IN_BSTR aTemplate, ULONG aMode, IN_BSTR aPath, BOOL aSecure, IGuestFile **aFile)
2612{
2613#ifndef VBOX_WITH_GUEST_CONTROL
2614 ReturnComNotImplemented();
2615#else
2616 LogFlowThisFuncEnter();
2617
2618 AutoCaller autoCaller(this);
2619 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2620
2621 ReturnComNotImplemented();
2622#endif /* VBOX_WITH_GUEST_CONTROL */
2623}
2624
2625STDMETHODIMP GuestSession::FileExists(IN_BSTR aPath, BOOL *aExists)
2626{
2627#ifndef VBOX_WITH_GUEST_CONTROL
2628 ReturnComNotImplemented();
2629#else
2630 LogFlowThisFuncEnter();
2631
2632 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2633 return setError(E_INVALIDARG, tr("No file to check existence for specified"));
2634 CheckComArgOutPointerValid(aExists);
2635
2636 AutoCaller autoCaller(this);
2637 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2638
2639 GuestFsObjData objData; int guestRc;
2640 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2641 if (RT_SUCCESS(vrc))
2642 {
2643 *aExists = TRUE;
2644 return S_OK;
2645 }
2646
2647 HRESULT hr = S_OK;
2648
2649 switch (vrc)
2650 {
2651 case VERR_GSTCTL_GUEST_ERROR:
2652 hr = GuestProcess::setErrorExternal(this, guestRc);
2653 break;
2654
2655 case VERR_NOT_A_FILE:
2656 *aExists = FALSE;
2657 break;
2658
2659 default:
2660 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information for \"%s\" failed: %Rrc"),
2661 Utf8Str(aPath).c_str(), vrc);
2662 break;
2663 }
2664
2665 return hr;
2666#endif /* VBOX_WITH_GUEST_CONTROL */
2667}
2668
2669STDMETHODIMP GuestSession::FileRemove(IN_BSTR aPath)
2670{
2671#ifndef VBOX_WITH_GUEST_CONTROL
2672 ReturnComNotImplemented();
2673#else
2674 LogFlowThisFuncEnter();
2675
2676 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2677 return setError(E_INVALIDARG, tr("No file to remove specified"));
2678
2679 AutoCaller autoCaller(this);
2680 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2681
2682 HRESULT hr = S_OK;
2683
2684 int guestRc;
2685 int vrc = fileRemoveInternal(Utf8Str(aPath), &guestRc);
2686 if (RT_FAILURE(vrc))
2687 {
2688 switch (vrc)
2689 {
2690 case VERR_GSTCTL_GUEST_ERROR:
2691 hr = GuestProcess::setErrorExternal(this, guestRc);
2692 break;
2693
2694 default:
2695 hr = setError(VBOX_E_IPRT_ERROR, tr("Removing file \"%s\" failed: %Rrc"),
2696 Utf8Str(aPath).c_str(), vrc);
2697 break;
2698 }
2699 }
2700
2701 return hr;
2702#endif /* VBOX_WITH_GUEST_CONTROL */
2703}
2704
2705STDMETHODIMP GuestSession::FileOpen(IN_BSTR aPath, IN_BSTR aOpenMode, IN_BSTR aDisposition, ULONG aCreationMode, LONG64 aOffset, IGuestFile **aFile)
2706{
2707#ifndef VBOX_WITH_GUEST_CONTROL
2708 ReturnComNotImplemented();
2709#else
2710 LogFlowThisFuncEnter();
2711
2712 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2713 return setError(E_INVALIDARG, tr("No file to open specified"));
2714 if (RT_UNLIKELY((aOpenMode) == NULL || *(aOpenMode) == '\0'))
2715 return setError(E_INVALIDARG, tr("No open mode specified"));
2716 if (RT_UNLIKELY((aDisposition) == NULL || *(aDisposition) == '\0'))
2717 return setError(E_INVALIDARG, tr("No disposition mode specified"));
2718
2719 CheckComArgOutPointerValid(aFile);
2720
2721 AutoCaller autoCaller(this);
2722 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2723
2724 HRESULT hr = isReadyExternal();
2725 if (FAILED(hr))
2726 return hr;
2727
2728 /** @todo Validate open mode. */
2729 /** @todo Validate disposition mode. */
2730
2731 /** @todo Validate creation mode. */
2732 uint32_t uCreationMode = 0;
2733
2734 GuestFileOpenInfo openInfo;
2735 openInfo.mFileName = Utf8Str(aPath);
2736 openInfo.mOpenMode = Utf8Str(aOpenMode);
2737 openInfo.mDisposition = Utf8Str(aDisposition);
2738 openInfo.mCreationMode = aCreationMode;
2739 openInfo.mInitialOffset = aOffset;
2740
2741 ComObjPtr <GuestFile> pFile; int guestRc;
2742 int vrc = fileOpenInternal(openInfo, pFile, &guestRc);
2743 if (RT_SUCCESS(vrc))
2744 {
2745 /* Return directory object to the caller. */
2746 hr = pFile.queryInterfaceTo(aFile);
2747 }
2748 else
2749 {
2750 switch (vrc)
2751 {
2752 case VERR_GSTCTL_GUEST_ERROR:
2753 hr = GuestFile::setErrorExternal(this, guestRc);
2754 break;
2755
2756 default:
2757 hr = setError(VBOX_E_IPRT_ERROR, tr("Opening guest file \"%s\" failed: %Rrc"),
2758 Utf8Str(aPath).c_str(), vrc);
2759 break;
2760 }
2761 }
2762
2763 return hr;
2764#endif /* VBOX_WITH_GUEST_CONTROL */
2765}
2766
2767STDMETHODIMP GuestSession::FileQueryInfo(IN_BSTR aPath, IGuestFsObjInfo **aInfo)
2768{
2769#ifndef VBOX_WITH_GUEST_CONTROL
2770 ReturnComNotImplemented();
2771#else
2772 LogFlowThisFuncEnter();
2773
2774 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2775 return setError(E_INVALIDARG, tr("No file to query information for specified"));
2776 CheckComArgOutPointerValid(aInfo);
2777
2778 AutoCaller autoCaller(this);
2779 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2780
2781 HRESULT hr = S_OK;
2782
2783 GuestFsObjData objData; int guestRc;
2784 int vrc = fileQueryInfoInternal(Utf8Str(aPath), objData, &guestRc);
2785 if (RT_SUCCESS(vrc))
2786 {
2787 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
2788 hr = pFsObjInfo.createObject();
2789 if (FAILED(hr)) return hr;
2790
2791 vrc = pFsObjInfo->init(objData);
2792 if (RT_SUCCESS(vrc))
2793 {
2794 hr = pFsObjInfo.queryInterfaceTo(aInfo);
2795 if (FAILED(hr)) return hr;
2796 }
2797 }
2798
2799 if (RT_FAILURE(vrc))
2800 {
2801 switch (vrc)
2802 {
2803 case VERR_GSTCTL_GUEST_ERROR:
2804 hr = GuestProcess::setErrorExternal(this, guestRc);
2805 break;
2806
2807 case VERR_NOT_A_FILE:
2808 hr = setError(VBOX_E_IPRT_ERROR, tr("Element exists but is not a file"));
2809 break;
2810
2811 default:
2812 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file information failed: %Rrc"), vrc);
2813 break;
2814 }
2815 }
2816
2817 return hr;
2818#endif /* VBOX_WITH_GUEST_CONTROL */
2819}
2820
2821STDMETHODIMP GuestSession::FileQuerySize(IN_BSTR aPath, LONG64 *aSize)
2822{
2823#ifndef VBOX_WITH_GUEST_CONTROL
2824 ReturnComNotImplemented();
2825#else
2826 LogFlowThisFuncEnter();
2827
2828 if (RT_UNLIKELY((aPath) == NULL || *(aPath) == '\0'))
2829 return setError(E_INVALIDARG, tr("No file to query size for specified"));
2830 CheckComArgOutPointerValid(aSize);
2831
2832 AutoCaller autoCaller(this);
2833 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2834
2835 HRESULT hr = S_OK;
2836
2837 int64_t llSize; int guestRc;
2838 int vrc = fileQuerySizeInternal(Utf8Str(aPath), &llSize, &guestRc);
2839 if (RT_SUCCESS(vrc))
2840 {
2841 *aSize = llSize;
2842 }
2843 else
2844 {
2845 switch (vrc)
2846 {
2847 case VERR_GSTCTL_GUEST_ERROR:
2848 hr = GuestProcess::setErrorExternal(this, guestRc);
2849 break;
2850
2851 default:
2852 hr = setError(VBOX_E_IPRT_ERROR, tr("Querying file size failed: %Rrc"), vrc);
2853 break;
2854 }
2855 }
2856
2857 return hr;
2858#endif /* VBOX_WITH_GUEST_CONTROL */
2859}
2860
2861STDMETHODIMP GuestSession::FileRename(IN_BSTR aSource, IN_BSTR aDest, ComSafeArrayIn(PathRenameFlag_T, aFlags))
2862{
2863#ifndef VBOX_WITH_GUEST_CONTROL
2864 ReturnComNotImplemented();
2865#else
2866 LogFlowThisFuncEnter();
2867
2868 AutoCaller autoCaller(this);
2869 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2870
2871 ReturnComNotImplemented();
2872#endif /* VBOX_WITH_GUEST_CONTROL */
2873}
2874
2875STDMETHODIMP GuestSession::FileSetACL(IN_BSTR aPath, IN_BSTR aACL)
2876{
2877#ifndef VBOX_WITH_GUEST_CONTROL
2878 ReturnComNotImplemented();
2879#else
2880 LogFlowThisFuncEnter();
2881
2882 AutoCaller autoCaller(this);
2883 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2884
2885 ReturnComNotImplemented();
2886#endif /* VBOX_WITH_GUEST_CONTROL */
2887}
2888
2889STDMETHODIMP GuestSession::ProcessCreate(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2890 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS, IGuestProcess **aProcess)
2891{
2892#ifndef VBOX_WITH_GUEST_CONTROL
2893 ReturnComNotImplemented();
2894#else
2895 LogFlowThisFuncEnter();
2896
2897 com::SafeArray<LONG> affinityIgnored;
2898
2899 return ProcessCreateEx(aCommand, ComSafeArrayInArg(aArguments), ComSafeArrayInArg(aEnvironment),
2900 ComSafeArrayInArg(aFlags), aTimeoutMS, ProcessPriority_Default, ComSafeArrayAsInParam(affinityIgnored), aProcess);
2901#endif /* VBOX_WITH_GUEST_CONTROL */
2902}
2903
2904STDMETHODIMP GuestSession::ProcessCreateEx(IN_BSTR aCommand, ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
2905 ComSafeArrayIn(ProcessCreateFlag_T, aFlags), ULONG aTimeoutMS,
2906 ProcessPriority_T aPriority, ComSafeArrayIn(LONG, aAffinity),
2907 IGuestProcess **aProcess)
2908{
2909#ifndef VBOX_WITH_GUEST_CONTROL
2910 ReturnComNotImplemented();
2911#else
2912 LogFlowThisFuncEnter();
2913
2914 if (RT_UNLIKELY((aCommand) == NULL || *(aCommand) == '\0'))
2915 return setError(E_INVALIDARG, tr("No command to execute specified"));
2916 CheckComArgOutPointerValid(aProcess);
2917
2918 AutoCaller autoCaller(this);
2919 if (FAILED(autoCaller.rc())) return autoCaller.rc();
2920
2921 HRESULT hr = isReadyExternal();
2922 if (FAILED(hr))
2923 return hr;
2924
2925 GuestProcessStartupInfo procInfo;
2926 procInfo.mCommand = Utf8Str(aCommand);
2927
2928 if (aArguments)
2929 {
2930 com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
2931 for (size_t i = 0; i < arguments.size(); i++)
2932 procInfo.mArguments.push_back(Utf8Str(arguments[i]));
2933 }
2934
2935 int rc = VINF_SUCCESS;
2936
2937 /*
2938 * Create the process environment:
2939 * - Apply the session environment in a first step, and
2940 * - Apply environment variables specified by this call to
2941 * have the chance of overwriting/deleting session entries.
2942 */
2943 procInfo.mEnvironment = mData.mEnvironment; /* Apply original session environment. */
2944
2945 if (aEnvironment)
2946 {
2947 com::SafeArray<IN_BSTR> environment(ComSafeArrayInArg(aEnvironment));
2948 for (size_t i = 0; i < environment.size() && RT_SUCCESS(rc); i++)
2949 rc = procInfo.mEnvironment.Set(Utf8Str(environment[i]));
2950 }
2951
2952 if (RT_SUCCESS(rc))
2953 {
2954 if (aFlags)
2955 {
2956 com::SafeArray<ProcessCreateFlag_T> flags(ComSafeArrayInArg(aFlags));
2957 for (size_t i = 0; i < flags.size(); i++)
2958 procInfo.mFlags |= flags[i];
2959 }
2960
2961 procInfo.mTimeoutMS = aTimeoutMS;
2962
2963 if (aAffinity)
2964 {
2965 com::SafeArray<LONG> affinity(ComSafeArrayInArg(aAffinity));
2966 for (size_t i = 0; i < affinity.size(); i++)
2967 {
2968 if (affinity[i])
2969 procInfo.mAffinity |= (uint64_t)1 << i;
2970 }
2971 }
2972
2973 procInfo.mPriority = aPriority;
2974
2975 ComObjPtr<GuestProcess> pProcess;
2976 rc = processCreateExInteral(procInfo, pProcess);
2977 if (RT_SUCCESS(rc))
2978 {
2979 /* Return guest session to the caller. */
2980 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
2981 if (FAILED(hr2))
2982 rc = VERR_COM_OBJECT_NOT_FOUND;
2983
2984 if (RT_SUCCESS(rc))
2985 rc = pProcess->startProcessAsync();
2986 }
2987 }
2988
2989 if (RT_FAILURE(rc))
2990 {
2991 switch (rc)
2992 {
2993 case VERR_MAX_PROCS_REACHED:
2994 hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest processes per session (%ld) reached"),
2995 VBOX_GUESTCTRL_MAX_OBJECTS);
2996 break;
2997
2998 /** @todo Add more errors here. */
2999
3000 default:
3001 hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest process, rc=%Rrc"), rc);
3002 break;
3003 }
3004 }
3005
3006 LogFlowFuncLeaveRC(rc);
3007 return hr;
3008#endif /* VBOX_WITH_GUEST_CONTROL */
3009}
3010
3011STDMETHODIMP GuestSession::ProcessGet(ULONG aPID, IGuestProcess **aProcess)
3012{
3013#ifndef VBOX_WITH_GUEST_CONTROL
3014 ReturnComNotImplemented();
3015#else
3016 LogFlowThisFunc(("aPID=%RU32\n", aPID));
3017
3018 CheckComArgOutPointerValid(aProcess);
3019 if (aPID == 0)
3020 return setError(E_INVALIDARG, tr("No valid process ID (PID) specified"));
3021
3022 AutoCaller autoCaller(this);
3023 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3024
3025 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
3026
3027 HRESULT hr = S_OK;
3028
3029 ComObjPtr<GuestProcess> pProcess;
3030 int rc = processGetByPID(aPID, &pProcess);
3031 if (RT_FAILURE(rc))
3032 hr = setError(E_INVALIDARG, tr("No process with PID %RU32 found"), aPID);
3033
3034 /* This will set (*aProcess) to NULL if pProgress is NULL. */
3035 HRESULT hr2 = pProcess.queryInterfaceTo(aProcess);
3036 if (SUCCEEDED(hr))
3037 hr = hr2;
3038
3039 LogFlowThisFunc(("aProcess=%p, hr=%Rhrc\n", *aProcess, hr));
3040 return hr;
3041#endif /* VBOX_WITH_GUEST_CONTROL */
3042}
3043
3044STDMETHODIMP GuestSession::SymlinkCreate(IN_BSTR aSource, IN_BSTR aTarget, SymlinkType_T aType)
3045{
3046#ifndef VBOX_WITH_GUEST_CONTROL
3047 ReturnComNotImplemented();
3048#else
3049 LogFlowThisFuncEnter();
3050
3051 AutoCaller autoCaller(this);
3052 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3053
3054 ReturnComNotImplemented();
3055#endif /* VBOX_WITH_GUEST_CONTROL */
3056}
3057
3058STDMETHODIMP GuestSession::SymlinkExists(IN_BSTR aSymlink, BOOL *aExists)
3059{
3060#ifndef VBOX_WITH_GUEST_CONTROL
3061 ReturnComNotImplemented();
3062#else
3063 LogFlowThisFuncEnter();
3064
3065 AutoCaller autoCaller(this);
3066 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3067
3068 ReturnComNotImplemented();
3069#endif /* VBOX_WITH_GUEST_CONTROL */
3070}
3071
3072STDMETHODIMP GuestSession::SymlinkRead(IN_BSTR aSymlink, ComSafeArrayIn(SymlinkReadFlag_T, aFlags), BSTR *aTarget)
3073{
3074#ifndef VBOX_WITH_GUEST_CONTROL
3075 ReturnComNotImplemented();
3076#else
3077 LogFlowThisFuncEnter();
3078
3079 AutoCaller autoCaller(this);
3080 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3081
3082 ReturnComNotImplemented();
3083#endif /* VBOX_WITH_GUEST_CONTROL */
3084}
3085
3086STDMETHODIMP GuestSession::SymlinkRemoveDirectory(IN_BSTR aPath)
3087{
3088#ifndef VBOX_WITH_GUEST_CONTROL
3089 ReturnComNotImplemented();
3090#else
3091 LogFlowThisFuncEnter();
3092
3093 AutoCaller autoCaller(this);
3094 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3095
3096 ReturnComNotImplemented();
3097#endif /* VBOX_WITH_GUEST_CONTROL */
3098}
3099
3100STDMETHODIMP GuestSession::SymlinkRemoveFile(IN_BSTR aFile)
3101{
3102#ifndef VBOX_WITH_GUEST_CONTROL
3103 ReturnComNotImplemented();
3104#else
3105 LogFlowThisFuncEnter();
3106
3107 AutoCaller autoCaller(this);
3108 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3109
3110 ReturnComNotImplemented();
3111#endif /* VBOX_WITH_GUEST_CONTROL */
3112}
3113
3114STDMETHODIMP GuestSession::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3115{
3116#ifndef VBOX_WITH_GUEST_CONTROL
3117 ReturnComNotImplemented();
3118#else
3119 LogFlowThisFuncEnter();
3120
3121 CheckComArgOutPointerValid(aReason);
3122
3123 AutoCaller autoCaller(this);
3124 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3125
3126 /*
3127 * Note: Do not hold any locks here while waiting!
3128 */
3129 HRESULT hr = S_OK;
3130
3131 int guestRc; GuestSessionWaitResult_T waitResult;
3132 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
3133 if (RT_SUCCESS(vrc))
3134 {
3135 *aReason = waitResult;
3136 }
3137 else
3138 {
3139 switch (vrc)
3140 {
3141 case VERR_GSTCTL_GUEST_ERROR:
3142 hr = GuestSession::setErrorExternal(this, guestRc);
3143 break;
3144
3145 case VERR_TIMEOUT:
3146 *aReason = GuestSessionWaitResult_Timeout;
3147 break;
3148
3149 default:
3150 {
3151 const char *pszSessionName = mData.mSession.mName.c_str();
3152 hr = setError(VBOX_E_IPRT_ERROR,
3153 tr("Waiting for guest session \"%s\" failed: %Rrc"),
3154 pszSessionName ? pszSessionName : tr("Unnamed"), vrc);
3155 break;
3156 }
3157 }
3158 }
3159
3160 LogFlowFuncLeaveRC(vrc);
3161 return hr;
3162#endif /* VBOX_WITH_GUEST_CONTROL */
3163}
3164
3165STDMETHODIMP GuestSession::WaitForArray(ComSafeArrayIn(GuestSessionWaitForFlag_T, aFlags), ULONG aTimeoutMS, GuestSessionWaitResult_T *aReason)
3166{
3167#ifndef VBOX_WITH_GUEST_CONTROL
3168 ReturnComNotImplemented();
3169#else
3170 LogFlowThisFuncEnter();
3171
3172 CheckComArgOutPointerValid(aReason);
3173
3174 AutoCaller autoCaller(this);
3175 if (FAILED(autoCaller.rc())) return autoCaller.rc();
3176
3177 /*
3178 * Note: Do not hold any locks here while waiting!
3179 */
3180 uint32_t fWaitFor = GuestSessionWaitForFlag_None;
3181 com::SafeArray<GuestSessionWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
3182 for (size_t i = 0; i < flags.size(); i++)
3183 fWaitFor |= flags[i];
3184
3185 return WaitFor(fWaitFor, aTimeoutMS, aReason);
3186#endif /* VBOX_WITH_GUEST_CONTROL */
3187}
3188
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