VirtualBox

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

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

Main: Eliminate the last bits of VirtualBoxBaseWithChildrenNEXT. It won't be missed.

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

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