VirtualBox

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

Last change on this file since 73768 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.7 KB
Line 
1/* $Id: USBDeviceFiltersImpl.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * Implementation of IUSBDeviceFilters.
4 */
5
6/*
7 * Copyright (C) 2005-2017 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->i_getVirtualBox()->i_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 COM_INTERFACE_ENTRY(ISupportErrorInfo)
261 COM_INTERFACE_ENTRY(IUSBDeviceFilter)
262 COM_INTERFACE_ENTRY2(IDispatch, IUSBDeviceFilter)
263 VBOX_TWEAK_INTERFACE_ENTRY(IUSBDeviceFilter)
264 END_COM_MAP()
265
266 DECLARE_EMPTY_CTOR_DTOR(USBDeviceFilter)
267
268 // IUSBDeviceFilter properties
269 STDMETHOD(COMGETTER(Name))(BSTR *aName);
270 STDMETHOD(COMSETTER(Name))(IN_BSTR aName);
271 STDMETHOD(COMGETTER(Active))(BOOL *aActive);
272 STDMETHOD(COMSETTER(Active))(BOOL aActive);
273 STDMETHOD(COMGETTER(VendorId))(BSTR *aVendorId);
274 STDMETHOD(COMSETTER(VendorId))(IN_BSTR aVendorId);
275 STDMETHOD(COMGETTER(ProductId))(BSTR *aProductId);
276 STDMETHOD(COMSETTER(ProductId))(IN_BSTR aProductId);
277 STDMETHOD(COMGETTER(Revision))(BSTR *aRevision);
278 STDMETHOD(COMSETTER(Revision))(IN_BSTR aRevision);
279 STDMETHOD(COMGETTER(Manufacturer))(BSTR *aManufacturer);
280 STDMETHOD(COMSETTER(Manufacturer))(IN_BSTR aManufacturer);
281 STDMETHOD(COMGETTER(Product))(BSTR *aProduct);
282 STDMETHOD(COMSETTER(Product))(IN_BSTR aProduct);
283 STDMETHOD(COMGETTER(SerialNumber))(BSTR *aSerialNumber);
284 STDMETHOD(COMSETTER(SerialNumber))(IN_BSTR aSerialNumber);
285 STDMETHOD(COMGETTER(Port))(BSTR *aPort);
286 STDMETHOD(COMSETTER(Port))(IN_BSTR aPort);
287 STDMETHOD(COMGETTER(Remote))(BSTR *aRemote);
288 STDMETHOD(COMSETTER(Remote))(IN_BSTR aRemote);
289 STDMETHOD(COMGETTER(MaskedInterfaces))(ULONG *aMaskedIfs);
290 STDMETHOD(COMSETTER(MaskedInterfaces))(ULONG aMaskedIfs);
291};
292#endif /* !VBOX_WITH_USB */
293
294
295HRESULT USBDeviceFilters::getDeviceFilters(std::vector<ComPtr<IUSBDeviceFilter> > &aDeviceFilters)
296{
297#ifdef VBOX_WITH_USB
298 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
299
300 SafeIfaceArray<IUSBDeviceFilter> collection(*m->llDeviceFilters.data());
301 aDeviceFilters.resize(collection.size());
302 if (collection.size())
303 for (size_t i = 0; i < collection.size(); ++i)
304 aDeviceFilters[i] = collection[i];
305
306 return S_OK;
307#else
308 NOREF(aDeviceFilters);
309# ifndef RT_OS_WINDOWS
310 NOREF(aDeviceFilters);
311# endif
312 ReturnComNotImplemented();
313#endif
314}
315
316// wrapped IUSBDeviceFilters methods
317/////////////////////////////////////////////////////////////////////////////
318
319HRESULT USBDeviceFilters::createDeviceFilter(const com::Utf8Str &aName,
320 ComPtr<IUSBDeviceFilter> &aFilter)
321
322{
323#ifdef VBOX_WITH_USB
324
325 /* the machine needs to be mutable */
326 AutoMutableOrSavedOrRunningStateDependency adep(m->pParent);
327 if (FAILED(adep.rc())) return adep.rc();
328
329 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
330
331 ComObjPtr<USBDeviceFilter> pFilter;
332 pFilter.createObject();
333 HRESULT rc = pFilter->init(this, Bstr(aName).raw());
334 ComAssertComRCRetRC(rc);
335 rc = pFilter.queryInterfaceTo(aFilter.asOutParam());
336 AssertComRCReturnRC(rc);
337
338 return S_OK;
339#else
340 NOREF(aName);
341 NOREF(aFilter);
342 ReturnComNotImplemented();
343#endif
344}
345
346
347HRESULT USBDeviceFilters::insertDeviceFilter(ULONG aPosition,
348 const ComPtr<IUSBDeviceFilter> &aFilter)
349{
350#ifdef VBOX_WITH_USB
351
352 /* the machine needs to be mutable */
353 AutoMutableOrSavedOrRunningStateDependency adep(m->pParent);
354 if (FAILED(adep.rc())) return adep.rc();
355
356 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
357
358 IUSBDeviceFilter *iFilter = aFilter;
359 ComObjPtr<USBDeviceFilter> pFilter = static_cast<USBDeviceFilter*>(iFilter);
360
361 if (pFilter->mInList)
362 return setError(VBOX_E_INVALID_OBJECT_STATE,
363 tr("The given USB device pFilter is already in the list"));
364
365 /* backup the list before modification */
366 m->llDeviceFilters.backup();
367
368 /* iterate to the position... */
369 DeviceFilterList::iterator it;
370 if (aPosition < m->llDeviceFilters->size())
371 {
372 it = m->llDeviceFilters->begin();
373 std::advance(it, aPosition);
374 }
375 else
376 it = m->llDeviceFilters->end();
377 /* ...and insert */
378 m->llDeviceFilters->insert(it, pFilter);
379 pFilter->mInList = true;
380
381 /* notify the proxy (only when it makes sense) */
382 if (pFilter->i_getData().mData.fActive && Global::IsOnline(adep.machineState())
383 && pFilter->i_getData().mRemote.isMatch(false))
384 {
385 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
386 ComAssertRet(pProxySvc, E_FAIL);
387
388 ComAssertRet(pFilter->i_getId() == NULL, E_FAIL);
389 pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter);
390 }
391
392 alock.release();
393 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
394 m->pParent->i_setModified(Machine::IsModified_USB);
395 mlock.release();
396
397 return S_OK;
398
399#else /* VBOX_WITH_USB */
400
401 NOREF(aPosition);
402 NOREF(aFilter);
403 ReturnComNotImplemented();
404
405#endif /* VBOX_WITH_USB */
406}
407
408HRESULT USBDeviceFilters::removeDeviceFilter(ULONG aPosition,
409 ComPtr<IUSBDeviceFilter> &aFilter)
410{
411#ifdef VBOX_WITH_USB
412 /* the machine needs to be mutable */
413 AutoMutableOrSavedOrRunningStateDependency adep(m->pParent);
414 if (FAILED(adep.rc())) return adep.rc();
415
416 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
417
418 if (!m->llDeviceFilters->size())
419 return setError(E_INVALIDARG,
420 tr("The USB device pFilter list is empty"));
421
422 if (aPosition >= m->llDeviceFilters->size())
423 return setError(E_INVALIDARG,
424 tr("Invalid position: %lu (must be in range [0, %lu])"),
425 aPosition, m->llDeviceFilters->size() - 1);
426
427 /* backup the list before modification */
428 m->llDeviceFilters.backup();
429
430 ComObjPtr<USBDeviceFilter> pFilter;
431 {
432 /* iterate to the position... */
433 DeviceFilterList::iterator it = m->llDeviceFilters->begin();
434 std::advance(it, aPosition);
435 /* ...get an element from there... */
436 pFilter = *it;
437 /* ...and remove */
438 pFilter->mInList = false;
439 m->llDeviceFilters->erase(it);
440 }
441
442 /* cancel sharing (make an independent copy of data) */
443 pFilter->unshare();
444 pFilter.queryInterfaceTo(aFilter.asOutParam());
445
446
447 /* notify the proxy (only when it makes sense) */
448 if (pFilter->i_getData().mData.fActive && Global::IsOnline(adep.machineState())
449 && pFilter->i_getData().mRemote.isMatch(false))
450 {
451 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
452 ComAssertRet(pProxySvc, E_FAIL);
453
454 ComAssertRet(pFilter->i_getId() != NULL, E_FAIL);
455 pProxySvc->removeFilter(pFilter->i_getId());
456 pFilter->i_getId() = NULL;
457 }
458
459 alock.release();
460 AutoWriteLock mlock(m->pParent COMMA_LOCKVAL_SRC_POS);
461 m->pParent->i_setModified(Machine::IsModified_USB);
462 mlock.release();
463
464 return S_OK;
465
466#else /* VBOX_WITH_USB */
467
468 NOREF(aPosition);
469 NOREF(aFilter);
470 ReturnComNotImplemented();
471
472#endif /* VBOX_WITH_USB */
473}
474
475// public methods only for internal purposes
476/////////////////////////////////////////////////////////////////////////////
477
478/**
479 * Loads settings from the given machine node.
480 * May be called once right after this object creation.
481 *
482 * @param data Configuration settings.
483 *
484 * @note Does not lock "this" as Machine::loadHardware, which calls this, does not lock either.
485 */
486HRESULT USBDeviceFilters::i_loadSettings(const settings::USB &data)
487{
488 AutoCaller autoCaller(this);
489 AssertComRCReturnRC(autoCaller.rc());
490
491 /* Note: we assume that the default values for attributes of optional
492 * nodes are assigned in the Data::Data() constructor and don't do it
493 * here. It implies that this method may only be called after constructing
494 * a new USBDeviceFilters object while all its data fields are in the default
495 * values. Exceptions are fields whose creation time defaults don't match
496 * values that should be applied when these fields are not explicitly set
497 * in the settings file (for backwards compatibility reasons). This takes
498 * place when a setting of a newly created object must default to A while
499 * the same setting of an object loaded from the old settings file must
500 * default to B. */
501
502#ifdef VBOX_WITH_USB
503 for (settings::USBDeviceFiltersList::const_iterator it = data.llDeviceFilters.begin();
504 it != data.llDeviceFilters.end();
505 ++it)
506 {
507 const settings::USBDeviceFilter &f = *it;
508 ComObjPtr<USBDeviceFilter> pFilter;
509 pFilter.createObject();
510 HRESULT rc = pFilter->init(this, // parent
511 f);
512 if (FAILED(rc)) return rc;
513
514 m->llDeviceFilters->push_back(pFilter);
515 pFilter->mInList = true;
516 }
517#endif /* VBOX_WITH_USB */
518
519 return S_OK;
520}
521
522/**
523 * Saves settings to the given machine node.
524 *
525 * @param data Configuration settings.
526 *
527 * @note Locks this object for reading.
528 */
529HRESULT USBDeviceFilters::i_saveSettings(settings::USB &data)
530{
531 AutoCaller autoCaller(this);
532 if (FAILED(autoCaller.rc())) return autoCaller.rc();
533
534 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
535
536#ifdef VBOX_WITH_USB
537 data.llDeviceFilters.clear();
538
539 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
540 it != m->llDeviceFilters->end();
541 ++it)
542 {
543 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
544 const USBDeviceFilter::BackupableUSBDeviceFilterData &filterData = (*it)->i_getData();
545
546 Bstr str;
547
548 settings::USBDeviceFilter f;
549 f.strName = filterData.mData.strName;
550 f.fActive = !!filterData.mData.fActive;
551 (*it)->COMGETTER(VendorId)(str.asOutParam());
552 f.strVendorId = str;
553 (*it)->COMGETTER(ProductId)(str.asOutParam());
554 f.strProductId = str;
555 (*it)->COMGETTER(Revision)(str.asOutParam());
556 f.strRevision = str;
557 (*it)->COMGETTER(Manufacturer)(str.asOutParam());
558 f.strManufacturer = str;
559 (*it)->COMGETTER(Product)(str.asOutParam());
560 f.strProduct = str;
561 (*it)->COMGETTER(SerialNumber)(str.asOutParam());
562 f.strSerialNumber = str;
563 (*it)->COMGETTER(Port)(str.asOutParam());
564 f.strPort = str;
565 f.strRemote = filterData.mRemote.string();
566 f.ulMaskedInterfaces = filterData.mData.ulMaskedInterfaces;
567
568 data.llDeviceFilters.push_back(f);
569 }
570#endif /* VBOX_WITH_USB */
571
572 return S_OK;
573}
574
575/** @note Locks objects for writing! */
576void USBDeviceFilters::i_rollback()
577{
578 AutoCaller autoCaller(this);
579 AssertComRCReturnVoid(autoCaller.rc());
580
581 /* we need the machine state */
582 AutoAnyStateDependency adep(m->pParent);
583 AssertComRCReturnVoid(adep.rc());
584
585 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
586
587#ifdef VBOX_WITH_USB
588
589 if (m->llDeviceFilters.isBackedUp())
590 {
591 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
592 Assert(pProxySvc);
593
594 /* uninitialize all new filters (absent in the backed up list) */
595 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
596 DeviceFilterList *backedList = m->llDeviceFilters.backedUpData();
597 while (it != m->llDeviceFilters->end())
598 {
599 if (std::find(backedList->begin(), backedList->end(), *it) ==
600 backedList->end())
601 {
602 /* notify the proxy (only when it makes sense) */
603 if ((*it)->i_getData().mData.fActive &&
604 Global::IsOnline(adep.machineState())
605 && (*it)->i_getData().mRemote.isMatch(false))
606 {
607 USBDeviceFilter *pFilter = *it;
608 Assert(pFilter->i_getId() != NULL);
609 pProxySvc->removeFilter(pFilter->i_getId());
610 pFilter->i_getId() = NULL;
611 }
612
613 (*it)->uninit();
614 }
615 ++it;
616 }
617
618 if (Global::IsOnline(adep.machineState()))
619 {
620 /* find all removed old filters (absent in the new list)
621 * and insert them back to the USB proxy */
622 it = backedList->begin();
623 while (it != backedList->end())
624 {
625 if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) ==
626 m->llDeviceFilters->end())
627 {
628 /* notify the proxy (only when necessary) */
629 if ((*it)->i_getData().mData.fActive
630 && (*it)->i_getData().mRemote.isMatch(false))
631 {
632 USBDeviceFilter *pFilter = *it; /* resolve ambiguity */
633 Assert(pFilter->i_getId() == NULL);
634 pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter);
635 }
636 }
637 ++it;
638 }
639 }
640
641 /* restore the list */
642 m->llDeviceFilters.rollback();
643 }
644
645 /* here we don't depend on the machine state any more */
646 adep.release();
647
648 /* rollback any changes to filters after restoring the list */
649 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
650 while (it != m->llDeviceFilters->end())
651 {
652 if ((*it)->i_isModified())
653 {
654 (*it)->i_rollback();
655 /* call this to notify the USB proxy about changes */
656 i_onDeviceFilterChange(*it);
657 }
658 ++it;
659 }
660
661#endif /* VBOX_WITH_USB */
662}
663
664/**
665 * @note Locks this object for writing, together with the peer object (also
666 * for writing) if there is one.
667 */
668void USBDeviceFilters::i_commit()
669{
670 /* sanity */
671 AutoCaller autoCaller(this);
672 AssertComRCReturnVoid(autoCaller.rc());
673
674 /* sanity too */
675 AutoCaller peerCaller(m->pPeer);
676 AssertComRCReturnVoid(peerCaller.rc());
677
678 /* lock both for writing since we modify both (mPeer is "master" so locked
679 * first) */
680 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
681
682#ifdef VBOX_WITH_USB
683 bool commitFilters = false;
684
685 if (m->llDeviceFilters.isBackedUp())
686 {
687 m->llDeviceFilters.commit();
688
689 /* apply changes to peer */
690 if (m->pPeer)
691 {
692 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
693
694 /* commit all changes to new filters (this will reshare data with
695 * peers for those who have peers) */
696 DeviceFilterList *newList = new DeviceFilterList();
697 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
698 while (it != m->llDeviceFilters->end())
699 {
700 (*it)->i_commit();
701
702 /* look if this filter has a peer filter */
703 ComObjPtr<USBDeviceFilter> peer = (*it)->i_peer();
704 if (!peer)
705 {
706 /* no peer means the filter is a newly created one;
707 * create a peer owning data this filter share it with */
708 peer.createObject();
709 peer->init(m->pPeer, *it, true /* aReshare */);
710 }
711 else
712 {
713 /* remove peer from the old list */
714 m->pPeer->m->llDeviceFilters->remove(peer);
715 }
716 /* and add it to the new list */
717 newList->push_back(peer);
718
719 ++it;
720 }
721
722 /* uninit old peer's filters that are left */
723 it = m->pPeer->m->llDeviceFilters->begin();
724 while (it != m->pPeer->m->llDeviceFilters->end())
725 {
726 (*it)->uninit();
727 ++it;
728 }
729
730 /* attach new list of filters to our peer */
731 m->pPeer->m->llDeviceFilters.attach(newList);
732 }
733 else
734 {
735 /* we have no peer (our parent is the newly created machine);
736 * just commit changes to filters */
737 commitFilters = true;
738 }
739 }
740 else
741 {
742 /* the list of filters itself is not changed,
743 * just commit changes to filters themselves */
744 commitFilters = true;
745 }
746
747 if (commitFilters)
748 {
749 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
750 while (it != m->llDeviceFilters->end())
751 {
752 (*it)->i_commit();
753 ++it;
754 }
755 }
756#endif /* VBOX_WITH_USB */
757}
758
759/**
760 * @note Locks this object for writing, together with the peer object
761 * represented by @a aThat (locked for reading).
762 */
763void USBDeviceFilters::i_copyFrom(USBDeviceFilters *aThat)
764{
765 AssertReturnVoid(aThat != NULL);
766
767 /* sanity */
768 AutoCaller autoCaller(this);
769 AssertComRCReturnVoid(autoCaller.rc());
770
771 /* sanity too */
772 AutoCaller thatCaller(aThat);
773 AssertComRCReturnVoid(thatCaller.rc());
774
775 /* even more sanity */
776 AutoAnyStateDependency adep(m->pParent);
777 AssertComRCReturnVoid(adep.rc());
778 /* Machine::copyFrom() may not be called when the VM is running */
779 AssertReturnVoid(!Global::IsOnline(adep.machineState()));
780
781 /* peer is not modified, lock it for reading (aThat is "master" so locked
782 * first) */
783 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
784 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
785
786#ifdef VBOX_WITH_USB
787
788 /* Note that we won't inform the USB proxy about new filters since the VM is
789 * not running when we are here and therefore no need to do so */
790
791 /* create private copies of all filters */
792 m->llDeviceFilters.backup();
793 m->llDeviceFilters->clear();
794 for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin();
795 it != aThat->m->llDeviceFilters->end();
796 ++it)
797 {
798 ComObjPtr<USBDeviceFilter> pFilter;
799 pFilter.createObject();
800 pFilter->initCopy(this, *it);
801 m->llDeviceFilters->push_back(pFilter);
802 }
803
804#endif /* VBOX_WITH_USB */
805}
806
807#ifdef VBOX_WITH_USB
808
809/**
810 * Called by setter methods of all USB device filters.
811 *
812 * @note Locks nothing.
813 */
814HRESULT USBDeviceFilters::i_onDeviceFilterChange(USBDeviceFilter *aFilter,
815 BOOL aActiveChanged /* = FALSE */)
816{
817 AutoCaller autoCaller(this);
818 AssertComRCReturnRC(autoCaller.rc());
819
820 /* we need the machine state */
821 AutoAnyStateDependency adep(m->pParent);
822 AssertComRCReturnRC(adep.rc());
823
824 /* nothing to do if the machine isn't running */
825 if (!Global::IsOnline(adep.machineState()))
826 return S_OK;
827
828 /* we don't modify our data fields -- no need to lock */
829
830 if ( aFilter->mInList
831 && m->pParent->i_isRegistered())
832 {
833 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
834 ComAssertRet(pProxySvc, E_FAIL);
835
836 if (aActiveChanged)
837 {
838 if (aFilter->i_getData().mRemote.isMatch(false))
839 {
840 /* insert/remove the filter from the proxy */
841 if (aFilter->i_getData().mData.fActive)
842 {
843 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
844 aFilter->i_getId() = pProxySvc->insertFilter(&aFilter->i_getData().mUSBFilter);
845 }
846 else
847 {
848 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
849 pProxySvc->removeFilter(aFilter->i_getId());
850 aFilter->i_getId() = NULL;
851 }
852 }
853 }
854 else
855 {
856 if (aFilter->i_getData().mData.fActive)
857 {
858 /* update the filter in the proxy */
859 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
860 pProxySvc->removeFilter(aFilter->i_getId());
861 if (aFilter->i_getData().mRemote.isMatch(false))
862 {
863 aFilter->i_getId() = pProxySvc->insertFilter(&aFilter->i_getData().mUSBFilter);
864 }
865 }
866 }
867 }
868
869 return S_OK;
870}
871
872/**
873 * Returns true if the given USB device matches to at least one of
874 * this controller's USB device filters.
875 *
876 * A HostUSBDevice specific version.
877 *
878 * @note Locks this object for reading.
879 */
880bool USBDeviceFilters::i_hasMatchingFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
881{
882 AutoCaller autoCaller(this);
883 AssertComRCReturn(autoCaller.rc(), false);
884
885 /* It is not possible to work with USB device if there is no USB controller present. */
886 if (!m->pParent->i_isUSBControllerPresent())
887 return false;
888
889 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
890
891 /* apply self filters */
892 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
893 it != m->llDeviceFilters->end();
894 ++it)
895 {
896 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
897 if (aDevice->i_isMatch((*it)->i_getData()))
898 {
899 *aMaskedIfs = (*it)->i_getData().mData.ulMaskedInterfaces;
900 return true;
901 }
902 }
903
904 return false;
905}
906
907/**
908 * Returns true if the given USB device matches to at least one of
909 * this controller's USB device filters.
910 *
911 * A generic version that accepts any IUSBDevice on input.
912 *
913 * @note
914 * This method MUST correlate with HostUSBDevice::isMatch()
915 * in the sense of the device matching logic.
916 *
917 * @note Locks this object for reading.
918 */
919bool USBDeviceFilters::i_hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
920{
921 LogFlowThisFuncEnter();
922
923 AutoCaller autoCaller(this);
924 AssertComRCReturn(autoCaller.rc(), false);
925
926 /* It is not possible to work with USB device if there is no USB controller present. */
927 if (!m->pParent->i_isUSBControllerPresent())
928 return false;
929
930 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
931
932 HRESULT rc = S_OK;
933
934 /* query fields */
935 USBFILTER dev;
936 USBFilterInit(&dev, USBFILTERTYPE_CAPTURE);
937
938 USHORT vendorId = 0;
939 rc = aUSBDevice->COMGETTER(VendorId)(&vendorId);
940 ComAssertComRCRet(rc, false);
941 ComAssertRet(vendorId, false);
942 int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
943
944 USHORT productId = 0;
945 rc = aUSBDevice->COMGETTER(ProductId)(&productId);
946 ComAssertComRCRet(rc, false);
947 vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
948
949 USHORT revision;
950 rc = aUSBDevice->COMGETTER(Revision)(&revision);
951 ComAssertComRCRet(rc, false);
952 vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
953
954 Bstr manufacturer;
955 rc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam());
956 ComAssertComRCRet(rc, false);
957 if (!manufacturer.isEmpty())
958 USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(),
959 true /*fMustBePresent*/, false /*fPurge*/);
960
961 Bstr product;
962 rc = aUSBDevice->COMGETTER(Product)(product.asOutParam());
963 ComAssertComRCRet(rc, false);
964 if (!product.isEmpty())
965 USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(),
966 true /*fMustBePresent*/, false /*fPurge*/);
967
968 Bstr serialNumber;
969 rc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam());
970 ComAssertComRCRet(rc, false);
971 if (!serialNumber.isEmpty())
972 USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(),
973 true /*fMustBePresent*/, false /*fPurge*/);
974
975 Bstr address;
976 rc = aUSBDevice->COMGETTER(Address)(address.asOutParam());
977 ComAssertComRCRet(rc, false);
978
979 USHORT port = 0;
980 rc = aUSBDevice->COMGETTER(Port)(&port);
981 ComAssertComRCRet(rc, false);
982 USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true);
983
984 BOOL remote = FALSE;
985 rc = aUSBDevice->COMGETTER(Remote)(&remote);
986 ComAssertComRCRet(rc, false);
987 ComAssertRet(remote == TRUE, false);
988
989 bool match = false;
990
991 /* apply self filters */
992 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
993 it != m->llDeviceFilters->end();
994 ++it)
995 {
996 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
997 const USBDeviceFilter::BackupableUSBDeviceFilterData &aData = (*it)->i_getData();
998
999 if (!aData.mData.fActive)
1000 continue;
1001 if (!aData.mRemote.isMatch(remote))
1002 continue;
1003 if (!USBFilterMatch(&aData.mUSBFilter, &dev))
1004 continue;
1005
1006 match = true;
1007 *aMaskedIfs = aData.mData.ulMaskedInterfaces;
1008 break;
1009 }
1010
1011 LogFlowThisFunc(("returns: %d\n", match));
1012 LogFlowThisFuncLeave();
1013
1014 return match;
1015}
1016
1017/**
1018 * Notifies the proxy pProxySvc about all filters as requested by the
1019 * @a aInsertFilters argument.
1020 *
1021 * @param aInsertFilters @c true to insert filters, @c false to remove.
1022 *
1023 * @note Locks this object for reading.
1024 */
1025HRESULT USBDeviceFilters::i_notifyProxy(bool aInsertFilters)
1026{
1027 LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters));
1028
1029 AutoCaller autoCaller(this);
1030 AssertComRCReturn(autoCaller.rc(), false);
1031
1032 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1033
1034 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
1035 AssertReturn(pProxySvc, E_FAIL);
1036
1037 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
1038 while (it != m->llDeviceFilters->end())
1039 {
1040 USBDeviceFilter *pFilter = *it; /* resolve ambiguity (for ComPtr below) */
1041
1042 /* notify the proxy (only if the filter is active) */
1043 if ( pFilter->i_getData().mData.fActive
1044 && pFilter->i_getData().mRemote.isMatch(false) /* and if the filter is NOT remote */
1045 )
1046 {
1047 if (aInsertFilters)
1048 {
1049 AssertReturn(pFilter->i_getId() == NULL, E_FAIL);
1050 pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter);
1051 }
1052 else
1053 {
1054 /* It's possible that the given filter was not inserted the proxy
1055 * when this method gets called (as a result of an early VM
1056 * process crash for example. So, don't assert that ID != NULL. */
1057 if (pFilter->i_getId() != NULL)
1058 {
1059 pProxySvc->removeFilter(pFilter->i_getId());
1060 pFilter->i_getId() = NULL;
1061 }
1062 }
1063 }
1064 ++it;
1065 }
1066
1067 return S_OK;
1068}
1069
1070Machine* USBDeviceFilters::i_getMachine()
1071{
1072 return m->pParent;
1073}
1074
1075#endif /* VBOX_WITH_USB */
1076
1077// private methods
1078/////////////////////////////////////////////////////////////////////////////
1079/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use