VirtualBox

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

Last change on this file since 25184 was 25149, checked in by vboxsync, 15 years ago

Main: cleanup: remove all CheckComRC* macros (no functional change)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.7 KB
Line 
1/* $Id: USBControllerImpl.cpp 25149 2009-12-02 14:34:47Z 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 if (FAILED(autoCaller.rc())) return 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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
235
236 /* the machine needs to be mutable */
237 Machine::AutoMutableStateDependency adep(mParent);
238 if (FAILED(adep.rc())) return 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 if (FAILED(autoCaller.rc())) return 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 if (FAILED(autoCaller.rc())) return autoCaller.rc();
276
277 /* the machine needs to be mutable */
278 Machine::AutoMutableStateDependency adep(mParent);
279 if (FAILED(adep.rc())) return 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 if (FAILED(autoCaller.rc())) return 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 VirtualBoxBase,
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 DECLARE_EMPTY_CTOR_DTOR (USBDeviceFilter)
332
333 // IUSBDeviceFilter properties
334 STDMETHOD(COMGETTER(Name)) (BSTR *aName);
335 STDMETHOD(COMSETTER(Name)) (IN_BSTR aName);
336 STDMETHOD(COMGETTER(Active)) (BOOL *aActive);
337 STDMETHOD(COMSETTER(Active)) (BOOL aActive);
338 STDMETHOD(COMGETTER(VendorId)) (BSTR *aVendorId);
339 STDMETHOD(COMSETTER(VendorId)) (IN_BSTR aVendorId);
340 STDMETHOD(COMGETTER(ProductId)) (BSTR *aProductId);
341 STDMETHOD(COMSETTER(ProductId)) (IN_BSTR aProductId);
342 STDMETHOD(COMGETTER(Revision)) (BSTR *aRevision);
343 STDMETHOD(COMSETTER(Revision)) (IN_BSTR aRevision);
344 STDMETHOD(COMGETTER(Manufacturer)) (BSTR *aManufacturer);
345 STDMETHOD(COMSETTER(Manufacturer)) (IN_BSTR aManufacturer);
346 STDMETHOD(COMGETTER(Product)) (BSTR *aProduct);
347 STDMETHOD(COMSETTER(Product)) (IN_BSTR aProduct);
348 STDMETHOD(COMGETTER(SerialNumber)) (BSTR *aSerialNumber);
349 STDMETHOD(COMSETTER(SerialNumber)) (IN_BSTR aSerialNumber);
350 STDMETHOD(COMGETTER(Port)) (BSTR *aPort);
351 STDMETHOD(COMSETTER(Port)) (IN_BSTR aPort);
352 STDMETHOD(COMGETTER(Remote)) (BSTR *aRemote);
353 STDMETHOD(COMSETTER(Remote)) (IN_BSTR aRemote);
354 STDMETHOD(COMGETTER(MaskedInterfaces)) (ULONG *aMaskedIfs);
355 STDMETHOD(COMSETTER(MaskedInterfaces)) (ULONG aMaskedIfs);
356};
357#endif /* !VBOX_WITH_USB */
358
359
360STDMETHODIMP USBController::COMGETTER(DeviceFilters) (ComSafeArrayOut(IUSBDeviceFilter *, aDevicesFilters))
361{
362#ifdef VBOX_WITH_USB
363 CheckComArgOutSafeArrayPointerValid(aDevicesFilters);
364
365 AutoCaller autoCaller(this);
366 if (FAILED(autoCaller.rc())) return autoCaller.rc();
367
368 AutoReadLock alock(this);
369
370 SafeIfaceArray<IUSBDeviceFilter> collection (*mDeviceFilters.data());
371 collection.detachTo(ComSafeArrayOutArg(aDevicesFilters));
372
373 return S_OK;
374#else
375 NOREF(aDevicesFilters);
376# ifndef RT_OS_WINDOWS
377 NOREF(aDevicesFiltersSize);
378# endif
379 ReturnComNotImplemented();
380#endif
381}
382
383// IUSBController methods
384/////////////////////////////////////////////////////////////////////////////
385
386STDMETHODIMP USBController::CreateDeviceFilter (IN_BSTR aName,
387 IUSBDeviceFilter **aFilter)
388{
389#ifdef VBOX_WITH_USB
390 CheckComArgOutPointerValid(aFilter);
391
392 CheckComArgStrNotEmptyOrNull(aName);
393
394 AutoCaller autoCaller(this);
395 if (FAILED(autoCaller.rc())) return autoCaller.rc();
396
397 /* the machine needs to be mutable */
398 Machine::AutoMutableStateDependency adep(mParent);
399 if (FAILED(adep.rc())) return adep.rc();
400
401 AutoWriteLock alock(this);
402
403 ComObjPtr<USBDeviceFilter> filter;
404 filter.createObject();
405 HRESULT rc = filter->init (this, aName);
406 ComAssertComRCRetRC (rc);
407 rc = filter.queryInterfaceTo(aFilter);
408 AssertComRCReturnRC(rc);
409
410 return S_OK;
411#else
412 NOREF(aName);
413 NOREF(aFilter);
414 ReturnComNotImplemented();
415#endif
416}
417
418STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
419 IUSBDeviceFilter *aFilter)
420{
421#ifdef VBOX_WITH_USB
422
423 CheckComArgNotNull(aFilter);
424
425 AutoCaller autoCaller(this);
426 if (FAILED(autoCaller.rc())) return autoCaller.rc();
427
428 /* the machine needs to be mutable */
429 Machine::AutoMutableStateDependency adep(mParent);
430 if (FAILED(adep.rc())) return adep.rc();
431
432 AutoWriteLock alock(this);
433
434 ComObjPtr<USBDeviceFilter> filter = getDependentChild (aFilter);
435 if (!filter)
436 return setError (E_INVALIDARG,
437 tr ("The given USB device filter is not created within "
438 "this VirtualBox instance"));
439
440 if (filter->mInList)
441 return setError (VBOX_E_INVALID_OBJECT_STATE,
442 tr ("The given USB device filter is already in the list"));
443
444 /* backup the list before modification */
445 mDeviceFilters.backup();
446
447 /* iterate to the position... */
448 DeviceFilterList::iterator it;
449 if (aPosition < mDeviceFilters->size())
450 {
451 it = mDeviceFilters->begin();
452 std::advance (it, aPosition);
453 }
454 else
455 it = mDeviceFilters->end();
456 /* ...and insert */
457 mDeviceFilters->insert (it, filter);
458 filter->mInList = true;
459
460 /* notify the proxy (only when it makes sense) */
461 if (filter->getData().mActive && Global::IsOnline(adep.machineState()))
462 {
463 USBProxyService *service = mParent->getVirtualBox()->host()->usbProxyService();
464 ComAssertRet (service, E_FAIL);
465
466 ComAssertRet(filter->getId() == NULL, E_FAIL);
467 filter->getId() = service->insertFilter (&filter->getData().mUSBFilter);
468 }
469
470 return S_OK;
471
472#else /* VBOX_WITH_USB */
473
474 NOREF(aPosition);
475 NOREF(aFilter);
476 ReturnComNotImplemented();
477
478#endif /* VBOX_WITH_USB */
479}
480
481STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
482 IUSBDeviceFilter **aFilter)
483{
484#ifdef VBOX_WITH_USB
485
486 CheckComArgOutPointerValid(aFilter);
487
488 AutoCaller autoCaller(this);
489 if (FAILED(autoCaller.rc())) return autoCaller.rc();
490
491 /* the machine needs to be mutable */
492 Machine::AutoMutableStateDependency adep(mParent);
493 if (FAILED(adep.rc())) return adep.rc();
494
495 AutoWriteLock alock(this);
496
497 if (!mDeviceFilters->size())
498 return setError (E_INVALIDARG,
499 tr ("The USB device filter list is empty"));
500
501 if (aPosition >= mDeviceFilters->size())
502 return setError (E_INVALIDARG,
503 tr ("Invalid position: %lu (must be in range [0, %lu])"),
504 aPosition, mDeviceFilters->size() - 1);
505
506 /* backup the list before modification */
507 mDeviceFilters.backup();
508
509 ComObjPtr<USBDeviceFilter> filter;
510 {
511 /* iterate to the position... */
512 DeviceFilterList::iterator it = mDeviceFilters->begin();
513 std::advance (it, aPosition);
514 /* ...get an element from there... */
515 filter = *it;
516 /* ...and remove */
517 filter->mInList = false;
518 mDeviceFilters->erase (it);
519 }
520
521 /* cancel sharing (make an independent copy of data) */
522 filter->unshare();
523
524 filter.queryInterfaceTo(aFilter);
525
526 /* notify the proxy (only when it makes sense) */
527 if (filter->getData().mActive && Global::IsOnline(adep.machineState()))
528 {
529 USBProxyService *service = mParent->getVirtualBox()->host()->usbProxyService();
530 ComAssertRet (service, E_FAIL);
531
532 ComAssertRet(filter->getId() != NULL, E_FAIL);
533 service->removeFilter(filter->getId());
534 filter->getId() = NULL;
535 }
536
537 return S_OK;
538
539#else /* VBOX_WITH_USB */
540
541 NOREF(aPosition);
542 NOREF(aFilter);
543 ReturnComNotImplemented();
544
545#endif /* VBOX_WITH_USB */
546}
547
548// public methods only for internal purposes
549/////////////////////////////////////////////////////////////////////////////
550
551/**
552 * Loads settings from the given machine node.
553 * May be called once right after this object creation.
554 *
555 * @param aMachineNode <Machine> node.
556 *
557 * @note Locks this object for writing.
558 */
559HRESULT USBController::loadSettings(const settings::USBController &data)
560{
561 AutoCaller autoCaller(this);
562 AssertComRCReturnRC(autoCaller.rc());
563
564 AutoWriteLock alock(this);
565
566 /* Note: we assume that the default values for attributes of optional
567 * nodes are assigned in the Data::Data() constructor and don't do it
568 * here. It implies that this method may only be called after constructing
569 * a new BIOSSettings object while all its data fields are in the default
570 * values. Exceptions are fields whose creation time defaults don't match
571 * values that should be applied when these fields are not explicitly set
572 * in the settings file (for backwards compatibility reasons). This takes
573 * place when a setting of a newly created object must default to A while
574 * the same setting of an object loaded from the old settings file must
575 * default to B. */
576
577 mData->mEnabled = data.fEnabled;
578 mData->mEnabledEhci = data.fEnabledEHCI;
579
580#ifdef VBOX_WITH_USB
581 for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin();
582 it != data.llDeviceFilters.end();
583 ++it)
584 {
585 const settings::USBDeviceFilter &f = *it;
586 ComObjPtr<USBDeviceFilter> pFilter;
587 pFilter.createObject();
588 HRESULT rc = pFilter->init(this, // parent
589 f);
590 if (FAILED(rc)) return rc;
591
592 mDeviceFilters->push_back(pFilter);
593 pFilter->mInList = true;
594 }
595#endif /* VBOX_WITH_USB */
596
597 return S_OK;
598}
599
600/**
601 * Saves settings to the given machine node.
602 *
603 * @param aMachineNode <Machine> node.
604 *
605 * @note Locks this object for reading.
606 */
607HRESULT USBController::saveSettings(settings::USBController &data)
608{
609 AutoCaller autoCaller(this);
610 if (FAILED(autoCaller.rc())) return autoCaller.rc();
611
612 AutoReadLock alock(this);
613
614 data.fEnabled = !!mData->mEnabled;
615 data.fEnabledEHCI = !!mData->mEnabledEhci;
616
617#ifdef VBOX_WITH_USB
618 data.llDeviceFilters.clear();
619
620 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
621 it != mDeviceFilters->end();
622 ++it)
623 {
624 AutoWriteLock filterLock (*it);
625 const USBDeviceFilter::Data &filterData = (*it)->getData();
626
627 Bstr str;
628
629 settings::USBDeviceFilter f;
630 f.strName = filterData.mName;
631 f.fActive = !!filterData.mActive;
632 (*it)->COMGETTER(VendorId)(str.asOutParam());
633 f.strVendorId = str;
634 (*it)->COMGETTER(ProductId)(str.asOutParam());
635 f.strProductId = str;
636 (*it)->COMGETTER (Revision) (str.asOutParam());
637 f.strRevision = str;
638 (*it)->COMGETTER (Manufacturer) (str.asOutParam());
639 f.strManufacturer = str;
640 (*it)->COMGETTER (Product) (str.asOutParam());
641 f.strProduct = str;
642 (*it)->COMGETTER (SerialNumber) (str.asOutParam());
643 f.strSerialNumber = str;
644 (*it)->COMGETTER (Port) (str.asOutParam());
645 f.strPort = str;
646 f.strRemote = filterData.mRemote.string();
647 f.ulMaskedInterfaces = filterData.mMaskedIfs;
648
649 data.llDeviceFilters.push_back(f);
650 }
651#endif /* VBOX_WITH_USB */
652
653 return S_OK;
654}
655
656/** @note Locks objects for reading! */
657bool USBController::isModified()
658{
659 AutoCaller autoCaller(this);
660 AssertComRCReturn (autoCaller.rc(), false);
661
662 AutoReadLock alock(this);
663
664 if (mData.isBackedUp()
665#ifdef VBOX_WITH_USB
666 || mDeviceFilters.isBackedUp()
667#endif
668 )
669 return true;
670
671#ifdef VBOX_WITH_USB
672 /* see whether any of filters has changed its data */
673 for (DeviceFilterList::const_iterator
674 it = mDeviceFilters->begin();
675 it != mDeviceFilters->end();
676 ++ it)
677 {
678 if ((*it)->isModified())
679 return true;
680 }
681#endif /* VBOX_WITH_USB */
682
683 return false;
684}
685
686/** @note Locks objects for reading! */
687bool USBController::isReallyModified()
688{
689 AutoCaller autoCaller(this);
690 AssertComRCReturn (autoCaller.rc(), false);
691
692 AutoReadLock alock(this);
693
694 if (mData.hasActualChanges())
695 return true;
696
697#ifdef VBOX_WITH_USB
698 if (!mDeviceFilters.isBackedUp())
699 {
700 /* see whether any of filters has changed its data */
701 for (DeviceFilterList::const_iterator
702 it = mDeviceFilters->begin();
703 it != mDeviceFilters->end();
704 ++ it)
705 {
706 if ((*it)->isReallyModified())
707 return true;
708 }
709
710 return false;
711 }
712
713 if (mDeviceFilters->size() != mDeviceFilters.backedUpData()->size())
714 return true;
715
716 if (mDeviceFilters->size() == 0)
717 return false;
718
719 /* Make copies to speed up comparison */
720 DeviceFilterList devices = *mDeviceFilters.data();
721 DeviceFilterList backDevices = *mDeviceFilters.backedUpData();
722
723 DeviceFilterList::iterator it = devices.begin();
724 while (it != devices.end())
725 {
726 bool found = false;
727 DeviceFilterList::iterator thatIt = backDevices.begin();
728 while (thatIt != backDevices.end())
729 {
730 if ((*it)->getData() == (*thatIt)->getData())
731 {
732 backDevices.erase (thatIt);
733 found = true;
734 break;
735 }
736 else
737 ++ thatIt;
738 }
739 if (found)
740 it = devices.erase (it);
741 else
742 return false;
743 }
744
745 Assert (devices.size() == 0 && backDevices.size() == 0);
746#endif /* VBOX_WITH_USB */
747
748 return false;
749}
750
751/** @note Locks objects for writing! */
752bool USBController::rollback()
753{
754 AutoCaller autoCaller(this);
755 AssertComRCReturn (autoCaller.rc(), false);
756
757 /* we need the machine state */
758 Machine::AutoAnyStateDependency adep (mParent);
759 AssertComRCReturn (adep.rc(), false);
760
761 AutoWriteLock alock(this);
762
763 bool dataChanged = false;
764
765 if (mData.isBackedUp())
766 {
767 /* we need to check all data to see whether anything will be changed
768 * after rollback */
769 dataChanged = mData.hasActualChanges();
770 mData.rollback();
771 }
772
773#ifdef VBOX_WITH_USB
774
775 if (mDeviceFilters.isBackedUp())
776 {
777 USBProxyService *service = mParent->getVirtualBox()->host()->usbProxyService();
778 ComAssertRet (service, false);
779
780 /* uninitialize all new filters (absent in the backed up list) */
781 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
782 DeviceFilterList *backedList = mDeviceFilters.backedUpData();
783 while (it != mDeviceFilters->end())
784 {
785 if (std::find (backedList->begin(), backedList->end(), *it) ==
786 backedList->end())
787 {
788 /* notify the proxy (only when it makes sense) */
789 if ((*it)->getData().mActive &&
790 Global::IsOnline (adep.machineState()))
791 {
792 USBDeviceFilter *filter = *it;
793 ComAssertRet(filter->getId() != NULL, false);
794 service->removeFilter(filter->getId());
795 filter->getId() = NULL;
796 }
797
798 (*it)->uninit();
799 }
800 ++ it;
801 }
802
803 if (Global::IsOnline (adep.machineState()))
804 {
805 /* find all removed old filters (absent in the new list)
806 * and insert them back to the USB proxy */
807 it = backedList->begin();
808 while (it != backedList->end())
809 {
810 if (std::find (mDeviceFilters->begin(), mDeviceFilters->end(), *it) ==
811 mDeviceFilters->end())
812 {
813 /* notify the proxy (only when necessary) */
814 if ((*it)->getData().mActive)
815 {
816 USBDeviceFilter *flt = *it; /* resolve ambiguity */
817 ComAssertRet(flt->getId() == NULL, false);
818 flt->getId() = service->insertFilter(&flt->getData().mUSBFilter);
819 }
820 }
821 ++ it;
822 }
823 }
824
825 /* restore the list */
826 mDeviceFilters.rollback();
827 }
828
829 /* here we don't depend on the machine state any more */
830 adep.release();
831
832 /* rollback any changes to filters after restoring the list */
833 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
834 while (it != mDeviceFilters->end())
835 {
836 if ((*it)->isModified())
837 {
838 (*it)->rollback();
839 /* call this to notify the USB proxy about changes */
840 onDeviceFilterChange (*it);
841 }
842 ++ it;
843 }
844
845#endif /* VBOX_WITH_USB */
846
847 return dataChanged;
848}
849
850/**
851 * @note Locks this object for writing, together with the peer object (also
852 * for writing) if there is one.
853 */
854void USBController::commit()
855{
856 /* sanity */
857 AutoCaller autoCaller(this);
858 AssertComRCReturnVoid (autoCaller.rc());
859
860 /* sanity too */
861 AutoCaller peerCaller (mPeer);
862 AssertComRCReturnVoid (peerCaller.rc());
863
864 /* lock both for writing since we modify both (mPeer is "master" so locked
865 * first) */
866 AutoMultiWriteLock2 alock (mPeer, this);
867
868 if (mData.isBackedUp())
869 {
870 mData.commit();
871 if (mPeer)
872 {
873 /* attach new data to the peer and reshare it */
874 AutoWriteLock peerlock (mPeer);
875 mPeer->mData.attach (mData);
876 }
877 }
878
879#ifdef VBOX_WITH_USB
880 bool commitFilters = false;
881
882 if (mDeviceFilters.isBackedUp())
883 {
884 mDeviceFilters.commit();
885
886 /* apply changes to peer */
887 if (mPeer)
888 {
889 AutoWriteLock peerlock (mPeer);
890
891 /* commit all changes to new filters (this will reshare data with
892 * peers for those who have peers) */
893 DeviceFilterList *newList = new DeviceFilterList();
894 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
895 while (it != mDeviceFilters->end())
896 {
897 (*it)->commit();
898
899 /* look if this filter has a peer filter */
900 ComObjPtr<USBDeviceFilter> peer = (*it)->peer();
901 if (!peer)
902 {
903 /* no peer means the filter is a newly created one;
904 * create a peer owning data this filter share it with */
905 peer.createObject();
906 peer->init (mPeer, *it, true /* aReshare */);
907 }
908 else
909 {
910 /* remove peer from the old list */
911 mPeer->mDeviceFilters->remove (peer);
912 }
913 /* and add it to the new list */
914 newList->push_back (peer);
915
916 ++ it;
917 }
918
919 /* uninit old peer's filters that are left */
920 it = mPeer->mDeviceFilters->begin();
921 while (it != mPeer->mDeviceFilters->end())
922 {
923 (*it)->uninit();
924 ++ it;
925 }
926
927 /* attach new list of filters to our peer */
928 mPeer->mDeviceFilters.attach (newList);
929 }
930 else
931 {
932 /* we have no peer (our parent is the newly created machine);
933 * just commit changes to filters */
934 commitFilters = true;
935 }
936 }
937 else
938 {
939 /* the list of filters itself is not changed,
940 * just commit changes to filters themselves */
941 commitFilters = true;
942 }
943
944 if (commitFilters)
945 {
946 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
947 while (it != mDeviceFilters->end())
948 {
949 (*it)->commit();
950 ++ it;
951 }
952 }
953#endif /* VBOX_WITH_USB */
954}
955
956/**
957 * @note Locks this object for writing, together with the peer object
958 * represented by @a aThat (locked for reading).
959 */
960void USBController::copyFrom (USBController *aThat)
961{
962 AssertReturnVoid (aThat != NULL);
963
964 /* sanity */
965 AutoCaller autoCaller(this);
966 AssertComRCReturnVoid (autoCaller.rc());
967
968 /* sanity too */
969 AutoCaller thatCaller (aThat);
970 AssertComRCReturnVoid (thatCaller.rc());
971
972 /* even more sanity */
973 Machine::AutoAnyStateDependency adep (mParent);
974 AssertComRCReturnVoid (adep.rc());
975 /* Machine::copyFrom() may not be called when the VM is running */
976 AssertReturnVoid (!Global::IsOnline (adep.machineState()));
977
978 /* peer is not modified, lock it for reading (aThat is "master" so locked
979 * first) */
980 AutoMultiLock2 alock (aThat->rlock(), this->wlock());
981
982 /* this will back up current data */
983 mData.assignCopy (aThat->mData);
984
985#ifdef VBOX_WITH_USB
986
987 /* Note that we won't inform the USB proxy about new filters since the VM is
988 * not running when we are here and therefore no need to do so */
989
990 /* create private copies of all filters */
991 mDeviceFilters.backup();
992 mDeviceFilters->clear();
993 for (DeviceFilterList::const_iterator it = aThat->mDeviceFilters->begin();
994 it != aThat->mDeviceFilters->end();
995 ++ it)
996 {
997 ComObjPtr<USBDeviceFilter> filter;
998 filter.createObject();
999 filter->initCopy (this, *it);
1000 mDeviceFilters->push_back (filter);
1001 }
1002
1003#endif /* VBOX_WITH_USB */
1004}
1005
1006#ifdef VBOX_WITH_USB
1007
1008/**
1009 * Called by setter methods of all USB device filters.
1010 *
1011 * @note Locks nothing.
1012 */
1013HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
1014 BOOL aActiveChanged /* = FALSE */)
1015{
1016 AutoCaller autoCaller(this);
1017 AssertComRCReturnRC(autoCaller.rc());
1018
1019 /* we need the machine state */
1020 Machine::AutoAnyStateDependency adep (mParent);
1021 AssertComRCReturnRC(adep.rc());
1022
1023 /* nothing to do if the machine isn't running */
1024 if (!Global::IsOnline (adep.machineState()))
1025 return S_OK;
1026
1027 /* we don't modify our data fields -- no need to lock */
1028
1029 if (aFilter->mInList && mParent->isRegistered())
1030 {
1031 USBProxyService *service = mParent->getVirtualBox()->host()->usbProxyService();
1032 ComAssertRet (service, E_FAIL);
1033
1034 if (aActiveChanged)
1035 {
1036 /* insert/remove the filter from the proxy */
1037 if (aFilter->getData().mActive)
1038 {
1039 ComAssertRet(aFilter->getId() == NULL, E_FAIL);
1040 aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter);
1041 }
1042 else
1043 {
1044 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1045 service->removeFilter(aFilter->getId());
1046 aFilter->getId() = NULL;
1047 }
1048 }
1049 else
1050 {
1051 if (aFilter->getData().mActive)
1052 {
1053 /* update the filter in the proxy */
1054 ComAssertRet(aFilter->getId() != NULL, E_FAIL);
1055 service->removeFilter(aFilter->getId());
1056 aFilter->getId() = service->insertFilter(&aFilter->getData().mUSBFilter);
1057 }
1058 }
1059 }
1060
1061 return S_OK;
1062}
1063
1064/**
1065 * Returns true if the given USB device matches to at least one of
1066 * this controller's USB device filters.
1067 *
1068 * A HostUSBDevice specific version.
1069 *
1070 * @note Locks this object for reading.
1071 */
1072bool USBController::hasMatchingFilter (const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
1073{
1074 AutoCaller autoCaller(this);
1075 AssertComRCReturn (autoCaller.rc(), false);
1076
1077 AutoReadLock alock(this);
1078
1079 /* Disabled USB controllers cannot actually work with USB devices */
1080 if (!mData->mEnabled)
1081 return false;
1082
1083 /* apply self filters */
1084 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1085 it != mDeviceFilters->end();
1086 ++ it)
1087 {
1088 AutoWriteLock filterLock (*it);
1089 if (aDevice->isMatch((*it)->getData()))
1090 {
1091 *aMaskedIfs = (*it)->getData().mMaskedIfs;
1092 return true;
1093 }
1094 }
1095
1096 return false;
1097}
1098
1099/**
1100 * Returns true if the given USB device matches to at least one of
1101 * this controller's USB device filters.
1102 *
1103 * A generic version that accepts any IUSBDevice on input.
1104 *
1105 * @note
1106 * This method MUST correlate with HostUSBDevice::isMatch()
1107 * in the sense of the device matching logic.
1108 *
1109 * @note Locks this object for reading.
1110 */
1111bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
1112{
1113 LogFlowThisFuncEnter();
1114
1115 AutoCaller autoCaller(this);
1116 AssertComRCReturn (autoCaller.rc(), false);
1117
1118 AutoReadLock alock(this);
1119
1120 /* Disabled USB controllers cannot actually work with USB devices */
1121 if (!mData->mEnabled)
1122 return false;
1123
1124 HRESULT rc = S_OK;
1125
1126 /* query fields */
1127 USBFILTER dev;
1128 USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);
1129
1130 USHORT vendorId = 0;
1131 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
1132 ComAssertComRCRet (rc, false);
1133 ComAssertRet (vendorId, false);
1134 int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
1135
1136 USHORT productId = 0;
1137 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
1138 ComAssertComRCRet (rc, false);
1139 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
1140
1141 USHORT revision;
1142 rc = aUSBDevice->COMGETTER(Revision) (&revision);
1143 ComAssertComRCRet (rc, false);
1144 vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
1145
1146 Bstr manufacturer;
1147 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
1148 ComAssertComRCRet (rc, false);
1149 if (!manufacturer.isNull())
1150 USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true);
1151
1152 Bstr product;
1153 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1154 ComAssertComRCRet (rc, false);
1155 if (!product.isNull())
1156 USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true);
1157
1158 Bstr serialNumber;
1159 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1160 ComAssertComRCRet (rc, false);
1161 if (!serialNumber.isNull())
1162 USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true);
1163
1164 Bstr address;
1165 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1166 ComAssertComRCRet (rc, false);
1167
1168 USHORT port = 0;
1169 rc = aUSBDevice->COMGETTER(Port)(&port);
1170 ComAssertComRCRet (rc, false);
1171 USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);
1172
1173 BOOL remote = FALSE;
1174 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1175 ComAssertComRCRet (rc, false);
1176 ComAssertRet (remote == TRUE, false);
1177
1178 bool match = false;
1179
1180 /* apply self filters */
1181 for (DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1182 it != mDeviceFilters->end();
1183 ++ it)
1184 {
1185 AutoWriteLock filterLock (*it);
1186 const USBDeviceFilter::Data &aData = (*it)->getData();
1187
1188 if (!aData.mActive)
1189 continue;
1190 if (!aData.mRemote.isMatch (remote))
1191 continue;
1192 if (!USBFilterMatch (&aData.mUSBFilter, &dev))
1193 continue;
1194
1195 match = true;
1196 *aMaskedIfs = aData.mMaskedIfs;
1197 break;
1198 }
1199
1200 LogFlowThisFunc(("returns: %d\n", match));
1201 LogFlowThisFuncLeave();
1202
1203 return match;
1204}
1205
1206/**
1207 * Notifies the proxy service about all filters as requested by the
1208 * @a aInsertFilters argument.
1209 *
1210 * @param aInsertFilters @c true to insert filters, @c false to remove.
1211 *
1212 * @note Locks this object for reading.
1213 */
1214HRESULT USBController::notifyProxy (bool aInsertFilters)
1215{
1216 LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters));
1217
1218 AutoCaller autoCaller(this);
1219 AssertComRCReturn (autoCaller.rc(), false);
1220
1221 AutoReadLock alock(this);
1222
1223 USBProxyService *service = mParent->getVirtualBox()->host()->usbProxyService();
1224 AssertReturn(service, E_FAIL);
1225
1226 DeviceFilterList::const_iterator it = mDeviceFilters->begin();
1227 while (it != mDeviceFilters->end())
1228 {
1229 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1230
1231 /* notify the proxy (only if the filter is active) */
1232 if (flt->getData().mActive)
1233 {
1234 if (aInsertFilters)
1235 {
1236 AssertReturn(flt->getId() == NULL, E_FAIL);
1237 flt->getId() = service->insertFilter(&flt->getData().mUSBFilter);
1238 }
1239 else
1240 {
1241 /* It's possible that the given filter was not inserted the proxy
1242 * when this method gets called (as a result of an early VM
1243 * process crash for example. So, don't assert that ID != NULL. */
1244 if (flt->getId() != NULL)
1245 {
1246 service->removeFilter(flt->getId());
1247 flt->getId() = NULL;
1248 }
1249 }
1250 }
1251 ++ it;
1252 }
1253
1254 return S_OK;
1255}
1256
1257#endif /* VBOX_WITH_USB */
1258
1259// private methods
1260/////////////////////////////////////////////////////////////////////////////
1261/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use