VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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