VirtualBox

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

Last change on this file since 15245 was 15157, checked in by vboxsync, 16 years ago

Main: #3312: Fixed a wrong assertion in USBController triggered on a failure to revert to the current snapshot (hidden regression after rewriting USB support for Windows)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 KB
Line 
1/* $Id: USBControllerImpl.cpp 15157 2008-12-09 11:39:21Z 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
23
24#include "USBControllerImpl.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 (E_INVALIDARG,
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 && adep.machineState() >= MachineState_Running)
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 && adep.machineState() >= MachineState_Running)
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 adep.machineState() >= MachineState_Running &&
849 adep.machineState() < MachineState_Discarding)
850 {
851 USBDeviceFilter *filter = *it;
852 ComAssertRet (filter->id() != NULL, false);
853 service->removeFilter (filter->id());
854 filter->id() = NULL;
855 }
856
857 (*it)->uninit();
858 }
859 ++ it;
860 }
861
862 if (adep.machineState() >= MachineState_Running &&
863 adep.machineState() < MachineState_Discarding)
864 {
865 /* find all removed old filters (absent in the new list)
866 * and insert them back to the USB proxy */
867 it = backedList->begin();
868 while (it != backedList->end())
869 {
870 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
871 mDeviceFilters->end())
872 {
873 /* notify the proxy (only when necessary) */
874 if ((*it)->data().mActive)
875 {
876 USBDeviceFilter *flt = *it; /* resolve ambiguity */
877 ComAssertRet (flt->id() == NULL, false);
878 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
879 }
880 }
881 ++ it;
882 }
883 }
884
885 /* restore the list */
886 mDeviceFilters.rollback();
887 }
888
889 /* here we don't depend on the machine state any more */
890 adep.release();
891
892 /* rollback any changes to filters after restoring the list */
893 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
894 while (it != mDeviceFilters->end())
895 {
896 if ((*it)->isModified())
897 {
898 (*it)->rollback();
899 /* call this to notify the USB proxy about changes */
900 onDeviceFilterChange (*it);
901 }
902 ++ it;
903 }
904
905#endif /* VBOX_WITH_USB */
906
907 return dataChanged;
908}
909
910/**
911 * @note Locks this object for writing, together with the peer object (also
912 * for writing) if there is one.
913 */
914void USBController::commit()
915{
916 /* sanity */
917 AutoCaller autoCaller (this);
918 AssertComRCReturnVoid (autoCaller.rc());
919
920 /* sanity too */
921 AutoCaller peerCaller (mPeer);
922 AssertComRCReturnVoid (peerCaller.rc());
923
924 /* lock both for writing since we modify both (mPeer is "master" so locked
925 * first) */
926 AutoMultiWriteLock2 alock (mPeer, this);
927
928 if (mData.isBackedUp())
929 {
930 mData.commit();
931 if (mPeer)
932 {
933 /* attach new data to the peer and reshare it */
934 AutoWriteLock peerlock (mPeer);
935 mPeer->mData.attach (mData);
936 }
937 }
938
939#ifdef VBOX_WITH_USB
940 bool commitFilters = false;
941
942 if (mDeviceFilters.isBackedUp())
943 {
944 mDeviceFilters.commit();
945
946 /* apply changes to peer */
947 if (mPeer)
948 {
949 AutoWriteLock peerlock (mPeer);
950
951 /* commit all changes to new filters (this will reshare data with
952 * peers for those who have peers) */
953 DeviceFilterList *newList = new DeviceFilterList();
954 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
955 while (it != mDeviceFilters->end())
956 {
957 (*it)->commit();
958
959 /* look if this filter has a peer filter */
960 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
961 if (!peer)
962 {
963 /* no peer means the filter is a newly created one;
964 * create a peer owning data this filter share it with */
965 peer.createObject();
966 peer->init (mPeer, *it, true /* aReshare */);
967 }
968 else
969 {
970 /* remove peer from the old list */
971 mPeer->mDeviceFilters->remove (peer);
972 }
973 /* and add it to the new list */
974 newList->push_back (peer);
975
976 ++ it;
977 }
978
979 /* uninit old peer's filters that are left */
980 it = mPeer->mDeviceFilters->begin();
981 while (it != mPeer->mDeviceFilters->end())
982 {
983 (*it)->uninit();
984 ++ it;
985 }
986
987 /* attach new list of filters to our peer */
988 mPeer->mDeviceFilters.attach (newList);
989 }
990 else
991 {
992 /* we have no peer (our parent is the newly created machine);
993 * just commit changes to filters */
994 commitFilters = true;
995 }
996 }
997 else
998 {
999 /* the list of filters itself is not changed,
1000 * just commit changes to filters themselves */
1001 commitFilters = true;
1002 }
1003
1004 if (commitFilters)
1005 {
1006 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1007 while (it != mDeviceFilters->end())
1008 {
1009 (*it)->commit();
1010 ++ it;
1011 }
1012 }
1013#endif /* VBOX_WITH_USB */
1014}
1015
1016/**
1017 * @note Locks this object for writing, together with the peer object
1018 * represented by @a aThat (locked for reading).
1019 */
1020void USBController::copyFrom (USBController *aThat)
1021{
1022 AssertReturnVoid (aThat != NULL);
1023
1024 /* sanity */
1025 AutoCaller autoCaller (this);
1026 AssertComRCReturnVoid (autoCaller.rc());
1027
1028 /* sanity too */
1029 AutoCaller thatCaller (aThat);
1030 AssertComRCReturnVoid (thatCaller.rc());
1031
1032 /* even more sanity */
1033 Machine::AutoAnyStateDependency adep (mParent);
1034 AssertComRCReturnVoid (adep.rc());
1035 /* Machine::copyFrom() may not be called when the VM is running */
1036 AssertReturnVoid (adep.machineState() < MachineState_Running ||
1037 adep.machineState() >= MachineState_Discarding);
1038
1039 /* peer is not modified, lock it for reading (aThat is "master" so locked
1040 * first) */
1041 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
1042
1043 /* this will back up current data */
1044 mData.assignCopy (aThat->mData);
1045
1046#ifdef VBOX_WITH_USB
1047
1048 /* Note that we won't inform the USB proxy about new filters since the VM is
1049 * not running when we are here and therefore no need to do so */
1050
1051 /* create private copies of all filters */
1052 mDeviceFilters.backup();
1053 mDeviceFilters->clear();
1054 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
1055 it != aThat->mDeviceFilters->end();
1056 ++ it)
1057 {
1058 ComObjPtr <USBDeviceFilter> filter;
1059 filter.createObject();
1060 filter->initCopy (this, *it);
1061 mDeviceFilters->push_back (filter);
1062 }
1063
1064#endif /* VBOX_WITH_USB */
1065}
1066
1067#ifdef VBOX_WITH_USB
1068
1069/**
1070 * Called by setter methods of all USB device filters.
1071 *
1072 * @note Locks nothing.
1073 */
1074HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
1075 BOOL aActiveChanged /* = FALSE */)
1076{
1077 AutoCaller autoCaller (this);
1078 AssertComRCReturnRC (autoCaller.rc());
1079
1080 /* we need the machine state */
1081 Machine::AutoAnyStateDependency adep (mParent);
1082 AssertComRCReturnRC (adep.rc());
1083
1084 /* nothing to do if the machine isn't running */
1085 if (adep.machineState() < MachineState_Running)
1086 return S_OK;
1087
1088 /* we don't modify our data fields -- no need to lock */
1089
1090 if (aFilter->mInList && mParent->isRegistered())
1091 {
1092 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1093 ComAssertRet (service, E_FAIL);
1094
1095 if (aActiveChanged)
1096 {
1097 /* insert/remove the filter from the proxy */
1098 if (aFilter->data().mActive)
1099 {
1100 ComAssertRet (aFilter->id() == NULL, E_FAIL);
1101 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1102 }
1103 else
1104 {
1105 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1106 service->removeFilter (aFilter->id());
1107 aFilter->id() = NULL;
1108 }
1109 }
1110 else
1111 {
1112 if (aFilter->data().mActive)
1113 {
1114 /* update the filter in the proxy */
1115 ComAssertRet (aFilter->id() != NULL, E_FAIL);
1116 service->removeFilter (aFilter->id());
1117 aFilter->id() = service->insertFilter (&aFilter->data().mUSBFilter);
1118 }
1119 }
1120 }
1121
1122 return S_OK;
1123}
1124
1125/**
1126 * Returns true if the given USB device matches to at least one of
1127 * this controller's USB device filters.
1128 *
1129 * A HostUSBDevice specific version.
1130 *
1131 * @note Locks this object for reading.
1132 */
1133bool USBController::hasMatchingFilter (const ComObjPtr <HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
1134{
1135 AutoCaller autoCaller (this);
1136 AssertComRCReturn (autoCaller.rc(), false);
1137
1138 AutoReadLock alock (this);
1139
1140 /* Disabled USB controllers cannot actually work with USB devices */
1141 if (!mData->mEnabled)
1142 return false;
1143
1144 /* apply self filters */
1145 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1146 it != mDeviceFilters->end();
1147 ++ it)
1148 {
1149 AutoWriteLock filterLock (*it);
1150 if (aDevice->isMatch ((*it)->data()))
1151 {
1152 *aMaskedIfs = (*it)->data().mMaskedIfs;
1153 return true;
1154 }
1155 }
1156
1157 return false;
1158}
1159
1160/**
1161 * Returns true if the given USB device matches to at least one of
1162 * this controller's USB device filters.
1163 *
1164 * A generic version that accepts any IUSBDevice on input.
1165 *
1166 * @note
1167 * This method MUST correlate with HostUSBDevice::isMatch()
1168 * in the sense of the device matching logic.
1169 *
1170 * @note Locks this object for reading.
1171 */
1172bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
1173{
1174 LogFlowThisFuncEnter();
1175
1176 AutoCaller autoCaller (this);
1177 AssertComRCReturn (autoCaller.rc(), false);
1178
1179 AutoReadLock alock (this);
1180
1181 /* Disabled USB controllers cannot actually work with USB devices */
1182 if (!mData->mEnabled)
1183 return false;
1184
1185 HRESULT rc = S_OK;
1186
1187 /* query fields */
1188 USBFILTER dev;
1189 USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);
1190
1191 USHORT vendorId = 0;
1192 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1193 ComAssertComRCRet (rc, false);
1194 ComAssertRet (vendorId, false);
1195 int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
1196
1197 USHORT productId = 0;
1198 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1199 ComAssertComRCRet (rc, false);
1200 ComAssertRet (productId, false);
1201 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
1202
1203 USHORT revision;
1204 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1205 ComAssertComRCRet (rc, false);
1206 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
1207
1208 Bstr manufacturer;
1209 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1210 ComAssertComRCRet (rc, false);
1211 if (!manufacturer.isNull())
1212 USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer), true);
1213
1214 Bstr product;
1215 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1216 ComAssertComRCRet (rc, false);
1217 if (!product.isNull())
1218 USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product), true);
1219
1220 Bstr serialNumber;
1221 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1222 ComAssertComRCRet (rc, false);
1223 if (!serialNumber.isNull())
1224 USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber), true);
1225
1226 Bstr address;
1227 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1228 ComAssertComRCRet (rc, false);
1229
1230 USHORT port = 0;
1231 rc = aUSBDevice->COMGETTER(Port)(&port);
1232 ComAssertComRCRet (rc, false);
1233 USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);
1234
1235 BOOL remote = FALSE;
1236 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1237 ComAssertComRCRet (rc, false);
1238 ComAssertRet (remote == TRUE, false);
1239
1240 bool match = false;
1241
1242 /* apply self filters */
1243 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1244 it != mDeviceFilters->end();
1245 ++ it)
1246 {
1247 AutoWriteLock filterLock (*it);
1248 const USBDeviceFilter::Data &aData = (*it)->data();
1249
1250 if (!aData.mActive)
1251 continue;
1252 if (!aData.mRemote.isMatch (remote))
1253 continue;
1254 if (!USBFilterMatch (&aData.mUSBFilter, &dev))
1255 continue;
1256
1257 match = true;
1258 *aMaskedIfs = aData.mMaskedIfs;
1259 break;
1260 }
1261
1262 LogFlowThisFunc (("returns: %d\n", match));
1263 LogFlowThisFuncLeave();
1264
1265 return match;
1266}
1267
1268/**
1269 * Notifies the proxy service about all filters as requested by the
1270 * @a aInsertFilters argument.
1271 *
1272 * @param aInsertFilters @c true to insert filters, @c false to remove.
1273 *
1274 * @note Locks this object for reading.
1275 */
1276HRESULT USBController::notifyProxy (bool aInsertFilters)
1277{
1278 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1279
1280 AutoCaller autoCaller (this);
1281 AssertComRCReturn (autoCaller.rc(), false);
1282
1283 AutoReadLock alock (this);
1284
1285 USBProxyService *service = mParent->virtualBox()->host()->usbProxyService();
1286 AssertReturn (service, E_FAIL);
1287
1288 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1289 while (it != mDeviceFilters->end())
1290 {
1291 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1292
1293 /* notify the proxy (only if the filter is active) */
1294 if (flt->data().mActive)
1295 {
1296 if (aInsertFilters)
1297 {
1298 AssertReturn (flt->id() == NULL, E_FAIL);
1299 flt->id() = service->insertFilter (&flt->data().mUSBFilter);
1300 }
1301 else
1302 {
1303 /* It's possible that the given filter was not inserted the proxy
1304 * when this method gets called (as a result of an early VM
1305 * process crash for example. So, don't assert that ID != NULL. */
1306 if (flt->id() != NULL)
1307 {
1308 service->removeFilter (flt->id());
1309 flt->id() = NULL;
1310 }
1311 }
1312 }
1313 ++ it;
1314 }
1315
1316 return S_OK;
1317}
1318
1319#endif /* VBOX_WITH_USB */
1320
1321// private methods
1322/////////////////////////////////////////////////////////////////////////////
1323/* 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