VirtualBox

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

Last change on this file since 5713 was 5713, checked in by vboxsync, 17 years ago

Added an maskedInterface property to the USB filters. It is used to hide a set of interface from the guest, which means that on Linux we won't capture those and linux can continue using them.

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