[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] | 58 | typedef std::list< ComObjPtr<USBDeviceFilter> > DeviceFilterList;
|
---|
| 59 |
|
---|
[47376] | 60 | struct 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] | 87 | DEFINE_EMPTY_CTOR_DTOR(USBDeviceFilters)
|
---|
[2845] | 88 |
|
---|
[47376] | 89 | HRESULT USBDeviceFilters::FinalConstruct()
|
---|
[1] | 90 | {
|
---|
[35638] | 91 | return BaseFinalConstruct();
|
---|
[1] | 92 | }
|
---|
| 93 |
|
---|
[47376] | 94 | void 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] | 109 | HRESULT 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] | 144 | HRESULT 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] | 186 | HRESULT 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] | 227 | void 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] | 263 | class ATL_NO_VTABLE USBDeviceFilter :
|
---|
[21660] | 264 | public VirtualBoxBase,
|
---|
[30856] | 265 | VBOX_SCRIPTABLE_IMPL(IUSBDeviceFilter)
|
---|
[7964] | 266 | {
|
---|
| 267 | public:
|
---|
| 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] | 306 | HRESULT 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] | 327 | HRESULT 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 |
|
---|
| 355 | HRESULT 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] | 416 | HRESULT 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] | 494 | HRESULT 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] | 539 | HRESULT 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] | 588 | void 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] | 680 | void 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] | 775 | void 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] | 826 | HRESULT 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] | 892 | bool 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] | 931 | bool 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] | 1037 | HRESULT 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] | 1082 | Machine* 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: */
|
---|