VirtualBox

source: vbox/trunk/src/VBox/Main/USBControllerImpl.cpp@ 16524

Last change on this file since 16524 was 15829, checked in by vboxsync, 16 years ago

#3285: Improve error handling API to include unique error numbers

  • Make code match documentation.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.5 KB
Line 
1/* $Id: USBControllerImpl.cpp 15829 2009-01-07 11:17:56Z vboxsync $ */
2/** @file
3 * Implementation of IUSBController.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#include "USBControllerImpl.h"
23
24#include "Global.h"
25#include "MachineImpl.h"
26#include "VirtualBoxImpl.h"
27#include "HostImpl.h"
28#ifdef VBOX_WITH_USB
29# include "USBDeviceImpl.h"
30# include "HostUSBDeviceImpl.h"
31# include "USBProxyService.h"
32#endif
33#include "Logging.h"
34
35
36#include <iprt/string.h>
37#include <iprt/cpputils.h>
38#include <VBox/err.h>
39
40#include <algorithm>
41
42// defines
43/////////////////////////////////////////////////////////////////////////////
44
45// constructor / destructor
46/////////////////////////////////////////////////////////////////////////////
47
48DEFINE_EMPTY_CTOR_DTOR (USBController)
49
50HRESULT USBController::FinalConstruct()
51{
52 return S_OK;
53}
54
55void USBController::FinalRelease()
56{
57 uninit();
58}
59
60// public initializer/uninitializer for internal purposes only
61/////////////////////////////////////////////////////////////////////////////
62
63/**
64 * Initializes the USB controller object.
65 *
66 * @returns COM result indicator.
67 * @param aParent Pointer to our parent object.
68 */
69HRESULT USBController::init (Machine *aParent)
70{
71 LogFlowThisFunc (("aParent=%p\n", aParent));
72
73 ComAssertRet (aParent, E_INVALIDARG);
74
75 /* Enclose the state transition NotReady->InInit->Ready */
76 AutoInitSpan autoInitSpan (this);
77 AssertReturn (autoInitSpan.isOk(), E_FAIL);
78
79 unconst (mParent) = aParent;
80 /* mPeer is left null */
81
82 mData.allocate();
83#ifdef VBOX_WITH_USB
84 mDeviceFilters.allocate();
85#endif
86
87 /* Confirm a successful initialization */
88 autoInitSpan.setSucceeded();
89
90 return S_OK;
91}
92
93/**
94 * Initializes the USB controller object given another USB controller object
95 * (a kind of copy constructor). This object shares data with
96 * the object passed as an argument.
97 *
98 * @returns COM result indicator.
99 * @param aParent Pointer to our parent object.
100 * @param aPeer The object to share.
101 *
102 * @note This object must be destroyed before the original object
103 * it shares data with is destroyed.
104 */
105HRESULT USBController::init (Machine *aParent, USBController *aPeer)
106{
107 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
108
109 ComAssertRet (aParent && aPeer, E_INVALIDARG);
110
111 /* Enclose the state transition NotReady->InInit->Ready */
112 AutoInitSpan autoInitSpan (this);
113 AssertReturn (autoInitSpan.isOk(), E_FAIL);
114
115 unconst (mParent) = aParent;
116 unconst (mPeer) = aPeer;
117
118 AutoWriteLock thatlock (aPeer);
119 mData.share (aPeer->mData);
120
121#ifdef VBOX_WITH_USB
122 /* create copies of all filters */
123 mDeviceFilters.allocate();
124 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
125 while (it != aPeer->mDeviceFilters->end())
126 {
127 ComObjPtr <USBDeviceFilter> filter;
128 filter.createObject();
129 filter->init (this, *it);
130 mDeviceFilters->push_back (filter);
131 ++ it;
132 }
133#endif /* VBOX_WITH_USB */
134
135 /* Confirm a successful initialization */
136 autoInitSpan.setSucceeded();
137
138 return S_OK;
139}
140
141
142/**
143 * Initializes the USB controller object given another guest object
144 * (a kind of copy constructor). This object makes a private copy of data
145 * of the original object passed as an argument.
146 */
147HRESULT USBController::initCopy (Machine *aParent, USBController *aPeer)
148{
149 LogFlowThisFunc (("aParent=%p, aPeer=%p\n", aParent, aPeer));
150
151 ComAssertRet (aParent && aPeer, E_INVALIDARG);
152
153 /* Enclose the state transition NotReady->InInit->Ready */
154 AutoInitSpan autoInitSpan (this);
155 AssertReturn (autoInitSpan.isOk(), E_FAIL);
156
157 unconst (mParent) = aParent;
158 /* mPeer is left null */
159
160 AutoWriteLock thatlock (aPeer);
161 mData.attachCopy (aPeer->mData);
162
163#ifdef VBOX_WITH_USB
164 /* create private copies of all filters */
165 mDeviceFilters.allocate();
166 DeviceFilterList::const_iterator it = aPeer->mDeviceFilters->begin();
167 while (it != aPeer->mDeviceFilters->end())
168 {
169 ComObjPtr <USBDeviceFilter> filter;
170 filter.createObject();
171 filter->initCopy (this, *it);
172 mDeviceFilters->push_back (filter);
173 ++ it;
174 }
175#endif /* VBOX_WITH_USB */
176
177 /* Confirm a successful initialization */
178 autoInitSpan.setSucceeded();
179
180 return S_OK;
181}
182
183
184/**
185 * Uninitializes the instance and sets the ready flag to FALSE.
186 * Called either from FinalRelease() or by the parent when it gets destroyed.
187 */
188void USBController::uninit()
189{
190 LogFlowThisFunc (("\n"));
191
192 /* Enclose the state transition Ready->InUninit->NotReady */
193 AutoUninitSpan autoUninitSpan (this);
194 if (autoUninitSpan.uninitDone())
195 return;
196
197 /* uninit all filters (including those still referenced by clients) */
198 uninitDependentChildren();
199
200#ifdef VBOX_WITH_USB
201 mDeviceFilters.free();
202#endif
203 mData.free();
204
205 unconst (mPeer).setNull();
206 unconst (mParent).setNull();
207}
208
209
210// IUSBController properties
211/////////////////////////////////////////////////////////////////////////////
212
213STDMETHODIMP USBController::COMGETTER(Enabled) (BOOL *aEnabled)
214{
215 CheckComArgOutPointerValid(aEnabled);
216
217 AutoCaller autoCaller (this);
218 CheckComRCReturnRC (autoCaller.rc());
219
220 AutoReadLock alock (this);
221
222 *aEnabled = mData->mEnabled;
223
224 return S_OK;
225}
226
227
228STDMETHODIMP USBController::COMSETTER(Enabled) (BOOL aEnabled)
229{
230 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
231
232 AutoCaller autoCaller (this);
233 CheckComRCReturnRC (autoCaller.rc());
234
235 /* the machine needs to be mutable */
236 Machine::AutoMutableStateDependency adep (mParent);
237 CheckComRCReturnRC (adep.rc());
238
239 AutoWriteLock alock (this);
240
241 if (mData->mEnabled != aEnabled)
242 {
243 mData.backup();
244 mData->mEnabled = aEnabled;
245
246 /* leave the lock for safety */
247 alock.leave();
248
249 mParent->onUSBControllerChange();
250 }
251
252 return S_OK;
253}
254
255STDMETHODIMP USBController::COMGETTER(EnabledEhci) (BOOL *aEnabled)
256{
257 CheckComArgOutPointerValid(aEnabled);
258
259 AutoCaller autoCaller (this);
260 CheckComRCReturnRC (autoCaller.rc());
261
262 AutoReadLock alock (this);
263
264 *aEnabled = mData->mEnabledEhci;
265
266 return S_OK;
267}
268
269STDMETHODIMP USBController::COMSETTER(EnabledEhci) (BOOL aEnabled)
270{
271 LogFlowThisFunc (("aEnabled=%RTbool\n", aEnabled));
272
273 AutoCaller autoCaller (this);
274 CheckComRCReturnRC (autoCaller.rc());
275
276 /* the machine needs to be mutable */
277 Machine::AutoMutableStateDependency adep (mParent);
278 CheckComRCReturnRC (adep.rc());
279
280 AutoWriteLock alock (this);
281
282 if (mData->mEnabledEhci != aEnabled)
283 {
284 mData.backup();
285 mData->mEnabledEhci = aEnabled;
286
287 /* leave the lock for safety */
288 alock.leave();
289
290 mParent->onUSBControllerChange();
291 }
292
293 return S_OK;
294}
295
296STDMETHODIMP USBController::COMGETTER(USBStandard) (USHORT *aUSBStandard)
297{
298 CheckComArgOutPointerValid(aUSBStandard);
299
300 AutoCaller autoCaller (this);
301 CheckComRCReturnRC (autoCaller.rc());
302
303 /* not accessing data -- no need to lock */
304
305 /** @todo This is no longer correct */
306 *aUSBStandard = 0x0101;
307
308 return S_OK;
309}
310
311#ifndef VBOX_WITH_USB
312/**
313 * Fake class for build without USB.
314 * We need an empty collection & enum for deviceFilters, that's all.
315 */
316class ATL_NO_VTABLE USBDeviceFilter :
317 public VirtualBoxBaseNEXT,
318 public VirtualBoxSupportErrorInfoImpl <USBDeviceFilter, IUSBDeviceFilter>,
319 public VirtualBoxSupportTranslation <USBDeviceFilter>,
320 public IUSBDeviceFilter
321{
322public:
323 DECLARE_NOT_AGGREGATABLE(USBDeviceFilter)
324 DECLARE_PROTECT_FINAL_CONSTRUCT()
325 BEGIN_COM_MAP(USBDeviceFilter)
326 COM_INTERFACE_ENTRY(ISupportErrorInfo)
327 COM_INTERFACE_ENTRY(IUSBDeviceFilter)
328 END_COM_MAP()
329
330 NS_DECL_ISUPPORTS
331
332 DECLARE_EMPTY_CTOR_DTOR (USBDeviceFilter)
333
334 // IUSBDeviceFilter properties
335 STDMETHOD(COMGETTER(Name)) (BSTR *aName);
336 STDMETHOD(COMSETTER(Name)) (IN_BSTR aName);
337 STDMETHOD(COMGETTER(Active)) (BOOL *aActive);
338 STDMETHOD(COMSETTER(Active)) (BOOL aActive);
339 STDMETHOD(COMGETTER(VendorId)) (BSTR *aVendorId);
340 STDMETHOD(COMSETTER(VendorId)) (IN_BSTR aVendorId);
341 STDMETHOD(COMGETTER(ProductId)) (BSTR *aProductId);
342 STDMETHOD(COMSETTER(ProductId)) (IN_BSTR aProductId);
343 STDMETHOD(COMGETTER(Revision)) (BSTR *aRevision);
344 STDMETHOD(COMSETTER(Revision)) (IN_BSTR aRevision);
345 STDMETHOD(COMGETTER(Manufacturer)) (BSTR *aManufacturer);
346 STDMETHOD(COMSETTER(Manufacturer)) (IN_BSTR aManufacturer);
347 STDMETHOD(COMGETTER(Product)) (BSTR *aProduct);
348 STDMETHOD(COMSETTER(Product)) (IN_BSTR aProduct);
349 STDMETHOD(COMGETTER(SerialNumber)) (BSTR *aSerialNumber);
350 STDMETHOD(COMSETTER(SerialNumber)) (IN_BSTR aSerialNumber);
351 STDMETHOD(COMGETTER(Port)) (BSTR *aPort);
352 STDMETHOD(COMSETTER(Port)) (IN_BSTR aPort);
353 STDMETHOD(COMGETTER(Remote)) (BSTR *aRemote);
354 STDMETHOD(COMSETTER(Remote)) (IN_BSTR aRemote);
355 STDMETHOD(COMGETTER(MaskedInterfaces)) (ULONG *aMaskedIfs);
356 STDMETHOD(COMSETTER(MaskedInterfaces)) (ULONG aMaskedIfs);
357};
358COM_DECL_READONLY_ENUM_AND_COLLECTION (USBDeviceFilter);
359COM_IMPL_READONLY_ENUM_AND_COLLECTION (USBDeviceFilter);
360#endif /* !VBOX_WITH_USB */
361
362
363STDMETHODIMP USBController::COMGETTER(DeviceFilters) (IUSBDeviceFilterCollection **aDevicesFilters)
364{
365 CheckComArgOutPointerValid(aDevicesFilters);
366
367 AutoCaller autoCaller (this);
368 CheckComRCReturnRC (autoCaller.rc());
369
370 AutoReadLock alock (this);
371
372 ComObjPtr <USBDeviceFilterCollection> collection;
373 collection.createObject();
374#ifdef VBOX_WITH_USB
375 collection->init (*mDeviceFilters.data());
376#endif
377 collection.queryInterfaceTo (aDevicesFilters);
378
379 return S_OK;
380}
381
382// IUSBController methods
383/////////////////////////////////////////////////////////////////////////////
384
385STDMETHODIMP USBController::CreateDeviceFilter (IN_BSTR aName,
386 IUSBDeviceFilter **aFilter)
387{
388#ifdef VBOX_WITH_USB
389 CheckComArgOutPointerValid(aFilter);
390
391 CheckComArgStrNotEmptyOrNull(aName);
392
393 AutoCaller autoCaller (this);
394 CheckComRCReturnRC (autoCaller.rc());
395
396 /* the machine needs to be mutable */
397 Machine::AutoMutableStateDependency adep (mParent);
398 CheckComRCReturnRC (adep.rc());
399
400 AutoWriteLock alock (this);
401
402 ComObjPtr <USBDeviceFilter> filter;
403 filter.createObject();
404 HRESULT rc = filter->init (this, aName);
405 ComAssertComRCRetRC (rc);
406 rc = filter.queryInterfaceTo (aFilter);
407 AssertComRCReturnRC (rc);
408
409 return S_OK;
410#else
411 ReturnComNotImplemented();
412#endif
413}
414
415STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
416 IUSBDeviceFilter *aFilter)
417{
418#ifdef VBOX_WITH_USB
419
420 CheckComArgNotNull(aFilter);
421
422 AutoCaller autoCaller (this);
423 CheckComRCReturnRC (autoCaller.rc());
424
425 /* the machine needs to be mutable */
426 Machine::AutoMutableStateDependency adep (mParent);
427 CheckComRCReturnRC (adep.rc());
428
429 AutoWriteLock alock (this);
430
431 ComObjPtr <USBDeviceFilter> filter = getDependentChild (aFilter);
432 if (!filter)
433 return setError (E_INVALIDARG,
434 tr ("The given USB device filter is not created within "
435 "this VirtualBox instance"));
436
437 if (filter->mInList)
438 return setError (VBOX_E_INVALID_OBJECT_STATE,
439 tr ("The given USB device filter is already in the list"));
440
441 /* backup the list before modification */
442 mDeviceFilters.backup();
443
444 /* iterate to the position... */
445 DeviceFilterList::iterator it;
446 if (aPosition < mDeviceFilters->size())
447 {
448 it = mDeviceFilters->begin();
449 std::advance (it, aPosition);
450 }
451 else
452 it = mDeviceFilters->end();
453 /* ...and insert */
454 mDeviceFilters->insert (it, filter);
455 filter->mInList = true;
456
457 /* notify the proxy (only when it makes sense) */
458 if (filter->data().mActive && Global::IsOnline (adep.machineState()))
459 {
460 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
461 ComAssertRet (service, E_FAIL);
462
463 ComAssertRet (filter->id() == NULL, E_FAIL);
464 filter->id() = service->insertFilter (&filter->data().mUSBFilter);
465 }
466
467 return S_OK;
468
469#else /* VBOX_WITH_USB */
470
471 ReturnComNotImplemented();
472
473#endif /* VBOX_WITH_USB */
474}
475
476STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
477 IUSBDeviceFilter **aFilter)
478{
479#ifdef VBOX_WITH_USB
480
481 CheckComArgOutPointerValid(aFilter);
482
483 AutoCaller autoCaller (this);
484 CheckComRCReturnRC (autoCaller.rc());
485
486 /* the machine needs to be mutable */
487 Machine::AutoMutableStateDependency adep (mParent);
488 CheckComRCReturnRC (adep.rc());
489
490 AutoWriteLock alock (this);
491
492 if (!mDeviceFilters->size())
493 return setError (E_INVALIDARG,
494 tr ("The USB device filter list is empty"));
495
496 if (aPosition >= mDeviceFilters->size())
497 return setError (E_INVALIDARG,
498 tr ("Invalid position: %lu (must be in range [0, %lu])"),
499 aPosition, mDeviceFilters->size() - 1);
500
501 /* backup the list before modification */
502 mDeviceFilters.backup();
503
504 ComObjPtr <USBDeviceFilter> filter;
505 {
506 /* iterate to the position... */
507 DeviceFilterList::iterator it = mDeviceFilters->begin();
508 std::advance (it, aPosition);
509 /* ...get an element from there... */
510 filter = *it;
511 /* ...and remove */
512 filter->mInList = false;
513 mDeviceFilters->erase (it);
514 }
515
516 /* cancel sharing (make an independent copy of data) */
517 filter->unshare();
518
519 filter.queryInterfaceTo (aFilter);
520
521 /* notify the proxy (only when it makes sense) */
522 if (filter->data().mActive && Global::IsOnline (adep.machineState()))
523 {
524 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
525 ComAssertRet (service, E_FAIL);
526
527 ComAssertRet (filter->id() != NULL, E_FAIL);
528 service->removeFilter (filter->id());
529 filter->id() = NULL;
530 }
531
532 return S_OK;
533
534#else /* VBOX_WITH_USB */
535
536 ReturnComNotImplemented();
537
538#endif /* VBOX_WITH_USB */
539}
540
541// public methods only for internal purposes
542/////////////////////////////////////////////////////////////////////////////
543
544/**
545 * Loads settings from the given machine node.
546 * May be called once right after this object creation.
547 *
548 * @param aMachineNode <Machine> node.
549 *
550 * @note Locks this object for writing.
551 */
552HRESULT USBController::loadSettings (const settings::Key &aMachineNode)
553{
554 using namespace settings;
555
556 AssertReturn (!aMachineNode.isNull(), E_FAIL);
557
558 AutoCaller autoCaller (this);
559 AssertComRCReturnRC (autoCaller.rc());
560
561 AutoWriteLock alock (this);
562
563 /* Note: we assume that the default values for attributes of optional
564 * nodes are assigned in the Data::Data() constructor and don't do it
565 * here. It implies that this method may only be called after constructing
566 * a new BIOSSettings object while all its data fields are in the default
567 * values. Exceptions are fields whose creation time defaults don't match
568 * values that should be applied when these fields are not explicitly set
569 * in the settings file (for backwards compatibility reasons). This takes
570 * place when a setting of a newly created object must default to A while
571 * the same setting of an object loaded from the old settings file must
572 * default to B. */
573
574 /* USB Controller node (required) */
575 Key controller = aMachineNode.key ("USBController");
576
577 /* enabled (required) */
578 mData->mEnabled = controller.value <bool> ("enabled");
579
580 /* enabledEhci (optiona, defaults to false) */
581 mData->mEnabledEhci = controller.value <bool> ("enabledEhci");
582
583#ifdef VBOX_WITH_USB
584 HRESULT rc = S_OK;
585
586 Key::List children = controller.keys ("DeviceFilter");
587 for (Key::List::const_iterator it = children.begin();
588 it != children.end(); ++ it)
589 {
590 /* required */
591 Bstr name = (*it).stringValue ("name");
592 bool active = (*it).value <bool> ("active");
593
594 /* optional */
595 Bstr vendorId = (*it).stringValue ("vendorId");
596 Bstr productId = (*it).stringValue ("productId");
597 Bstr revision = (*it).stringValue ("revision");
598 Bstr manufacturer = (*it).stringValue ("manufacturer");
599 Bstr product = (*it).stringValue ("product");
600 Bstr serialNumber = (*it).stringValue ("serialNumber");
601 Bstr port = (*it).stringValue ("port");
602 Bstr remote = (*it).stringValue ("remote");
603 ULONG maskedIfs = (*it).value <ULONG> ("maskedInterfaces");
604
605 ComObjPtr <USBDeviceFilter> filterObj;
606 filterObj.createObject();
607 rc = filterObj->init (this,
608 name, active, vendorId, productId, revision,
609 manufacturer, product, serialNumber,
610 port, remote, maskedIfs);
611 /* error info is set by init() when appropriate */
612 CheckComRCReturnRC (rc);
613
614 mDeviceFilters->push_back (filterObj);
615 filterObj->mInList = true;
616 }
617#endif /* VBOX_WITH_USB */
618
619 return S_OK;
620}
621
622/**
623 * Saves settings to the given machine node.
624 *
625 * @param aMachineNode <Machine> node.
626 *
627 * @note Locks this object for reading.
628 */
629HRESULT USBController::saveSettings (settings::Key &aMachineNode)
630{
631 using namespace settings;
632
633 AssertReturn (!aMachineNode.isNull(), E_FAIL);
634
635 AutoCaller autoCaller (this);
636 CheckComRCReturnRC (autoCaller.rc());
637
638 AutoReadLock alock (this);
639
640 /* first, delete the entry */
641 Key controller = aMachineNode.findKey ("USBController");
642#ifdef VBOX_WITH_USB
643 if (!controller.isNull())
644 controller.zap();
645 /* then, recreate it */
646 controller = aMachineNode.createKey ("USBController");
647#else
648 /* don't zap it. */
649 if (controller.isNull())
650 controller = aMachineNode.createKey ("USBController");
651#endif
652
653 /* enabled */
654 controller.setValue <bool> ("enabled", !!mData->mEnabled);
655
656 /* enabledEhci */
657 controller.setValue <bool> ("enabledEhci", !!mData->mEnabledEhci);
658
659#ifdef VBOX_WITH_USB
660 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
661 while (it != mDeviceFilters->end())
662 {
663 AutoWriteLock filterLock (*it);
664 const USBDeviceFilter::Data &data = (*it)->data();
665
666 Key filter = controller.appendKey ("DeviceFilter");
667
668 filter.setValue <Bstr> ("name", data.mName);
669 filter.setValue <bool> ("active", !!data.mActive);
670
671 /* all are optional */
672 Bstr str;
673 (*it)->COMGETTER (VendorId) (str.asOutParam());
674 if (!str.isNull())
675 filter.setValue <Bstr> ("vendorId", str);
676
677 (*it)->COMGETTER (ProductId) (str.asOutParam());
678 if (!str.isNull())
679 filter.setValue <Bstr> ("productId", str);
680
681 (*it)->COMGETTER (Revision) (str.asOutParam());
682 if (!str.isNull())
683 filter.setValue <Bstr> ("revision", str);
684
685 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
686 if (!str.isNull())
687 filter.setValue <Bstr> ("manufacturer", str);
688
689 (*it)->COMGETTER (Product) (str.asOutParam());
690 if (!str.isNull())
691 filter.setValue <Bstr> ("product", str);
692
693 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
694 if (!str.isNull())
695 filter.setValue <Bstr> ("serialNumber", str);
696
697 (*it)->COMGETTER (Port) (str.asOutParam());
698 if (!str.isNull())
699 filter.setValue <Bstr> ("port", str);
700
701 if (data.mRemote.string())
702 filter.setValue <Bstr> ("remote", data.mRemote.string());
703
704 if (data.mMaskedIfs)
705 filter.setValue <ULONG> ("maskedInterfaces", data.mMaskedIfs);
706
707 ++ it;
708 }
709#endif /* VBOX_WITH_USB */
710
711 return S_OK;
712}
713
714/** @note Locks objects for reading! */
715bool USBController::isModified()
716{
717 AutoCaller autoCaller (this);
718 AssertComRCReturn (autoCaller.rc(), false);
719
720 AutoReadLock alock (this);
721
722 if (mData.isBackedUp()
723#ifdef VBOX_WITH_USB
724 || mDeviceFilters.isBackedUp()
725#endif
726 )
727 return true;
728
729#ifdef VBOX_WITH_USB
730 /* see whether any of filters has changed its data */
731 for (DeviceFilterList::const_iterator
732 it = mDeviceFilters->begin();
733 it != mDeviceFilters->end();
734 ++ it)
735 {
736 if ((*it)->isModified())
737 return true;
738 }
739#endif /* VBOX_WITH_USB */
740
741 return false;
742}
743
744/** @note Locks objects for reading! */
745bool USBController::isReallyModified()
746{
747 AutoCaller autoCaller (this);
748 AssertComRCReturn (autoCaller.rc(), false);
749
750 AutoReadLock alock (this);
751
752 if (mData.hasActualChanges())
753 return true;
754
755#ifdef VBOX_WITH_USB
756 if (!mDeviceFilters.isBackedUp())
757 {
758 /* see whether any of filters has changed its data */
759 for (DeviceFilterList::const_iterator
760 it = mDeviceFilters->begin();
761 it != mDeviceFilters->end();
762 ++ it)
763 {
764 if ((*it)->isReallyModified())
765 return true;
766 }
767
768 return false;
769 }
770
771 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
772 return true;
773
774 if (mDeviceFilters->size() == 0)
775 return false;
776
777 /* Make copies to speed up comparison */
778 DeviceFilterList devices = *mDeviceFilters.data();
779 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
780
781 DeviceFilterList::iterator it = devices.begin();
782 while (it != devices.end())
783 {
784 bool found = false;
785 DeviceFilterList::iterator thatIt = backDevices.begin();
786 while (thatIt != backDevices.end())
787 {
788 if ((*it)->data() == (*thatIt)->data())
789 {
790 backDevices.erase (thatIt);
791 found = true;
792 break;
793 }
794 else
795 ++ thatIt;
796 }
797 if (found)
798 it = devices.erase (it);
799 else
800 return false;
801 }
802
803 Assert (devices.size() == 0 && backDevices.size() == 0);
804#endif /* VBOX_WITH_USB */
805
806 return false;
807}
808
809/** @note Locks objects for writing! */
810bool USBController::rollback()
811{
812 AutoCaller autoCaller (this);
813 AssertComRCReturn (autoCaller.rc(), false);
814
815 /* we need the machine state */
816 Machine::AutoAnyStateDependency adep (mParent);
817 AssertComRCReturn (adep.rc(), false);
818
819 AutoWriteLock alock (this);
820
821 bool dataChanged = false;
822
823 if (mData.isBackedUp())
824 {
825 /* we need to check all data to see whether anything will be changed
826 * after rollback */
827 dataChanged = mData.hasActualChanges();
828 mData.rollback();
829 }
830
831#ifdef VBOX_WITH_USB
832
833 if (mDeviceFilters.isBackedUp())
834 {
835 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
836 ComAssertRet (service, false);
837
838 /* uninitialize all new filters (absent in the backed up list) */
839 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
840 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
841 while (it != mDeviceFilters->end())
842 {
843 if (std::find (backedList->begin(), backedList->end(), *it) ==
844 backedList->end())
845 {
846 /* notify the proxy (only when it makes sense) */
847 if ((*it)->data().mActive &&
848 Global::IsOnline (adep.machineState()))
849 {
850 USBDeviceFilter *filter = *it;
851 ComAssertRet (filter->id() != NULL, false);
852 service->removeFilter (filter->id());
853 filter->id() = NULL;
854 }
855
856 (*it)->uninit();
857 }
858 ++ it;
859 }
860
861 if (Global::IsOnline (adep.machineState()))
862 {
863 /* find all removed old filters (absent in the new list)
864 * and insert them back to the USB proxy */
865 it = backedList->begin();
866 while (it != backedList->end())
867 {
868 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
869 mDeviceFilters->end())
870 {
871 /* notify the proxy (only when necessary) */
872 if ((*it)->data().mActive)
873 {
874 USBDeviceFilter *flt = *it; /* resolve ambiguity */
875 ComAssertRet (flt->id() == NULL, false);
876 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
877 }
878 }
879 ++ it;
880 }
881 }
882
883 /* restore the list */
884 mDeviceFilters.rollback();
885 }
886
887 /* here we don't depend on the machine state any more */
888 adep.release();
889
890 /* rollback any changes to filters after restoring the list */
891 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
892 while (it != mDeviceFilters->end())
893 {
894 if ((*it)->isModified())
895 {
896 (*it)->rollback();
897 /* call this to notify the USB proxy about changes */
898 onDeviceFilterChange (*it);
899 }
900 ++ it;
901 }
902
903#endif /* VBOX_WITH_USB */
904
905 return dataChanged;
906}
907
908/**
909 * @note Locks this object for writing, together with the peer object (also
910 * for writing) if there is one.
911 */
912void USBController::commit()
913{
914 /* sanity */
915 AutoCaller autoCaller (this);
916 AssertComRCReturnVoid (autoCaller.rc());
917
918 /* sanity too */
919 AutoCaller peerCaller (mPeer);
920 AssertComRCReturnVoid (peerCaller.rc());
921
922 /* lock both for writing since we modify both (mPeer is "master" so locked
923 * first) */
924 AutoMultiWriteLock2 alock (mPeer, this);
925
926 if (mData.isBackedUp())
927 {
928 mData.commit();
929 if (mPeer)
930 {
931 /* attach new data to the peer and reshare it */
932 AutoWriteLock peerlock (mPeer);
933 mPeer->mData.attach (mData);
934 }
935 }
936
937#ifdef VBOX_WITH_USB
938 bool commitFilters = false;
939
940 if (mDeviceFilters.isBackedUp())
941 {
942 mDeviceFilters.commit();
943
944 /* apply changes to peer */
945 if (mPeer)
946 {
947 AutoWriteLock peerlock (mPeer);
948
949 /* commit all changes to new filters (this will reshare data with
950 * peers for those who have peers) */
951 DeviceFilterList *newList = new DeviceFilterList();
952 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
953 while (it != mDeviceFilters->end())
954 {
955 (*it)->commit();
956
957 /* look if this filter has a peer filter */
958 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
959 if (!peer)
960 {
961 /* no peer means the filter is a newly created one;
962 * create a peer owning data this filter share it with */
963 peer.createObject();
964 peer->init (mPeer, *it, true /* aReshare */);
965 }
966 else
967 {
968 /* remove peer from the old list */
969 mPeer->mDeviceFilters->remove (peer);
970 }
971 /* and add it to the new list */
972 newList->push_back (peer);
973
974 ++ it;
975 }
976
977 /* uninit old peer's filters that are left */
978 it = mPeer->mDeviceFilters->begin();
979 while (it != mPeer->mDeviceFilters->end())
980 {
981 (*it)->uninit();
982 ++ it;
983 }
984
985 /* attach new list of filters to our peer */
986 mPeer->mDeviceFilters.attach (newList);
987 }
988 else
989 {
990 /* we have no peer (our parent is the newly created machine);
991 * just commit changes to filters */
992 commitFilters = true;
993 }
994 }
995 else
996 {
997 /* the list of filters itself is not changed,
998 * just commit changes to filters themselves */
999 commitFilters = true;
1000 }
1001
1002 if (commitFilters)
1003 {
1004 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1005 while (it != mDeviceFilters->end())
1006 {
1007 (*it)->commit();
1008 ++ it;
1009 }
1010 }
1011#endif /* VBOX_WITH_USB */
1012}
1013
1014/**
1015 * @note Locks this object for writing, together with the peer object
1016 * represented by @a aThat (locked for reading).
1017 */
1018void USBController::copyFrom (USBController *aThat)
1019{
1020 AssertReturnVoid (aThat != NULL);
1021
1022 /* sanity */
1023 AutoCaller autoCaller (this);
1024 AssertComRCReturnVoid (autoCaller.rc());
1025
1026 /* sanity too */
1027 AutoCaller thatCaller (aThat);
1028 AssertComRCReturnVoid (thatCaller.rc());
1029
1030 /* even more sanity */
1031 Machine::AutoAnyStateDependency adep (mParent);
1032 AssertComRCReturnVoid (adep.rc());
1033 /* Machine::copyFrom() may not be called when the VM is running */
1034 AssertReturnVoid (!Global::IsOnline (adep.machineState()));
1035
1036 /* peer is not modified, lock it for reading (aThat is "master" so locked
1037 * first) */
1038 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1039
1040 /* this will back up current data */
1041 mData.assignCopy (aThat->mData);
1042
1043#ifdef VBOX_WITH_USB
1044
1045 /* Note that we won't inform the USB proxy about new filters since the VM is
1046 * not running when we are here and therefore no need to do so */
1047
1048 /* create private copies of all filters */
1049 mDeviceFilters.backup();
1050 mDeviceFilters->clear();
1051 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
1052 it != aThat->mDeviceFilters->end();
1053 ++ it)
1054 {
1055 ComObjPtr <USBDeviceFilter> filter;
1056 filter.createObject();
1057 filter->initCopy (this, *it);
1058 mDeviceFilters->push_back (filter);
1059 }
1060
1061#endif /* VBOX_WITH_USB */
1062}
1063
1064#ifdef VBOX_WITH_USB
1065
1066/**
1067 * Called by setter methods of all USB device filters.
1068 *
1069 * @note Locks nothing.
1070 */
1071HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
1072 BOOL aActiveChanged /* = FALSE */)
1073{
1074 AutoCaller autoCaller (this);
1075 AssertComRCReturnRC (autoCaller.rc());
1076
1077 /* we need the machine state */
1078 Machine::AutoAnyStateDependency adep (mParent);
1079 AssertComRCReturnRC (adep.rc());
1080
1081 /* nothing to do if the machine isn't running */
1082 if (!Global::IsOnline (adep.machineState()))
1083 return S_OK;
1084
1085 /* we don't modify our data fields -- no need to lock */
1086
1087 if (aFilter->mInList && mParent->isRegistered())
1088 {
1089 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1090 ComAssertRet (service, E_FAIL);
1091
1092 if (aActiveChanged)
1093 {
1094 /* insert/remove the filter from the proxy */
1095 if (aFilter->data().mActive)
1096 {
1097 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1098 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1099 }
1100 else
1101 {
1102 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1103 service->removeFilter (aFilter->id());
1104 aFilter->id() = NULL;
1105 }
1106 }
1107 else
1108 {
1109 if (aFilter->data().mActive)
1110 {
1111 /* update the filter in the proxy */
1112 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1113 service->removeFilter (aFilter->id());
1114 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1115 }
1116 }
1117 }
1118
1119 return S_OK;
1120}
1121
1122/**
1123 * Returns true if the given USB device matches to at least one of
1124 * this controller's USB device filters.
1125 *
1126 * A HostUSBDevice specific version.
1127 *
1128 * @note Locks this object for reading.
1129 */
1130bool USBController::hasMatchingFilter (const ComObjPtr <HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
1131{
1132 AutoCaller autoCaller (this);
1133 AssertComRCReturn (autoCaller.rc(), false);
1134
1135 AutoReadLock alock (this);
1136
1137 /* Disabled USB controllers cannot actually work with USB devices */
1138 if (!mData->mEnabled)
1139 return false;
1140
1141 /* apply self filters */
1142 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1143 it != mDeviceFilters->end();
1144 ++ it)
1145 {
1146 AutoWriteLock filterLock (*it);
1147 if (aDevice->isMatch ((*it)->data()))
1148 {
1149 *aMaskedIfs = (*it)->data().mMaskedIfs;
1150 return true;
1151 }
1152 }
1153
1154 return false;
1155}
1156
1157/**
1158 * Returns true if the given USB device matches to at least one of
1159 * this controller's USB device filters.
1160 *
1161 * A generic version that accepts any IUSBDevice on input.
1162 *
1163 * @note
1164 * This method MUST correlate with HostUSBDevice::isMatch()
1165 * in the sense of the device matching logic.
1166 *
1167 * @note Locks this object for reading.
1168 */
1169bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
1170{
1171 LogFlowThisFuncEnter();
1172
1173 AutoCaller autoCaller (this);
1174 AssertComRCReturn (autoCaller.rc(), false);
1175
1176 AutoReadLock alock (this);
1177
1178 /* Disabled USB controllers cannot actually work with USB devices */
1179 if (!mData->mEnabled)
1180 return false;
1181
1182 HRESULT rc = S_OK;
1183
1184 /* query fields */
1185 USBFILTER dev;
1186 USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);
1187
1188 USHORT vendorId = 0;
1189 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1190 ComAssertComRCRet (rc, false);
1191 ComAssertRet (vendorId, false);
1192 int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
1193
1194 USHORT productId = 0;
1195 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1196 ComAssertComRCRet (rc, false);
1197 ComAssertRet (productId, false);
1198 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
1199
1200 USHORT revision;
1201 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1202 ComAssertComRCRet (rc, false);
1203 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
1204
1205 Bstr manufacturer;
1206 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1207 ComAssertComRCRet (rc, false);
1208 if (!manufacturer.isNull())
1209 USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer), true);
1210
1211 Bstr product;
1212 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1213 ComAssertComRCRet (rc, false);
1214 if (!product.isNull())
1215 USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product), true);
1216
1217 Bstr serialNumber;
1218 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1219 ComAssertComRCRet (rc, false);
1220 if (!serialNumber.isNull())
1221 USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber), true);
1222
1223 Bstr address;
1224 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1225 ComAssertComRCRet (rc, false);
1226
1227 USHORT port = 0;
1228 rc = aUSBDevice->COMGETTER(Port)(&port);
1229 ComAssertComRCRet (rc, false);
1230 USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);
1231
1232 BOOL remote = FALSE;
1233 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1234 ComAssertComRCRet (rc, false);
1235 ComAssertRet (remote == TRUE, false);
1236
1237 bool match = false;
1238
1239 /* apply self filters */
1240 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1241 it != mDeviceFilters->end();
1242 ++ it)
1243 {
1244 AutoWriteLock filterLock (*it);
1245 const USBDeviceFilter::Data &aData = (*it)->data();
1246
1247 if (!aData.mActive)
1248 continue;
1249 if (!aData.mRemote.isMatch (remote))
1250 continue;
1251 if (!USBFilterMatch (&aData.mUSBFilter, &dev))
1252 continue;
1253
1254 match = true;
1255 *aMaskedIfs = aData.mMaskedIfs;
1256 break;
1257 }
1258
1259 LogFlowThisFunc (("returns: %d\n", match));
1260 LogFlowThisFuncLeave();
1261
1262 return match;
1263}
1264
1265/**
1266 * Notifies the proxy service about all filters as requested by the
1267 * @a aInsertFilters argument.
1268 *
1269 * @param aInsertFilters @c true to insert filters, @c false to remove.
1270 *
1271 * @note Locks this object for reading.
1272 */
1273HRESULT USBController::notifyProxy (bool aInsertFilters)
1274{
1275 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1276
1277 AutoCaller autoCaller (this);
1278 AssertComRCReturn (autoCaller.rc(), false);
1279
1280 AutoReadLock alock (this);
1281
1282 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1283 AssertReturn (service, E_FAIL);
1284
1285 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1286 while (it != mDeviceFilters->end())
1287 {
1288 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1289
1290 /* notify the proxy (only if the filter is active) */
1291 if (flt->data().mActive)
1292 {
1293 if (aInsertFilters)
1294 {
1295 AssertReturn (flt->id() == NULL, E_FAIL);
1296 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
1297 }
1298 else
1299 {
1300 /* It's possible that the given filter was not inserted the proxy
1301 * when this method gets called (as a result of an early VM
1302 * process crash for example. So, don't assert that ID != NULL. */
1303 if (flt->id() != NULL)
1304 {
1305 service->removeFilter (flt->id());
1306 flt->id() = NULL;
1307 }
1308 }
1309 }
1310 ++ it;
1311 }
1312
1313 return S_OK;
1314}
1315
1316#endif /* VBOX_WITH_USB */
1317
1318// private methods
1319/////////////////////////////////////////////////////////////////////////////
1320/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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