VirtualBox

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

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

Guest Control: Adjustments for supporting < 4.3 Guest Additions in conjunction with the new guest session, extended testcase (now passing using latest 4.2 Guest Additions with latest trunk).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use