VirtualBox

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

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

manual-cpp -DVBOX_WITH_USBFILTER. One worry, not sure why the Action setter call was omitted from the init. Hopefully just a left over.

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