VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBDeviceFiltersImpl.cpp@ 47469

Last change on this file since 47469 was 47401, checked in by vboxsync, 11 years ago

Main,Frontends: Second step of USB controller rework. There is one controller instance for every USB controller now. Adapt frontends and testsuite to work with the changed API

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

© 2023 Oracle
ContactPrivacy policyTerms of Use