VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBControllerImpl.cpp@ 38432

Last change on this file since 38432 was 38432, checked in by vboxsync, 14 years ago

Main/USB: don't propagate remote filtera to USBProxyService

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