VirtualBox

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

Last change on this file since 25194 was 25194, checked in by vboxsync, 15 years ago

Main: stop USBController from being a VirtualBoxBaseWithChildren; make its instance data private

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