VirtualBox

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

Last change on this file since 2805 was 2805, checked in by vboxsync, 18 years ago

Main: Fixed: Machine-level USB filters are now inserted to the USB proxy only upon VM startup and removed upon termination (defect #1975).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.6 KB
Line 
1/** @file
2 *
3 * Implementation of IUSBController.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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 <VBox/err.h>
36
37#include <algorithm>
38
39// defines
40/////////////////////////////////////////////////////////////////////////////
41
42// constructor / destructor
43/////////////////////////////////////////////////////////////////////////////
44
45HRESULT USBController::FinalConstruct()
46{
47 return S_OK;
48}
49
50void USBController::FinalRelease()
51{
52 if (isReady())
53 uninit();
54}
55
56// public initializer/uninitializer for internal purposes only
57/////////////////////////////////////////////////////////////////////////////
58
59/**
60 * Initializes the USB controller object.
61 *
62 * @returns COM result indicator.
63 * @param a_pParent Pointer to our parent object.
64 */
65HRESULT USBController::init(Machine *a_pParent)
66{
67 LogFlowMember(("USBController::init (%p)\n", a_pParent));
68
69 ComAssertRet (a_pParent, E_INVALIDARG);
70
71 AutoLock alock(this);
72 ComAssertRet (!isReady(), E_UNEXPECTED);
73
74 m_Parent = a_pParent;
75 // m_Peer is left null
76
77 m_Data.allocate();
78 m_DeviceFilters.allocate();
79
80 setReady(true);
81 return S_OK;
82}
83
84
85/**
86 * Initializes the USB controller object given another USB controller object
87 * (a kind of copy constructor). This object shares data with
88 * the object passed as an argument.
89 *
90 * @returns COM result indicator.
91 * @param a_pParent Pointer to our parent object.
92 * @param a_pPeer The object to share.
93 *
94 * @remark This object must be destroyed before the original object
95 * it shares data with is destroyed.
96 */
97HRESULT USBController::init(Machine *a_pParent, USBController *a_pPeer)
98{
99 LogFlowMember(("USBController::init (%p, %p)\n", a_pParent, a_pPeer));
100
101 ComAssertRet (a_pParent && a_pPeer, E_INVALIDARG);
102
103 AutoLock alock(this);
104 ComAssertRet (!isReady(), E_UNEXPECTED);
105
106 m_Parent = a_pParent;
107 m_Peer = a_pPeer;
108
109 AutoLock thatlock(a_pPeer);
110 m_Data.share(a_pPeer->m_Data);
111
112 // create copies of all filters
113 m_DeviceFilters.allocate();
114 DeviceFilterList::const_iterator it = a_pPeer->m_DeviceFilters->begin();
115 while (it != a_pPeer->m_DeviceFilters->end())
116 {
117 ComObjPtr <USBDeviceFilter> filter;
118 filter.createObject();
119 filter->init (this, *it);
120 m_DeviceFilters->push_back (filter);
121 ++ it;
122 }
123
124 setReady(true);
125 return S_OK;
126}
127
128
129/**
130 * Initializes the USB controller object given another guest object
131 * (a kind of copy constructor). This object makes a private copy of data
132 * of the original object passed as an argument.
133 */
134HRESULT USBController::initCopy (Machine *a_pParent, USBController *a_pPeer)
135{
136 LogFlowMember(("USBController::initCopy (%p, %p)\n", a_pParent, a_pPeer));
137
138 ComAssertRet (a_pParent && a_pPeer, E_INVALIDARG);
139
140 AutoLock alock(this);
141 ComAssertRet (!isReady(), E_UNEXPECTED);
142
143 m_Parent = a_pParent;
144 // m_Peer is left null
145
146 AutoLock thatlock(a_pPeer);
147 m_Data.attachCopy (a_pPeer->m_Data);
148
149 // create private copies of all filters
150 m_DeviceFilters.allocate();
151 DeviceFilterList::const_iterator it = a_pPeer->m_DeviceFilters->begin();
152 while (it != a_pPeer->m_DeviceFilters->end())
153 {
154 ComObjPtr <USBDeviceFilter> filter;
155 filter.createObject();
156 filter->initCopy (this, *it);
157 m_DeviceFilters->push_back (filter);
158 ++ it;
159 }
160
161 setReady(true);
162 return S_OK;
163}
164
165
166/**
167 * Uninitializes the instance and sets the ready flag to FALSE.
168 * Called either from FinalRelease() or by the parent when it gets destroyed.
169 */
170void USBController::uninit()
171{
172 LogFlowMember(("USBController::uninit()\n"));
173
174 AutoLock alock(this);
175 AssertReturn (isReady(), (void) 0);
176
177 // uninit all filters (including those still referenced by clients)
178 uninitDependentChildren();
179
180 m_DeviceFilters.free();
181 m_Data.free();
182
183 m_Peer.setNull();
184 m_Parent.setNull();
185
186 setReady(false);
187}
188
189
190
191// IUSBController properties
192/////////////////////////////////////////////////////////////////////////////
193
194STDMETHODIMP USBController::COMGETTER(Enabled)(BOOL *a_pfEnabled)
195{
196 if (!a_pfEnabled)
197 return E_POINTER;
198
199 AutoLock alock(this);
200 CHECK_READY();
201
202 *a_pfEnabled = m_Data->m_fEnabled;
203 LogFlowMember(("USBController::GetEnabled: returns %p\n", *a_pfEnabled));
204 return S_OK;
205}
206
207
208STDMETHODIMP USBController::COMSETTER(Enabled)(BOOL a_fEnabled)
209{
210 LogFlowMember(("USBController::SetEnabled: %s\n", a_fEnabled ? "enable" : "disable"));
211
212 AutoLock alock(this);
213 CHECK_READY();
214
215 CHECK_MACHINE_MUTABILITY (m_Parent);
216
217 if (m_Data->m_fEnabled != a_fEnabled)
218 {
219 m_Data.backup();
220 m_Data->m_fEnabled = a_fEnabled;
221
222 alock.unlock();
223 m_Parent->onUSBControllerChange();
224 }
225
226 return S_OK;
227}
228
229/**
230 * Get the USB standard version.
231 *
232 * @param a_pusUSBStandard Where to store the BCD version word.
233 */
234STDMETHODIMP USBController::COMGETTER(USBStandard)(USHORT *a_pusUSBStandard)
235{
236 if (!a_pusUSBStandard)
237 return E_POINTER;
238
239 AutoLock alock(this);
240 CHECK_READY();
241
242 *a_pusUSBStandard = 0x0101;
243 LogFlowMember(("USBController::GetUSBStandard: returns 0x0101\n"));
244 return S_OK;
245}
246
247STDMETHODIMP USBController::COMGETTER(DeviceFilters) (IUSBDeviceFilterCollection **aDevicesFilters)
248{
249 if (!aDevicesFilters)
250 return E_POINTER;
251
252 AutoLock lock(this);
253 CHECK_READY();
254
255 ComObjPtr <USBDeviceFilterCollection> collection;
256 collection.createObject();
257 collection->init (*m_DeviceFilters.data());
258 collection.queryInterfaceTo (aDevicesFilters);
259 return S_OK;
260}
261
262// IUSBController methods
263/////////////////////////////////////////////////////////////////////////////
264
265STDMETHODIMP USBController::CreateDeviceFilter (INPTR BSTR aName,
266 IUSBDeviceFilter **aFilter)
267{
268 if (!aFilter)
269 return E_POINTER;
270
271 if (!aName || *aName == 0)
272 return E_INVALIDARG;
273
274 AutoLock lock (this);
275 CHECK_READY();
276
277 CHECK_MACHINE_MUTABILITY (m_Parent);
278
279 ComObjPtr <USBDeviceFilter> filter;
280 filter.createObject();
281 HRESULT rc = filter->init (this, aName);
282 ComAssertComRCRet (rc, rc);
283 rc = filter.queryInterfaceTo (aFilter);
284 AssertComRCReturn (rc, rc);
285 return S_OK;
286}
287
288STDMETHODIMP USBController::InsertDeviceFilter (ULONG aPosition,
289 IUSBDeviceFilter *aFilter)
290{
291 if (!aFilter)
292 return E_INVALIDARG;
293
294 AutoLock lock (this);
295 CHECK_READY();
296
297 /* the machine needs to be mutable */
298 Machine::AutoStateDependency <Machine::MutableStateDep> adep (m_Parent);
299 CheckComRCReturnRC (adep.rc());
300
301 ComObjPtr <USBDeviceFilter> filter = getDependentChild (aFilter);
302 if (!filter)
303 return setError (E_INVALIDARG,
304 tr ("The given USB device filter is not created within "
305 "this VirtualBox instance"));
306
307 if (filter->mInList)
308 return setError (E_INVALIDARG,
309 tr ("The given USB device filter is already in the list"));
310
311 /* backup the list before modification */
312 m_DeviceFilters.backup();
313
314 /* iterate to the position... */
315 DeviceFilterList::iterator it;
316 if (aPosition < m_DeviceFilters->size())
317 {
318 it = m_DeviceFilters->begin();
319 std::advance (it, aPosition);
320 }
321 else
322 it = m_DeviceFilters->end();
323 /* ...and insert */
324 m_DeviceFilters->insert (it, filter);
325 filter->mInList = true;
326
327 /// @todo After rewriting Win32 USB support, no more necessary;
328 // a candidate for removal.
329#if 0
330 /* notify the proxy (only when the filter is active) */
331 if (filter->data().mActive)
332#else
333 /* notify the proxy (only when it makes sense) */
334 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
335#endif
336 {
337 USBProxyService *service = m_Parent->virtualBox()->host()->usbProxyService();
338 ComAssertRet (service, E_FAIL);
339
340 ComAssertRet (filter->id() == NULL, E_FAIL);
341 filter->id() = service->insertFilter (ComPtr <IUSBDeviceFilter> (aFilter));
342 }
343
344 return S_OK;
345}
346
347STDMETHODIMP USBController::RemoveDeviceFilter (ULONG aPosition,
348 IUSBDeviceFilter **aFilter)
349{
350 if (!aFilter)
351 return E_POINTER;
352
353 AutoLock lock (this);
354 CHECK_READY();
355
356 /* the machine needs to be mutable */
357 Machine::AutoStateDependency <Machine::MutableStateDep> adep (m_Parent);
358 CheckComRCReturnRC (adep.rc());
359
360 if (!m_DeviceFilters->size())
361 return setError (E_INVALIDARG,
362 tr ("The USB device filter list is empty"));
363
364 if (aPosition >= m_DeviceFilters->size())
365 return setError (E_INVALIDARG,
366 tr ("Invalid position: %lu (must be in range [0, %lu])"),
367 aPosition, m_DeviceFilters->size() - 1);
368
369 /* backup the list before modification */
370 m_DeviceFilters.backup();
371
372 ComObjPtr <USBDeviceFilter> filter;
373 {
374 /* iterate to the position... */
375 DeviceFilterList::iterator it = m_DeviceFilters->begin();
376 std::advance (it, aPosition);
377 /* ...get an element from there... */
378 filter = *it;
379 /* ...and remove */
380 filter->mInList = false;
381 m_DeviceFilters->erase (it);
382 }
383
384 /* cancel sharing (make an independent copy of data) */
385 filter->unshare();
386
387 filter.queryInterfaceTo (aFilter);
388
389 /// @todo After rewriting Win32 USB support, no more necessary;
390 // a candidate for removal.
391#if 0
392 /* notify the proxy (only when the filter is active) */
393 if (filter->data().mActive)
394#else
395 /* notify the proxy (only when it makes sense) */
396 if (filter->data().mActive && adep.machineState() >= MachineState_Running)
397#endif
398 {
399 USBProxyService *service = m_Parent->virtualBox()->host()->usbProxyService();
400 ComAssertRet (service, E_FAIL);
401
402 ComAssertRet (filter->id() != NULL, E_FAIL);
403 service->removeFilter (filter->id());
404 filter->id() = NULL;
405 }
406
407 return S_OK;
408}
409
410// public methods only for internal purposes
411/////////////////////////////////////////////////////////////////////////////
412
413/** Loads settings from the configuration node */
414HRESULT USBController::loadSettings (CFGNODE aMachine)
415{
416 AutoLock lock (this);
417 CHECK_READY();
418
419 ComAssertRet (aMachine, E_FAIL);
420
421 CFGNODE controller = NULL;
422 CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
423 Assert (controller);
424
425 // enabled
426 bool enabled;
427 CFGLDRQueryBool (controller, "enabled", &enabled);
428 m_Data->m_fEnabled = enabled;
429
430 HRESULT rc = S_OK;
431
432 unsigned filterCount = 0;
433 CFGLDRCountChildren (controller, "DeviceFilter", &filterCount);
434 for (unsigned i = 0; i < filterCount && SUCCEEDED (rc); i++)
435 {
436 CFGNODE filter = NULL;
437 CFGLDRGetChildNode (controller, "DeviceFilter", i, &filter);
438 Assert (filter);
439
440 Bstr name;
441 CFGLDRQueryBSTR (filter, "name", name.asOutParam());
442 bool active;
443 CFGLDRQueryBool (filter, "active", &active);
444
445 Bstr vendorId;
446 CFGLDRQueryBSTR (filter, "vendorid", vendorId.asOutParam());
447 Bstr productId;
448 CFGLDRQueryBSTR (filter, "productid", productId.asOutParam());
449 Bstr revision;
450 CFGLDRQueryBSTR (filter, "revision", revision.asOutParam());
451 Bstr manufacturer;
452 CFGLDRQueryBSTR (filter, "manufacturer", manufacturer.asOutParam());
453 Bstr product;
454 CFGLDRQueryBSTR (filter, "product", product.asOutParam());
455 Bstr serialNumber;
456 CFGLDRQueryBSTR (filter, "serialnumber", serialNumber.asOutParam());
457 Bstr port;
458 CFGLDRQueryBSTR (filter, "port", port.asOutParam());
459 Bstr remote;
460 CFGLDRQueryBSTR (filter, "remote", remote.asOutParam());
461
462 ComObjPtr <USBDeviceFilter> filterObj;
463 filterObj.createObject();
464 rc = filterObj->init (this,
465 name, active, vendorId, productId, revision,
466 manufacturer, product, serialNumber,
467 port, remote);
468 // error info is set by init() when appropriate
469 if (SUCCEEDED (rc))
470 {
471 m_DeviceFilters->push_back (filterObj);
472 filterObj->mInList = true;
473 }
474
475 CFGLDRReleaseNode (filter);
476 }
477
478 CFGLDRReleaseNode (controller);
479
480 return rc;
481}
482
483/** Saves settings to the configuration node */
484HRESULT USBController::saveSettings (CFGNODE aMachine)
485{
486 AutoLock lock (this);
487 CHECK_READY();
488
489 ComAssertRet (aMachine, E_FAIL);
490
491 // first, delete the entry
492 CFGNODE controller = NULL;
493 int vrc = CFGLDRGetChildNode (aMachine, "USBController", 0, &controller);
494 if (VBOX_SUCCESS (vrc))
495 {
496 vrc = CFGLDRDeleteNode (controller);
497 ComAssertRCRet (vrc, E_FAIL);
498 }
499 // then, recreate it
500 vrc = CFGLDRCreateChildNode (aMachine, "USBController", &controller);
501 ComAssertRCRet (vrc, E_FAIL);
502
503 // enabled
504 CFGLDRSetBool (controller, "enabled", !!m_Data->m_fEnabled);
505
506 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
507 while (it != m_DeviceFilters->end())
508 {
509 AutoLock filterLock (*it);
510 const USBDeviceFilter::Data &data = (*it)->data();
511
512 CFGNODE filter = NULL;
513 CFGLDRAppendChildNode (controller, "DeviceFilter", &filter);
514
515 CFGLDRSetBSTR (filter, "name", data.mName);
516 CFGLDRSetBool (filter, "active", !!data.mActive);
517
518 // all are optional
519 if (data.mVendorId.string())
520 CFGLDRSetBSTR (filter, "vendorid", data.mVendorId.string());
521 if (data.mProductId.string())
522 CFGLDRSetBSTR (filter, "productid", data.mProductId.string());
523 if (data.mRevision.string())
524 CFGLDRSetBSTR (filter, "revision", data.mRevision.string());
525 if (data.mManufacturer.string())
526 CFGLDRSetBSTR (filter, "manufacturer", data.mManufacturer.string());
527 if (data.mProduct.string())
528 CFGLDRSetBSTR (filter, "product", data.mProduct.string());
529 if (data.mSerialNumber.string())
530 CFGLDRSetBSTR (filter, "serialnumber", data.mSerialNumber.string());
531 if (data.mPort.string())
532 CFGLDRSetBSTR (filter, "port", data.mPort.string());
533 if (data.mRemote.string())
534 CFGLDRSetBSTR (filter, "remote", data.mRemote.string());
535
536 CFGLDRReleaseNode (filter);
537
538 ++ it;
539 }
540
541 CFGLDRReleaseNode (controller);
542
543 return S_OK;
544}
545
546bool USBController::isModified()
547{
548 AutoLock alock(this);
549
550 if (m_Data.isBackedUp() || m_DeviceFilters.isBackedUp())
551 return true;
552
553 /* see whether any of filters has changed its data */
554 for (DeviceFilterList::const_iterator
555 it = m_DeviceFilters->begin();
556 it != m_DeviceFilters->end();
557 ++ it)
558 {
559 if ((*it)->isModified())
560 return true;
561 }
562
563 return false;
564}
565
566bool USBController::isReallyModified()
567{
568 AutoLock alock(this);
569
570 if (m_Data.hasActualChanges())
571 return true;
572
573 if (!m_DeviceFilters.isBackedUp())
574 {
575 /* see whether any of filters has changed its data */
576 for (DeviceFilterList::const_iterator
577 it = m_DeviceFilters->begin();
578 it != m_DeviceFilters->end();
579 ++ it)
580 {
581 if ((*it)->isReallyModified())
582 return true;
583 }
584
585 return false;
586 }
587
588 if (m_DeviceFilters->size() != m_DeviceFilters.backedUpData()->size())
589 return true;
590
591 if (m_DeviceFilters->size() == 0)
592 return false;
593
594 /* Make copies to speed up comparison */
595 DeviceFilterList devices = *m_DeviceFilters.data();
596 DeviceFilterList backDevices = *m_DeviceFilters.backedUpData();
597
598 DeviceFilterList::iterator it = devices.begin();
599 while (it != devices.end())
600 {
601 bool found = false;
602 DeviceFilterList::iterator thatIt = backDevices.begin();
603 while (thatIt != backDevices.end())
604 {
605 if ((*it)->data() == (*thatIt)->data())
606 {
607 backDevices.erase (thatIt);
608 found = true;
609 break;
610 }
611 else
612 ++ thatIt;
613 }
614 if (found)
615 it = devices.erase (it);
616 else
617 return false;
618 }
619
620 Assert (devices.size() == 0 && backDevices.size() == 0);
621
622 return false;
623}
624
625bool USBController::rollback()
626{
627 AutoLock alock (this);
628
629 /* we need the machine state */
630 Machine::AutoStateDependency <Machine::MutableStateDep> adep (m_Parent);
631 AssertComRCReturn (adep.rc(), false);
632
633 bool dataChanged = false;
634
635 if (m_Data.isBackedUp())
636 {
637 /* we need to check all data to see whether anything will be changed
638 * after rollback */
639 dataChanged = m_Data.hasActualChanges();
640 m_Data.rollback();
641 }
642
643 if (m_DeviceFilters.isBackedUp())
644 {
645 USBProxyService *service = m_Parent->virtualBox()->host()->usbProxyService();
646 ComAssertRet (service, false);
647
648 /* uninitialize all new filters (absent in the backed up list) */
649 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
650 DeviceFilterList *backedList = m_DeviceFilters.backedUpData();
651 while (it != m_DeviceFilters->end())
652 {
653 if (std::find (backedList->begin(), backedList->end(), *it) ==
654 backedList->end())
655 {
656 /// @todo After rewriting Win32 USB support, no more necessary;
657 // a candidate for removal.
658#if 0
659 /* notify the proxy (only when the filter is active) */
660 if ((*it)->data().mActive)
661#else
662 /* notify the proxy (only when it makes sense) */
663 if ((*it)->data().mActive &&
664 adep.machineState() >= MachineState_Running)
665#endif
666 {
667 USBDeviceFilter *filter = *it;
668 ComAssertRet (filter->id() != NULL, false);
669 service->removeFilter (filter->id());
670 filter->id() = NULL;
671 }
672
673 (*it)->uninit();
674 }
675 ++ it;
676 }
677
678 /// @todo After rewriting Win32 USB support, no more necessary;
679 // a candidate for removal.
680#if 0
681#else
682 if (adep.machineState() >= MachineState_Running)
683#endif
684 {
685 /* find all removed old filters (absent in the new list)
686 * and insert them back to the USB proxy */
687 it = backedList->begin();
688 while (it != backedList->end())
689 {
690 if (std::find (m_DeviceFilters->begin(), m_DeviceFilters->end(), *it) ==
691 m_DeviceFilters->end())
692 {
693 /* notify the proxy (only when necessary) */
694 if ((*it)->data().mActive)
695 {
696 USBDeviceFilter *flt = *it; /* resolve ambiguity */
697 ComAssertRet (flt->id() == NULL, false);
698 flt->id() = service->insertFilter
699 (ComPtr <IUSBDeviceFilter> (flt));
700 }
701 }
702 ++ it;
703 }
704 }
705
706 /* restore the list */
707 m_DeviceFilters.rollback();
708 }
709
710 /* here we don't depend on the machine state any more */
711 adep.release();
712
713 /* rollback any changes to filters after restoring the list */
714 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
715 while (it != m_DeviceFilters->end())
716 {
717 if ((*it)->isModified())
718 {
719 (*it)->rollback();
720 /* call this to notify the USB proxy about changes */
721 onDeviceFilterChange (*it);
722 }
723 ++ it;
724 }
725
726 return dataChanged;
727}
728
729void USBController::commit()
730{
731 AutoLock alock (this);
732
733 if (m_Data.isBackedUp())
734 {
735 m_Data.commit();
736 if (m_Peer)
737 {
738 // attach new data to the peer and reshare it
739 AutoLock peerlock (m_Peer);
740 m_Peer->m_Data.attach (m_Data);
741 }
742 }
743
744 bool commitFilters = false;
745
746 if (m_DeviceFilters.isBackedUp())
747 {
748 m_DeviceFilters.commit();
749
750 // apply changes to peer
751 if (m_Peer)
752 {
753 AutoLock peerlock (m_Peer);
754 // commit all changes to new filters (this will reshare data with
755 // peers for those who have peers)
756 DeviceFilterList *newList = new DeviceFilterList();
757 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
758 while (it != m_DeviceFilters->end())
759 {
760 (*it)->commit();
761
762 // look if this filter has a peer filter
763 ComObjPtr <USBDeviceFilter> peer = (*it)->peer();
764 if (!peer)
765 {
766 // no peer means the filter is a newly created one;
767 // create a peer owning data this filter share it with
768 peer.createObject();
769 peer->init (m_Peer, *it, true /* aReshare */);
770 }
771 else
772 {
773 // remove peer from the old list
774 m_Peer->m_DeviceFilters->remove (peer);
775 }
776 // and add it to the new list
777 newList->push_back (peer);
778
779 ++ it;
780 }
781
782 // uninit old peer's filters that are left
783 it = m_Peer->m_DeviceFilters->begin();
784 while (it != m_Peer->m_DeviceFilters->end())
785 {
786 (*it)->uninit();
787 ++ it;
788 }
789
790 // attach new list of filters to our peer
791 m_Peer->m_DeviceFilters.attach (newList);
792 }
793 else
794 {
795 // we have no peer (our parent is the newly created machine);
796 // just commit changes to filters
797 commitFilters = true;
798 }
799 }
800 else
801 {
802 // the list of filters itself is not changed,
803 // just commit changes to filters themselves
804 commitFilters = true;
805 }
806
807 if (commitFilters)
808 {
809 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
810 while (it != m_DeviceFilters->end())
811 {
812 (*it)->commit();
813 ++ it;
814 }
815 }
816}
817
818void USBController::copyFrom (USBController *aThat)
819{
820 AutoLock alock (this);
821 AutoLock thatLock (aThat);
822
823 if (m_Parent->isRegistered())
824 {
825 // reuse onMachineRegistered to tell USB proxy to remove all current filters
826 HRESULT rc = onMachineRegistered (FALSE);
827 AssertComRCReturn (rc, (void) 0);
828 }
829
830 // this will back up current data
831 m_Data.assignCopy (aThat->m_Data);
832
833 // create private copies of all filters
834 m_DeviceFilters.backup();
835 m_DeviceFilters->clear();
836 for (DeviceFilterList::const_iterator it = aThat->m_DeviceFilters->begin();
837 it != aThat->m_DeviceFilters->end();
838 ++ it)
839 {
840 ComObjPtr <USBDeviceFilter> filter;
841 filter.createObject();
842 filter->initCopy (this, *it);
843 m_DeviceFilters->push_back (filter);
844 }
845
846 if (m_Parent->isRegistered())
847 {
848 // reuse onMachineRegistered to tell USB proxy to insert all current filters
849 HRESULT rc = onMachineRegistered (TRUE);
850 AssertComRCReturn (rc, (void) 0);
851 }
852}
853
854/**
855 * Called by VirtualBox when it changes the registered state
856 * of the machine this USB controller belongs to.
857 *
858 * @param aRegistered new registered state of the machine
859 */
860HRESULT USBController::onMachineRegistered (BOOL aRegistered)
861{
862 AutoLock alock (this);
863 CHECK_READY();
864
865 /// @todo After rewriting Win32 USB support, no more necessary;
866 // a candidate for removal.
867#if 0
868 notifyProxy (!!aRegistered);
869#endif
870
871 return S_OK;
872}
873
874/**
875 * Called by setter methods of all USB device filters.
876 */
877HRESULT USBController::onDeviceFilterChange (USBDeviceFilter *aFilter,
878 BOOL aActiveChanged /* = FALSE */)
879{
880 AutoLock alock (this);
881 CHECK_READY();
882
883 /// @todo After rewriting Win32 USB support, no more necessary;
884 // a candidate for removal.
885#if 0
886#else
887 /* we need the machine state */
888 Machine::AutoStateDependency <Machine::MutableStateDep> adep (m_Parent);
889 AssertComRCReturnRC (adep.rc());
890
891 /* nothing to do if the machine isn't running */
892 if (adep.machineState() < MachineState_Running)
893 return S_OK;
894#endif
895
896 if (aFilter->mInList && m_Parent->isRegistered())
897 {
898 USBProxyService *service = m_Parent->virtualBox()->host()->usbProxyService();
899 ComAssertRet (service, E_FAIL);
900
901 if (aActiveChanged)
902 {
903 /* insert/remove the filter from the proxy */
904 if (aFilter->data().mActive)
905 {
906 ComAssertRet (aFilter->id() == NULL, E_FAIL);
907 aFilter->id() = service->insertFilter
908 (ComPtr <IUSBDeviceFilter> (aFilter));
909 }
910 else
911 {
912 ComAssertRet (aFilter->id() != NULL, E_FAIL);
913 service->removeFilter (aFilter->id());
914 aFilter->id() = NULL;
915 }
916 }
917 else
918 {
919 if (aFilter->data().mActive)
920 {
921 /* update the filter in the proxy */
922 ComAssertRet (aFilter->id() != NULL, E_FAIL);
923 service->removeFilter (aFilter->id());
924 aFilter->id() = service->insertFilter
925 (ComPtr <IUSBDeviceFilter> (aFilter));
926 }
927 }
928 }
929
930 return S_OK;
931}
932
933/**
934 * Returns true if the given USB device matches to at least one of
935 * this controller's USB device filters.
936 *
937 * A HostUSBDevice specific version.
938 */
939bool USBController::hasMatchingFilter (ComObjPtr <HostUSBDevice> &aDevice)
940{
941 AutoLock alock (this);
942 if (!isReady())
943 return false;
944
945 bool match = false;
946
947 // apply self filters
948 for (DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
949 !match && it != m_DeviceFilters->end();
950 ++ it)
951 {
952 AutoLock filterLock (*it);
953 match = aDevice->isMatch ((*it)->data());
954 }
955
956 return match;
957}
958
959/**
960 * Returns true if the given USB device matches to at least one of
961 * this controller's USB device filters.
962 *
963 * A generic version that accepts any IUSBDevice on input.
964 *
965 * @note
966 * This method MUST correlate with HostUSBDevice::isMatch()
967 * in the sense of the device matching logic.
968 */
969bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice)
970{
971 LogFlowThisFunc (("\n"));
972
973 AutoLock alock (this);
974 if (!isReady())
975 return false;
976
977 HRESULT rc = S_OK;
978
979 // query fields
980
981 USHORT vendorId = 0;
982 rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
983 ComAssertComRCRet (rc, false);
984 ComAssertRet (vendorId, false);
985
986 USHORT productId = 0;
987 rc = aUSBDevice->COMGETTER(ProductId) (&productId);
988 ComAssertComRCRet (rc, false);
989 ComAssertRet (productId, false);
990
991 USHORT revision;
992 rc = aUSBDevice->COMGETTER(Revision) (&revision);
993 ComAssertComRCRet (rc, false);
994
995 Bstr manufacturer;
996 rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
997 ComAssertComRCRet (rc, false);
998
999 Bstr product;
1000 rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
1001 ComAssertComRCRet (rc, false);
1002
1003 Bstr serialNumber;
1004 rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
1005 ComAssertComRCRet (rc, false);
1006
1007 Bstr address;
1008 rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
1009 ComAssertComRCRet (rc, false);
1010
1011 USHORT port = 0;
1012 rc = aUSBDevice->COMGETTER(Port)(&port);
1013 ComAssertComRCRet (rc, false);
1014
1015 BOOL remote = FALSE;
1016 rc = aUSBDevice->COMGETTER(Remote)(&remote);
1017 ComAssertComRCRet (rc, false);
1018 ComAssertRet (remote == TRUE, false);
1019
1020 bool match = false;
1021
1022 // apply self filters
1023 for (DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
1024 it != m_DeviceFilters->end();
1025 ++ it)
1026 {
1027 AutoLock filterLock (*it);
1028 const USBDeviceFilter::Data &aData = (*it)->data();
1029
1030 if (!aData.mActive)
1031 continue;
1032 if (!aData.mVendorId.isMatch (vendorId))
1033 continue;
1034 if (!aData.mProductId.isMatch (productId))
1035 continue;
1036 if (!aData.mRevision.isMatch (revision))
1037 continue;
1038
1039#if !defined (__WIN__)
1040 // these filters are temporarily ignored on Win32
1041 if (!aData.mManufacturer.isMatch (manufacturer))
1042 continue;
1043 if (!aData.mProduct.isMatch (product))
1044 continue;
1045 if (!aData.mSerialNumber.isMatch (serialNumber))
1046 continue;
1047 if (!aData.mPort.isMatch (port))
1048 continue;
1049#endif
1050
1051 if (!aData.mRemote.isMatch (remote))
1052 continue;
1053
1054 match = true;
1055 break;
1056 }
1057
1058 LogFlowMember (("USBController::hasMatchingFilter() returns: %d\n", match));
1059 return match;
1060}
1061
1062HRESULT USBController::notifyProxy (bool aInsertFilters)
1063{
1064 LogFlowThisFunc (("aInsertFilters=%RTbool\n", aInsertFilters));
1065
1066 AutoLock alock (this);
1067 if (!isReady())
1068 return false;
1069
1070 USBProxyService *service = m_Parent->virtualBox()->host()->usbProxyService();
1071 AssertReturn (service, E_FAIL);
1072
1073 DeviceFilterList::const_iterator it = m_DeviceFilters->begin();
1074 while (it != m_DeviceFilters->end())
1075 {
1076 USBDeviceFilter *flt = *it; /* resolve ambiguity (for ComPtr below) */
1077
1078 /* notify the proxy (only if the filter is active) */
1079 if (flt->data().mActive)
1080 {
1081 if (aInsertFilters)
1082 {
1083 AssertReturn (flt->id() == NULL, E_FAIL);
1084 flt->id() = service->insertFilter
1085 (ComPtr <IUSBDeviceFilter> (flt));
1086 }
1087 else
1088 {
1089 AssertReturn (flt->id() != NULL, E_FAIL);
1090 service->removeFilter (flt->id());
1091 flt->id() = NULL;
1092 }
1093 }
1094 ++ it;
1095 }
1096
1097 return S_OK;
1098}
1099
1100// private methods
1101/////////////////////////////////////////////////////////////////////////////
1102
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette