VirtualBox

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

Last change on this file since 20045 was 17394, checked in by vboxsync, 16 years ago

#3551: “Main: Replace remaining collections with safe arrays”
Convert USBDeviceFilterCollection.

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