VirtualBox

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

Last change on this file since 98262 was 98262, checked in by vboxsync, 17 months ago

Main: rc() -> hrc()/vrc(). bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use