VirtualBox

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

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

#3551: “Main: Replace remaining collections with safe arrays”
Converted USBFilterCollection. Tested with filters in the GUI.

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