VirtualBox

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

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

Main: coding style

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