VirtualBox

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

Last change on this file since 98351 was 98292, checked in by vboxsync, 23 months ago

Main/src-server: rc -> hrc/vrc. Enabled scm rc checks. 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 98292 2023-01-25 01:14:53Z 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 hrc = pFilter->init(this, Bstr(aName).raw());
342 ComAssertComRCRetRC(hrc);
343 hrc = pFilter.queryInterfaceTo(aFilter.asOutParam());
344 AssertComRCReturnRC(hrc);
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 hrc = pFilter->init(this /*aParent*/, f);
519 if (FAILED(hrc)) return hrc;
520
521 m->llDeviceFilters->push_back(pFilter);
522 pFilter->mInList = true;
523 }
524#else
525 RT_NOREF(data);
526#endif /* VBOX_WITH_USB */
527
528 return S_OK;
529}
530
531/**
532 * Saves settings to the given machine node.
533 *
534 * @param data Configuration settings.
535 *
536 * @note Locks this object for reading.
537 */
538HRESULT USBDeviceFilters::i_saveSettings(settings::USB &data)
539{
540 AutoCaller autoCaller(this);
541 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
542
543 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
544
545#ifdef VBOX_WITH_USB
546 data.llDeviceFilters.clear();
547
548 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
549 it != m->llDeviceFilters->end();
550 ++it)
551 {
552 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
553 const USBDeviceFilter::BackupableUSBDeviceFilterData &filterData = (*it)->i_getData();
554
555 Bstr str;
556
557 settings::USBDeviceFilter f;
558 f.strName = filterData.mData.strName;
559 f.fActive = !!filterData.mData.fActive;
560 (*it)->COMGETTER(VendorId)(str.asOutParam());
561 f.strVendorId = str;
562 (*it)->COMGETTER(ProductId)(str.asOutParam());
563 f.strProductId = str;
564 (*it)->COMGETTER(Revision)(str.asOutParam());
565 f.strRevision = str;
566 (*it)->COMGETTER(Manufacturer)(str.asOutParam());
567 f.strManufacturer = str;
568 (*it)->COMGETTER(Product)(str.asOutParam());
569 f.strProduct = str;
570 (*it)->COMGETTER(SerialNumber)(str.asOutParam());
571 f.strSerialNumber = str;
572 (*it)->COMGETTER(Port)(str.asOutParam());
573 f.strPort = str;
574 f.strRemote = filterData.mRemote.string();
575 f.ulMaskedInterfaces = filterData.mData.ulMaskedInterfaces;
576
577 data.llDeviceFilters.push_back(f);
578 }
579#else
580 RT_NOREF(data);
581#endif /* VBOX_WITH_USB */
582
583 return S_OK;
584}
585
586/** @note Locks objects for writing! */
587void USBDeviceFilters::i_rollback()
588{
589 AutoCaller autoCaller(this);
590 AssertComRCReturnVoid(autoCaller.hrc());
591
592 /* we need the machine state */
593 AutoAnyStateDependency adep(m->pParent);
594 AssertComRCReturnVoid(adep.hrc());
595
596 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
597
598#ifdef VBOX_WITH_USB
599
600 if (m->llDeviceFilters.isBackedUp())
601 {
602 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
603 Assert(pProxySvc);
604
605 /* uninitialize all new filters (absent in the backed up list) */
606 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
607 DeviceFilterList *backedList = m->llDeviceFilters.backedUpData();
608 while (it != m->llDeviceFilters->end())
609 {
610 if (std::find(backedList->begin(), backedList->end(), *it) ==
611 backedList->end())
612 {
613 /* notify the proxy (only when it makes sense) */
614 if ((*it)->i_getData().mData.fActive &&
615 Global::IsOnline(adep.machineState())
616 && (*it)->i_getData().mRemote.isMatch(false))
617 {
618 USBDeviceFilter *pFilter = *it;
619 Assert(pFilter->i_getId() != NULL);
620 pProxySvc->removeFilter(pFilter->i_getId());
621 pFilter->i_getId() = NULL;
622 }
623
624 (*it)->uninit();
625 }
626 ++it;
627 }
628
629 if (Global::IsOnline(adep.machineState()))
630 {
631 /* find all removed old filters (absent in the new list)
632 * and insert them back to the USB proxy */
633 it = backedList->begin();
634 while (it != backedList->end())
635 {
636 if (std::find(m->llDeviceFilters->begin(), m->llDeviceFilters->end(), *it) ==
637 m->llDeviceFilters->end())
638 {
639 /* notify the proxy (only when necessary) */
640 if ((*it)->i_getData().mData.fActive
641 && (*it)->i_getData().mRemote.isMatch(false))
642 {
643 USBDeviceFilter *pFilter = *it; /* resolve ambiguity */
644 Assert(pFilter->i_getId() == NULL);
645 pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter);
646 }
647 }
648 ++it;
649 }
650 }
651
652 /* restore the list */
653 m->llDeviceFilters.rollback();
654 }
655
656 /* here we don't depend on the machine state any more */
657 adep.release();
658
659 /* rollback any changes to filters after restoring the list */
660 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
661 while (it != m->llDeviceFilters->end())
662 {
663 if ((*it)->i_isModified())
664 {
665 (*it)->i_rollback();
666 /* call this to notify the USB proxy about changes */
667 i_onDeviceFilterChange(*it);
668 }
669 ++it;
670 }
671
672#endif /* VBOX_WITH_USB */
673}
674
675/**
676 * @note Locks this object for writing, together with the peer object (also
677 * for writing) if there is one.
678 */
679void USBDeviceFilters::i_commit()
680{
681 /* sanity */
682 AutoCaller autoCaller(this);
683 AssertComRCReturnVoid(autoCaller.hrc());
684
685 /* sanity too */
686 AutoCaller peerCaller(m->pPeer);
687 AssertComRCReturnVoid(peerCaller.hrc());
688
689 /* lock both for writing since we modify both (mPeer is "master" so locked
690 * first) */
691 AutoMultiWriteLock2 alock(m->pPeer, this COMMA_LOCKVAL_SRC_POS);
692
693#ifdef VBOX_WITH_USB
694 bool commitFilters = false;
695
696 if (m->llDeviceFilters.isBackedUp())
697 {
698 m->llDeviceFilters.commit();
699
700 /* apply changes to peer */
701 if (m->pPeer)
702 {
703 AutoWriteLock peerlock(m->pPeer COMMA_LOCKVAL_SRC_POS);
704
705 /* commit all changes to new filters (this will reshare data with
706 * peers for those who have peers) */
707 DeviceFilterList *newList = new DeviceFilterList();
708 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
709 while (it != m->llDeviceFilters->end())
710 {
711 (*it)->i_commit();
712
713 /* look if this filter has a peer filter */
714 ComObjPtr<USBDeviceFilter> peer = (*it)->i_peer();
715 if (!peer)
716 {
717 /* no peer means the filter is a newly created one;
718 * create a peer owning data this filter share it with */
719 peer.createObject();
720 peer->init(m->pPeer, *it, true /* aReshare */);
721 }
722 else
723 {
724 /* remove peer from the old list */
725 m->pPeer->m->llDeviceFilters->remove(peer);
726 }
727 /* and add it to the new list */
728 newList->push_back(peer);
729
730 ++it;
731 }
732
733 /* uninit old peer's filters that are left */
734 it = m->pPeer->m->llDeviceFilters->begin();
735 while (it != m->pPeer->m->llDeviceFilters->end())
736 {
737 (*it)->uninit();
738 ++it;
739 }
740
741 /* attach new list of filters to our peer */
742 m->pPeer->m->llDeviceFilters.attach(newList);
743 }
744 else
745 {
746 /* we have no peer (our parent is the newly created machine);
747 * just commit changes to filters */
748 commitFilters = true;
749 }
750 }
751 else
752 {
753 /* the list of filters itself is not changed,
754 * just commit changes to filters themselves */
755 commitFilters = true;
756 }
757
758 if (commitFilters)
759 {
760 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
761 while (it != m->llDeviceFilters->end())
762 {
763 (*it)->i_commit();
764 ++it;
765 }
766 }
767#endif /* VBOX_WITH_USB */
768}
769
770/**
771 * @note Locks this object for writing, together with the peer object
772 * represented by @a aThat (locked for reading).
773 */
774void USBDeviceFilters::i_copyFrom(USBDeviceFilters *aThat)
775{
776 AssertReturnVoid(aThat != NULL);
777
778 /* sanity */
779 AutoCaller autoCaller(this);
780 AssertComRCReturnVoid(autoCaller.hrc());
781
782 /* sanity too */
783 AutoCaller thatCaller(aThat);
784 AssertComRCReturnVoid(thatCaller.hrc());
785
786 /* even more sanity */
787 AutoAnyStateDependency adep(m->pParent);
788 AssertComRCReturnVoid(adep.hrc());
789 /* Machine::copyFrom() may not be called when the VM is running */
790 AssertReturnVoid(!Global::IsOnline(adep.machineState()));
791
792 /* peer is not modified, lock it for reading (aThat is "master" so locked
793 * first) */
794 AutoReadLock rl(aThat COMMA_LOCKVAL_SRC_POS);
795 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
796
797#ifdef VBOX_WITH_USB
798
799 /* Note that we won't inform the USB proxy about new filters since the VM is
800 * not running when we are here and therefore no need to do so */
801
802 /* create private copies of all filters */
803 m->llDeviceFilters.backup();
804 m->llDeviceFilters->clear();
805 for (DeviceFilterList::const_iterator it = aThat->m->llDeviceFilters->begin();
806 it != aThat->m->llDeviceFilters->end();
807 ++it)
808 {
809 ComObjPtr<USBDeviceFilter> pFilter;
810 pFilter.createObject();
811 pFilter->initCopy(this, *it);
812 m->llDeviceFilters->push_back(pFilter);
813 }
814
815#endif /* VBOX_WITH_USB */
816}
817
818#ifdef VBOX_WITH_USB
819
820/**
821 * Called by setter methods of all USB device filters.
822 *
823 * @note Locks nothing.
824 */
825HRESULT USBDeviceFilters::i_onDeviceFilterChange(USBDeviceFilter *aFilter,
826 BOOL aActiveChanged /* = FALSE */)
827{
828 AutoCaller autoCaller(this);
829 AssertComRCReturnRC(autoCaller.hrc());
830
831 /* we need the machine state */
832 AutoAnyStateDependency adep(m->pParent);
833 AssertComRCReturnRC(adep.hrc());
834
835 /* nothing to do if the machine isn't running */
836 if (!Global::IsOnline(adep.machineState()))
837 return S_OK;
838
839 /* we don't modify our data fields -- no need to lock */
840
841 if ( aFilter->mInList
842 && m->pParent->i_isRegistered())
843 {
844 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
845 ComAssertRet(pProxySvc, E_FAIL);
846
847 if (aActiveChanged)
848 {
849 if (aFilter->i_getData().mRemote.isMatch(false))
850 {
851 /* insert/remove the filter from the proxy */
852 if (aFilter->i_getData().mData.fActive)
853 {
854 ComAssertRet(aFilter->i_getId() == NULL, E_FAIL);
855 aFilter->i_getId() = pProxySvc->insertFilter(&aFilter->i_getData().mUSBFilter);
856 }
857 else
858 {
859 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
860 pProxySvc->removeFilter(aFilter->i_getId());
861 aFilter->i_getId() = NULL;
862 }
863 }
864 }
865 else
866 {
867 if (aFilter->i_getData().mData.fActive)
868 {
869 /* update the filter in the proxy */
870 ComAssertRet(aFilter->i_getId() != NULL, E_FAIL);
871 pProxySvc->removeFilter(aFilter->i_getId());
872 if (aFilter->i_getData().mRemote.isMatch(false))
873 {
874 aFilter->i_getId() = pProxySvc->insertFilter(&aFilter->i_getData().mUSBFilter);
875 }
876 }
877 }
878 }
879
880 return S_OK;
881}
882
883/**
884 * Returns true if the given USB device matches to at least one of
885 * this controller's USB device filters.
886 *
887 * A HostUSBDevice specific version.
888 *
889 * @note Locks this object for reading.
890 */
891bool USBDeviceFilters::i_hasMatchingFilter(const ComObjPtr<HostUSBDevice> &aDevice, ULONG *aMaskedIfs)
892{
893 AutoCaller autoCaller(this);
894 AssertComRCReturn(autoCaller.hrc(), false);
895
896 /* It is not possible to work with USB device if there is no USB controller present. */
897 if (!m->pParent->i_isUSBControllerPresent())
898 return false;
899
900 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
901
902 /* apply self filters */
903 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
904 it != m->llDeviceFilters->end();
905 ++it)
906 {
907 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
908 if (aDevice->i_isMatch((*it)->i_getData()))
909 {
910 *aMaskedIfs = (*it)->i_getData().mData.ulMaskedInterfaces;
911 return true;
912 }
913 }
914
915 return false;
916}
917
918/**
919 * Returns true if the given USB device matches to at least one of
920 * this controller's USB device filters.
921 *
922 * A generic version that accepts any IUSBDevice on input.
923 *
924 * @note
925 * This method MUST correlate with HostUSBDevice::isMatch()
926 * in the sense of the device matching logic.
927 *
928 * @note Locks this object for reading.
929 */
930bool USBDeviceFilters::i_hasMatchingFilter(IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
931{
932 LogFlowThisFuncEnter();
933
934 AutoCaller autoCaller(this);
935 AssertComRCReturn(autoCaller.hrc(), false);
936
937 /* It is not possible to work with USB device if there is no USB controller present. */
938 if (!m->pParent->i_isUSBControllerPresent())
939 return false;
940
941 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
942
943 /* query fields */
944 USBFILTER dev;
945 USBFilterInit(&dev, USBFILTERTYPE_CAPTURE);
946
947 USHORT vendorId = 0;
948 HRESULT hrc = aUSBDevice->COMGETTER(VendorId)(&vendorId);
949 ComAssertComRCRet(hrc, false);
950 ComAssertRet(vendorId, false);
951 int vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);
952
953 USHORT productId = 0;
954 hrc = aUSBDevice->COMGETTER(ProductId)(&productId);
955 ComAssertComRCRet(hrc, false);
956 vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);
957
958 USHORT revision;
959 hrc = aUSBDevice->COMGETTER(Revision)(&revision);
960 ComAssertComRCRet(hrc, false);
961 vrc = USBFilterSetNumExact(&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);
962
963 Bstr manufacturer;
964 hrc = aUSBDevice->COMGETTER(Manufacturer)(manufacturer.asOutParam());
965 ComAssertComRCRet(hrc, false);
966 if (!manufacturer.isEmpty())
967 USBFilterSetStringExact(&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(),
968 true /*fMustBePresent*/, false /*fPurge*/);
969
970 Bstr product;
971 hrc = aUSBDevice->COMGETTER(Product)(product.asOutParam());
972 ComAssertComRCRet(hrc, false);
973 if (!product.isEmpty())
974 USBFilterSetStringExact(&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(),
975 true /*fMustBePresent*/, false /*fPurge*/);
976
977 Bstr serialNumber;
978 hrc = aUSBDevice->COMGETTER(SerialNumber)(serialNumber.asOutParam());
979 ComAssertComRCRet(hrc, false);
980 if (!serialNumber.isEmpty())
981 USBFilterSetStringExact(&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(),
982 true /*fMustBePresent*/, false /*fPurge*/);
983
984 Bstr address;
985 hrc = aUSBDevice->COMGETTER(Address)(address.asOutParam());
986 ComAssertComRCRet(hrc, false);
987
988 USHORT port = 0;
989 hrc = aUSBDevice->COMGETTER(Port)(&port);
990 ComAssertComRCRet(hrc, false);
991 USBFilterSetNumExact(&dev, USBFILTERIDX_PORT, port, true);
992
993 BOOL remote = FALSE;
994 hrc = aUSBDevice->COMGETTER(Remote)(&remote);
995 ComAssertComRCRet(hrc, false);
996 ComAssertRet(remote == TRUE, false);
997
998 bool match = false;
999
1000 /* apply self filters */
1001 for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
1002 it != m->llDeviceFilters->end();
1003 ++it)
1004 {
1005 AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
1006 const USBDeviceFilter::BackupableUSBDeviceFilterData &aData = (*it)->i_getData();
1007
1008 if (!aData.mData.fActive)
1009 continue;
1010 if (!aData.mRemote.isMatch(remote))
1011 continue;
1012 if (!USBFilterMatch(&aData.mUSBFilter, &dev))
1013 continue;
1014
1015 match = true;
1016 *aMaskedIfs = aData.mData.ulMaskedInterfaces;
1017 break;
1018 }
1019
1020 LogFlowThisFunc(("returns: %d\n", match));
1021 LogFlowThisFuncLeave();
1022
1023 return match;
1024}
1025
1026/**
1027 * Notifies the proxy pProxySvc about all filters as requested by the
1028 * @a aInsertFilters argument.
1029 *
1030 * @param aInsertFilters @c true to insert filters, @c false to remove.
1031 *
1032 * @note Locks this object for reading.
1033 */
1034HRESULT USBDeviceFilters::i_notifyProxy(bool aInsertFilters)
1035{
1036 LogFlowThisFunc(("aInsertFilters=%RTbool\n", aInsertFilters));
1037
1038 AutoCaller autoCaller(this);
1039 AssertComRCReturn(autoCaller.hrc(), false);
1040
1041 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1042
1043 USBProxyService *pProxySvc = m->pHost->i_usbProxyService();
1044 AssertReturn(pProxySvc, E_FAIL);
1045
1046 DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
1047 while (it != m->llDeviceFilters->end())
1048 {
1049 USBDeviceFilter *pFilter = *it; /* resolve ambiguity (for ComPtr below) */
1050
1051 /* notify the proxy (only if the filter is active) */
1052 if ( pFilter->i_getData().mData.fActive
1053 && pFilter->i_getData().mRemote.isMatch(false) /* and if the filter is NOT remote */
1054 )
1055 {
1056 if (aInsertFilters)
1057 {
1058 AssertReturn(pFilter->i_getId() == NULL, E_FAIL);
1059 pFilter->i_getId() = pProxySvc->insertFilter(&pFilter->i_getData().mUSBFilter);
1060 }
1061 else
1062 {
1063 /* It's possible that the given filter was not inserted the proxy
1064 * when this method gets called (as a result of an early VM
1065 * process crash for example. So, don't assert that ID != NULL. */
1066 if (pFilter->i_getId() != NULL)
1067 {
1068 pProxySvc->removeFilter(pFilter->i_getId());
1069 pFilter->i_getId() = NULL;
1070 }
1071 }
1072 }
1073 ++it;
1074 }
1075
1076 return S_OK;
1077}
1078
1079Machine* USBDeviceFilters::i_getMachine()
1080{
1081 return m->pParent;
1082}
1083
1084#endif /* VBOX_WITH_USB */
1085
1086// private methods
1087/////////////////////////////////////////////////////////////////////////////
1088/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette