VirtualBox

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

Last change on this file since 47764 was 47764, checked in by vboxsync, 12 years ago

Committed too much.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette