VirtualBox

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

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

More USBFILTER changes.

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