VirtualBox

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

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

Main: Removed extra logging.

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