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

© 2023 Oracle
ContactPrivacy policyTerms of Use