VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBDeviceFilterImpl.cpp@ 103131

Last change on this file since 103131 was 100772, checked in by vboxsync, 15 months ago

include/VBox/usbfilter.h,HostDrivers/VBoxUSB/USBFilter: IUSBDeviceFilter:
USB device interval filters don't work. bugref:10452

Main/Host,Main/USBDeviceFilter: Adding or removing global USB device
filters causes memory corruption wihch can lead to a deadlock or a SEGV
as the list of global USB device filters (llChildren) changes while
the list is being walked.

Frontends/VBoxManage: 'VBoxManage list usbfilters' doesn't display the
'Port' value of the device filter.

Frontends/VBoxManage: 'VBoxManage add usbfilter' and 'VBoxManage modify
usbfilter' both ignore the --product="Value" option.

Main/VirtualBox.xidl: Improve the IUSBDeviceFilter wording to make
things clearer in the 'VirtualBox Programming Guide and Reference Guide'
aka SDKRef.pdf.

HostDrivers/VBoxUSB/testcase/tstUSBFilter: Include a variety of USB
device filter entries which include the 'int:' prefix to fully exercise
the interval filter parsing code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.6 KB
Line 
1/* $Id: USBDeviceFilterImpl.cpp 100772 2023-08-01 17:34:48Z vboxsync $ */
2/** @file
3 * Implementation of VirtualBox COM components: USBDeviceFilter and HostUSBDeviceFilter
4 */
5
6/*
7 * Copyright (C) 2006-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_USBDEVICEFILTER
29#include "USBDeviceFilterImpl.h"
30#include "USBDeviceFiltersImpl.h"
31#include "MachineImpl.h"
32#include "HostImpl.h"
33
34#include <iprt/cpp/utils.h>
35#include <VBox/settings.h>
36
37#include "AutoStateDep.h"
38#include "AutoCaller.h"
39#include "LoggingNew.h"
40
41////////////////////////////////////////////////////////////////////////////////
42// Internal Helpers
43////////////////////////////////////////////////////////////////////////////////
44
45/**
46 * Converts a USBFilter field into a string.
47 *
48 * (This function is also used by HostUSBDeviceFilter.)
49 *
50 * @param aFilter The filter.
51 * @param aIdx The field index.
52 * @param rstrOut The output string.
53 */
54static void i_usbFilterFieldToString(PCUSBFILTER aFilter, USBFILTERIDX aIdx, Utf8Str &rstrOut)
55{
56 const USBFILTERMATCH matchingMethod = USBFilterGetMatchingMethod(aFilter, aIdx);
57 Assert(matchingMethod != USBFILTERMATCH_INVALID);
58
59 if (USBFilterIsMethodNumeric(matchingMethod))
60 {
61 int value = USBFilterGetNum(aFilter, aIdx);
62 Assert(value >= 0 && value <= 0xffff);
63
64 rstrOut.printf("%04RX16", (uint16_t)value);
65 }
66 else if (USBFilterIsMethodString(matchingMethod))
67 rstrOut = USBFilterGetString(aFilter, aIdx);
68 else
69 rstrOut.setNull();
70}
71
72/*static*/
73const char* USBDeviceFilter::i_describeUSBFilterIdx(USBFILTERIDX aIdx)
74{
75 switch (aIdx)
76 {
77 case USBFILTERIDX_VENDOR_ID: return tr("Vendor ID");
78 case USBFILTERIDX_PRODUCT_ID: return tr("Product ID");
79 case USBFILTERIDX_DEVICE: return tr("Revision");
80 case USBFILTERIDX_MANUFACTURER_STR: return tr("Manufacturer");
81 case USBFILTERIDX_PRODUCT_STR: return tr("Product");
82 case USBFILTERIDX_SERIAL_NUMBER_STR: return tr("Serial number");
83 case USBFILTERIDX_PORT: return tr("Port number");
84 default: return "";
85 }
86 /* not reached. */
87}
88
89/**
90 * Interprets a string and assigns it to a USBFilter field.
91 *
92 * (This function is also used by HostUSBDeviceFilter.)
93 *
94 * @param aFilter The filter.
95 * @param aIdx The field index.
96 * @param aValue The input string.
97 * @param aErrStr Where to return the error string on failure.
98 *
99 * @return COM status code.
100 * @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/
101 */
102/*static*/ HRESULT USBDeviceFilter::i_usbFilterFieldFromString(PUSBFILTER aFilter,
103 USBFILTERIDX aIdx,
104 const Utf8Str &aValue,
105 Utf8Str &aErrStr)
106{
107 int vrc;
108 if (aValue.isEmpty())
109 vrc = USBFilterSetIgnore(aFilter, aIdx);
110 else
111 {
112 const char *pcszValue = aValue.c_str();
113 if (USBFilterIsNumericField(aIdx))
114 {
115 /* Is it a lonely number? */
116 char *pszNext;
117 uint64_t u64;
118 vrc = RTStrToUInt64Ex(pcszValue, &pszNext, 16, &u64);
119 if (RT_SUCCESS(vrc))
120 pszNext = RTStrStripL(pszNext);
121 if ( vrc == VINF_SUCCESS
122 && !*pszNext)
123 {
124 if (u64 > 0xffff)
125 {
126 // there was a bug writing out "-1" values in earlier versions, which got
127 // written as "FFFFFFFF"; make sure we don't fail on those
128 if (u64 == 0xffffffff)
129 u64 = 0xffff;
130 else
131 {
132 aErrStr.printf(tr("The %s value '%s' is too big (max 0xFFFF)"), i_describeUSBFilterIdx(aIdx), pcszValue);
133 return E_INVALIDARG;
134 }
135 }
136
137 vrc = USBFilterSetNumExact(aFilter, aIdx, (uint16_t)u64, true /* fMustBePresent */);
138 }
139 else
140 vrc = USBFilterSetNumExpression(aFilter, aIdx, pcszValue, true /* fMustBePresent */);
141 }
142 else
143 {
144 /* Any wildcard in the string? */
145 Assert(USBFilterIsStringField(aIdx));
146 if ( strchr(pcszValue, '*')
147 || strchr(pcszValue, '?')
148 /* || strchr (psz, '[') - later */
149 )
150 vrc = USBFilterSetStringPattern(aFilter, aIdx, pcszValue, true /*fMustBePresent*/);
151 else
152 vrc = USBFilterSetStringExact(aFilter, aIdx, pcszValue, true /*fMustBePresent*/, false /*fPurge*/);
153 }
154 }
155
156 if (RT_FAILURE(vrc))
157 {
158 if (vrc == VERR_INVALID_PARAMETER)
159 {
160 aErrStr.printf(tr("The %s filter expression '%s' is not valid"), i_describeUSBFilterIdx(aIdx), aValue.c_str());
161 return E_INVALIDARG;
162 }
163 if (vrc == VERR_BUFFER_OVERFLOW)
164 {
165 aErrStr.printf(tr("Insufficient expression space for the '%s' filter expression '%s'"),
166 i_describeUSBFilterIdx(aIdx), aValue.c_str());
167 return E_FAIL;
168 }
169 AssertRC(vrc);
170 aErrStr.printf(tr("Encountered unexpected status %Rrc when setting '%s' to '%s'"),
171 vrc, i_describeUSBFilterIdx(aIdx), aValue.c_str());
172 return E_FAIL;
173 }
174
175 return S_OK;
176}
177
178
179////////////////////////////////////////////////////////////////////////////////
180// USBDeviceFilter
181////////////////////////////////////////////////////////////////////////////////
182
183// constructor / destructor
184////////////////////////////////////////////////////////////////////////////////
185
186USBDeviceFilter::USBDeviceFilter()
187 : mParent(NULL),
188 mPeer(NULL)
189{
190}
191
192USBDeviceFilter::~USBDeviceFilter()
193{
194}
195
196HRESULT USBDeviceFilter::FinalConstruct()
197{
198 return BaseFinalConstruct();
199}
200
201void USBDeviceFilter::FinalRelease()
202{
203 uninit();
204 BaseFinalRelease();
205}
206
207// public initializer/uninitializer for internal purposes only
208////////////////////////////////////////////////////////////////////////////////
209
210/**
211 * Initializes the USB device filter object.
212 *
213 * @param aParent Handle of the parent object.
214 * @param data Reference filter settings.
215 */
216HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent,
217 const settings::USBDeviceFilter &data)
218{
219 LogFlowThisFunc(("aParent=%p\n", aParent));
220
221 ComAssertRet(aParent && !data.strName.isEmpty(), E_INVALIDARG);
222
223 /* Enclose the state transition NotReady->InInit->Ready */
224 AutoInitSpan autoInitSpan(this);
225 AssertReturn(autoInitSpan.isOk(), E_FAIL);
226
227 unconst(mParent) = aParent;
228 /* mPeer is left null */
229
230 m_fModified = false;
231
232 bd.allocate();
233 bd->mData.strName = data.strName;
234 bd->mData.fActive = data.fActive;
235 bd->mData.ulMaskedInterfaces = 0;
236
237 /* initialize all filters to any match using null string */
238 USBFilterInit(&bd->mUSBFilter, USBFILTERTYPE_CAPTURE);
239 bd->mRemote = NULL;
240
241 mInList = false;
242
243 /* use setters for the attributes below to reuse parsing errors
244 * handling */
245
246 HRESULT hrc = i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
247 if (FAILED(hrc)) return hrc;
248
249 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
250 if (FAILED(hrc)) return hrc;
251
252 hrc = i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
253 if (FAILED(hrc)) return hrc;
254
255 hrc = i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
256 if (FAILED(hrc)) return hrc;
257
258 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, data.strProduct);
259 if (FAILED(hrc)) return hrc;
260
261 hrc = i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
262 if (FAILED(hrc)) return hrc;
263
264 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
265 if (FAILED(hrc)) return hrc;
266
267 hrc = COMSETTER(Remote)(Bstr(data.strRemote).raw());
268 if (FAILED(hrc)) return hrc;
269
270 hrc = COMSETTER(MaskedInterfaces)(data.ulMaskedInterfaces);
271 if (FAILED(hrc)) return hrc;
272
273 /* Confirm successful initialization */
274 autoInitSpan.setSucceeded();
275
276 return S_OK;
277}
278
279/**
280 * Initializes the USB device filter object (short version).
281 *
282 * @param aParent Handle of the parent object.
283 * @param aName Name of the filter.
284 */
285HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, IN_BSTR aName)
286{
287 LogFlowThisFunc(("aParent=%p\n", aParent));
288
289 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
290
291 /* Enclose the state transition NotReady->InInit->Ready */
292 AutoInitSpan autoInitSpan(this);
293 AssertReturn(autoInitSpan.isOk(), E_FAIL);
294
295 unconst(mParent) = aParent;
296 /* mPeer is left null */
297
298 m_fModified = false;
299
300 bd.allocate();
301
302 bd->mData.strName = Utf8Str(aName);
303 bd->mData.fActive = FALSE;
304 bd->mData.ulMaskedInterfaces = 0;
305
306 /* initialize all filters to any match using null string */
307 USBFilterInit(&bd->mUSBFilter, USBFILTERTYPE_CAPTURE);
308 bd->mRemote = NULL;
309
310 mInList = false;
311
312 /* Confirm successful initialization */
313 autoInitSpan.setSucceeded();
314
315 return S_OK;
316}
317
318/**
319 * Initializes the object given another object
320 * (a kind of copy constructor). This object shares data with
321 * the object passed as an argument.
322 *
323 * @param aParent Handle of the parent object.
324 * @param aThat
325 * @param aReshare
326 * When false, the original object will remain a data owner.
327 * Otherwise, data ownership will be transferred from the original
328 * object to this one.
329 *
330 * @note This object must be destroyed before the original object
331 * it shares data with is destroyed.
332 *
333 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
334 * reading if @a aReshare is false.
335 */
336HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, USBDeviceFilter *aThat,
337 bool aReshare /* = false */)
338{
339 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
340 aParent, aThat, aReshare));
341
342 ComAssertRet(aParent && aThat, E_INVALIDARG);
343
344 /* Enclose the state transition NotReady->InInit->Ready */
345 AutoInitSpan autoInitSpan(this);
346 AssertReturn(autoInitSpan.isOk(), E_FAIL);
347
348 unconst(mParent) = aParent;
349
350 m_fModified = false;
351
352 /* sanity */
353 AutoCaller thatCaller(aThat);
354 AssertComRCReturnRC(thatCaller.hrc());
355
356 if (aReshare)
357 {
358 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
359
360 unconst(aThat->mPeer) = this;
361 bd.attach(aThat->bd);
362 }
363 else
364 {
365 unconst(mPeer) = aThat;
366
367 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
368 bd.share(aThat->bd);
369 }
370
371 /* the arbitrary ID field is not reset because
372 * the copy is a shadow of the original */
373
374 mInList = aThat->mInList;
375
376 /* Confirm successful initialization */
377 autoInitSpan.setSucceeded();
378
379 return S_OK;
380}
381
382/**
383 * Initializes the guest object given another guest object
384 * (a kind of copy constructor). This object makes a private copy of data
385 * of the original object passed as an argument.
386 *
387 * @note Locks @a aThat object for reading.
388 */
389HRESULT USBDeviceFilter::initCopy(USBDeviceFilters *aParent, USBDeviceFilter *aThat)
390{
391 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
392
393 ComAssertRet(aParent && aThat, E_INVALIDARG);
394
395 /* Enclose the state transition NotReady->InInit->Ready */
396 AutoInitSpan autoInitSpan(this);
397 AssertReturn(autoInitSpan.isOk(), E_FAIL);
398
399 unconst(mParent) = aParent;
400 /* mPeer is left null */
401
402 m_fModified = false;
403
404 /* sanity */
405 AutoCaller thatCaller(aThat);
406 AssertComRCReturnRC(thatCaller.hrc());
407
408 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
409 bd.attachCopy(aThat->bd);
410
411 /* reset the arbitrary ID field
412 * (this field is something unique that two distinct objects, even if they
413 * are deep copies of each other, should not share) */
414 bd->mId = NULL;
415
416 mInList = aThat->mInList;
417
418 /* Confirm successful initialization */
419 autoInitSpan.setSucceeded();
420
421 return S_OK;
422}
423
424/**
425 * Uninitializes the instance and sets the ready flag to FALSE.
426 * Called either from FinalRelease() or by the parent when it gets destroyed.
427 */
428void USBDeviceFilter::uninit()
429{
430 LogFlowThisFunc(("\n"));
431
432 /* Enclose the state transition Ready->InUninit->NotReady */
433 AutoUninitSpan autoUninitSpan(this);
434 if (autoUninitSpan.uninitDone())
435 return;
436
437 mInList = false;
438
439 bd.free();
440
441 unconst(mPeer) = NULL;
442 unconst(mParent) = NULL;
443}
444
445
446// IUSBDeviceFilter properties
447////////////////////////////////////////////////////////////////////////////////
448
449HRESULT USBDeviceFilter::getName(com::Utf8Str &aName)
450{
451 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
452
453 return aName.assignEx(bd->mData.strName);
454}
455
456HRESULT USBDeviceFilter::setName(const com::Utf8Str &aName)
457{
458 /* the machine needs to be mutable */
459 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
460 if (FAILED(adep.hrc())) return adep.hrc();
461
462 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
463
464 if (bd->mData.strName != aName)
465 {
466 m_fModified = true;
467 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
468
469 bd.backup();
470 bd->mData.strName = aName;
471
472 // leave the lock before informing callbacks
473 alock.release();
474
475 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
476 pMachine->i_setModified(Machine::IsModified_USB);
477 mlock.release();
478
479 return mParent->i_onDeviceFilterChange(this);
480 }
481
482 return S_OK;
483}
484
485HRESULT USBDeviceFilter::getActive(BOOL *aActive)
486{
487 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
488
489 *aActive = bd->mData.fActive;
490
491 return S_OK;
492}
493
494HRESULT USBDeviceFilter::setActive(const BOOL aActive)
495{
496 /* the machine needs to be mutable */
497 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
498 if (FAILED(adep.hrc())) return adep.hrc();
499
500 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
501
502 if (bd->mData.fActive != RT_BOOL(aActive))
503 {
504 m_fModified = true;
505 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
506
507 bd.backup();
508 bd->mData.fActive = RT_BOOL(aActive);
509
510 // leave the lock before informing callbacks
511 alock.release();
512
513 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
514 pMachine->i_setModified(Machine::IsModified_USB);
515 mlock.release();
516
517 return mParent->i_onDeviceFilterChange(this, TRUE /* aActiveChanged */);
518 }
519
520 return S_OK;
521}
522
523HRESULT USBDeviceFilter::getVendorId(com::Utf8Str &aVendorId)
524{
525 return i_usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
526}
527
528HRESULT USBDeviceFilter::setVendorId(const com::Utf8Str &aVendorId)
529{
530 return i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
531}
532
533HRESULT USBDeviceFilter::getProductId(com::Utf8Str &aProductId)
534{
535 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
536}
537
538HRESULT USBDeviceFilter::setProductId(const com::Utf8Str &aProductId)
539{
540 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
541}
542
543HRESULT USBDeviceFilter::getRevision(com::Utf8Str &aRevision)
544{
545 return i_usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
546}
547
548HRESULT USBDeviceFilter::setRevision(const com::Utf8Str &aRevision)
549{
550 return i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
551}
552
553HRESULT USBDeviceFilter::getManufacturer(com::Utf8Str &aManufacturer)
554{
555 return i_usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
556}
557
558HRESULT USBDeviceFilter::setManufacturer(const com::Utf8Str &aManufacturer)
559{
560 return i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
561}
562
563HRESULT USBDeviceFilter::getProduct(com::Utf8Str &aProduct)
564{
565 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
566}
567
568HRESULT USBDeviceFilter::setProduct(const com::Utf8Str &aProduct)
569{
570 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
571}
572
573HRESULT USBDeviceFilter::getSerialNumber(com::Utf8Str &aSerialNumber)
574{
575 return i_usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
576}
577
578HRESULT USBDeviceFilter::setSerialNumber(const com::Utf8Str &aSerialNumber)
579{
580 return i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
581}
582
583HRESULT USBDeviceFilter::getPort(com::Utf8Str &aPort)
584{
585 return i_usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
586}
587
588HRESULT USBDeviceFilter::setPort(const com::Utf8Str &aPort)
589{
590 return i_usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
591}
592
593
594HRESULT USBDeviceFilter::getRemote(com::Utf8Str &aRemote)
595{
596 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
597
598 aRemote = bd->mRemote.string();
599
600 return S_OK;
601}
602
603HRESULT USBDeviceFilter::setRemote(const com::Utf8Str &aRemote)
604{
605 /* the machine needs to be mutable */
606 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
607 if (FAILED(adep.hrc())) return adep.hrc();
608 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
609 Bstr bRemote = Bstr(aRemote).raw();
610
611 if (bd->mRemote.string() != bRemote)
612 {
613 BackupableUSBDeviceFilterData::BOOLFilter flt = bRemote;
614 ComAssertRet(!flt.isNull(), E_FAIL);
615 if (!flt.isValid())
616 return setError(E_INVALIDARG,
617 tr("Remote state filter string '%s' is not valid (error at position %d)"),
618 aRemote.c_str(), flt.errorPosition() + 1);
619
620 m_fModified = true;
621 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
622
623 bd.backup();
624 bd->mRemote = flt;
625
626 // leave the lock before informing callbacks
627 alock.release();
628
629 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
630 pMachine->i_setModified(Machine::IsModified_USB);
631 mlock.release();
632
633 return mParent->i_onDeviceFilterChange(this);
634 }
635 return S_OK;
636}
637
638
639HRESULT USBDeviceFilter::getMaskedInterfaces(ULONG *aMaskedIfs)
640{
641 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
642
643 *aMaskedIfs = bd->mData.ulMaskedInterfaces;
644
645 return S_OK;
646}
647
648HRESULT USBDeviceFilter::setMaskedInterfaces(ULONG aMaskedIfs)
649{
650 /* the machine needs to be mutable */
651 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
652 if (FAILED(adep.hrc())) return adep.hrc();
653
654 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
655
656 if (bd->mData.ulMaskedInterfaces != aMaskedIfs)
657 {
658 m_fModified = true;
659 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
660
661 bd.backup();
662 bd->mData.ulMaskedInterfaces = aMaskedIfs;
663 // leave the lock before informing callbacks
664 alock.release();
665
666 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
667 pMachine->i_setModified(Machine::IsModified_USB);
668 mlock.release();
669
670 return mParent->i_onDeviceFilterChange(this);
671 }
672
673 return S_OK;
674}
675
676// public methods only for internal purposes
677////////////////////////////////////////////////////////////////////////////////
678
679bool USBDeviceFilter::i_isModified()
680{
681 AutoCaller autoCaller(this);
682 AssertComRCReturn(autoCaller.hrc(), false);
683
684 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
685 return m_fModified;
686}
687
688/**
689 * @note Locks this object for writing.
690 */
691void USBDeviceFilter::i_rollback()
692{
693 /* sanity */
694 AutoCaller autoCaller(this);
695 AssertComRCReturnVoid(autoCaller.hrc());
696
697 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
698
699 bd.rollback();
700}
701
702/**
703 * @note Locks this object for writing, together with the peer object (also
704 * for writing) if there is one.
705 */
706void USBDeviceFilter::i_commit()
707{
708 /* sanity */
709 AutoCaller autoCaller(this);
710 AssertComRCReturnVoid(autoCaller.hrc());
711
712 /* sanity too */
713 AutoCaller peerCaller(mPeer);
714 AssertComRCReturnVoid(peerCaller.hrc());
715
716 /* lock both for writing since we modify both (mPeer is "master" so locked
717 * first) */
718 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
719
720 if (bd.isBackedUp())
721 {
722 bd.commit();
723 if (mPeer)
724 {
725 /* attach new data to the peer and reshare it */
726 mPeer->bd.attach(bd);
727 }
728 }
729}
730
731/**
732 * Cancels sharing (if any) by making an independent copy of data.
733 * This operation also resets this object's peer to NULL.
734 *
735 * @note Locks this object for writing, together with the peer object
736 * represented by @a aThat (locked for reading).
737 */
738void USBDeviceFilter::unshare()
739{
740 /* sanity */
741 AutoCaller autoCaller(this);
742 AssertComRCReturnVoid(autoCaller.hrc());
743
744 /* sanity too */
745 AutoCaller peerCaller(mPeer);
746 AssertComRCReturnVoid(peerCaller.hrc());
747
748 /* peer is not modified, lock it for reading (mPeer is "master" so locked
749 * first) */
750 AutoReadLock rl(mPeer COMMA_LOCKVAL_SRC_POS);
751 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
752
753 if (bd.isShared())
754 {
755 if (!bd.isBackedUp())
756 bd.backup();
757
758 bd.commit();
759 }
760
761 unconst(mPeer) = NULL;
762}
763
764/**
765 * Generic USB filter field getter; converts the field value to UTF-16.
766 *
767 * @param aIdx The field index.
768 * @param aStr Where to store the value.
769 *
770 * @return COM status.
771 */
772HRESULT USBDeviceFilter::i_usbFilterFieldGetter(USBFILTERIDX aIdx, com::Utf8Str &aStr)
773{
774 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
775
776 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, aStr);
777 return S_OK;
778}
779
780/**
781 * Generic USB filter field setter, expects UTF-8 input.
782 *
783 * @param aIdx The field index.
784 * @param strNew The new value.
785 *
786 * @return COM status.
787 */
788HRESULT USBDeviceFilter::i_usbFilterFieldSetter(USBFILTERIDX aIdx,
789 const com::Utf8Str &strNew)
790{
791 /* the machine needs to be mutable */
792 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
793 if (FAILED(adep.hrc())) return adep.hrc();
794
795 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
796
797
798 com::Utf8Str strOld;
799 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, strOld);
800 if (strOld != strNew)
801 {
802 m_fModified = true;
803 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
804
805 bd.backup();
806
807 com::Utf8Str errStr;
808 HRESULT hrc = i_usbFilterFieldFromString(&bd->mUSBFilter, aIdx, strNew, errStr);
809 if (FAILED(hrc))
810 {
811 bd.rollback();
812 return setError(hrc, "%s", errStr.c_str());
813 }
814
815 // leave the lock before informing callbacks
816 alock.release();
817
818 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
819 pMachine->i_setModified(Machine::IsModified_USB);
820 mlock.release();
821
822 return mParent->i_onDeviceFilterChange(this);
823 }
824
825 return S_OK;
826}
827
828
829////////////////////////////////////////////////////////////////////////////////
830// HostUSBDeviceFilter
831////////////////////////////////////////////////////////////////////////////////
832
833// constructor / destructor
834////////////////////////////////////////////////////////////////////////////////
835
836HostUSBDeviceFilter::HostUSBDeviceFilter()
837 : mParent(NULL)
838{
839}
840
841HostUSBDeviceFilter::~HostUSBDeviceFilter()
842{
843}
844
845
846HRESULT HostUSBDeviceFilter::FinalConstruct()
847{
848 return S_OK;
849}
850
851void HostUSBDeviceFilter::FinalRelease()
852{
853 uninit();
854}
855
856// public initializer/uninitializer for internal purposes only
857////////////////////////////////////////////////////////////////////////////////
858
859/**
860 * Initializes the USB device filter object.
861 *
862 * @param aParent Handle of the parent object.
863 * @param data Settings data.
864 */
865HRESULT HostUSBDeviceFilter::init(Host *aParent,
866 const settings::USBDeviceFilter &data)
867{
868 LogFlowThisFunc(("aParent=%p\n", aParent));
869
870 ComAssertRet(aParent && !data.strName.isEmpty(), E_INVALIDARG);
871
872 /* Enclose the state transition NotReady->InInit->Ready */
873 AutoInitSpan autoInitSpan(this);
874 AssertReturn(autoInitSpan.isOk(), E_FAIL);
875
876 unconst(mParent) = aParent;
877
878 /* register with parent early, since uninit() will unconditionally
879 * unregister on failure */
880 mParent->i_addChild(this);
881
882 bd.allocate();
883 bd->mData.strName = data.strName;
884 bd->mData.fActive = data.fActive;
885 USBFilterInit (&bd->mUSBFilter, USBFILTERTYPE_IGNORE);
886 bd->mRemote = NULL;
887 bd->mData.ulMaskedInterfaces = 0;
888
889 mInList = false;
890
891 /* use setters for the attributes below to reuse parsing errors
892 * handling */
893
894 HRESULT hrc = setAction(data.action);
895 if (FAILED(hrc)) return hrc;
896
897 hrc = i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
898 if (FAILED(hrc)) return hrc;
899
900 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
901 if (FAILED(hrc)) return hrc;
902
903 hrc = i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
904 if (FAILED(hrc)) return hrc;
905
906 hrc = i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
907 if (FAILED(hrc)) return hrc;
908
909 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProduct);
910 if (FAILED(hrc)) return hrc;
911
912 hrc = i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
913 if (FAILED(hrc)) return hrc;
914
915 hrc = i_usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
916 if (FAILED(hrc)) return hrc;
917
918 /* Confirm successful initialization */
919 autoInitSpan.setSucceeded();
920
921 return S_OK;
922}
923
924/**
925 * Initializes the USB device filter object (short version).
926 *
927 * @param aParent Handle of the parent object.
928 * @param aName Filter name.
929 */
930HRESULT HostUSBDeviceFilter::init(Host *aParent, IN_BSTR aName)
931{
932 LogFlowThisFunc(("aParent=%p\n", aParent));
933
934 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
935
936 /* Enclose the state transition NotReady->InInit->Ready */
937 AutoInitSpan autoInitSpan(this);
938 AssertReturn(autoInitSpan.isOk(), E_FAIL);
939
940 unconst(mParent) = aParent;
941
942 /* register with parent early, since uninit() will unconditionally
943 * unregister on failure */
944 mParent->i_addChild(this);
945
946 bd.allocate();
947
948 bd->mData.strName = Utf8Str(aName);
949 bd->mData.fActive = FALSE;
950 mInList = false;
951 USBFilterInit(&bd->mUSBFilter, USBFILTERTYPE_IGNORE);
952 bd->mRemote = NULL;
953 bd->mData.ulMaskedInterfaces = 0;
954
955 /* Confirm successful initialization */
956 autoInitSpan.setSucceeded();
957
958 return S_OK;
959}
960
961/**
962 * Uninitializes the instance and sets the ready flag to FALSE.
963 * Called either from FinalRelease() or by the parent when it gets destroyed.
964 */
965void HostUSBDeviceFilter::uninit()
966{
967 LogFlowThisFunc(("\n"));
968
969 /* Enclose the state transition Ready->InUninit->NotReady */
970 AutoUninitSpan autoUninitSpan(this);
971 if (autoUninitSpan.uninitDone())
972 return;
973
974 mInList = false;
975
976 bd.free();
977
978 unconst(mParent) = NULL;
979}
980
981/**
982 * Most of the USB bits are protect by one lock to simplify things.
983 * This lock is currently the one of the Host object, which happens
984 * to be our parent.
985 */
986RWLockHandle *HostUSBDeviceFilter::lockHandle() const
987{
988 return mParent->lockHandle();
989}
990
991
992// IUSBDeviceFilter properties
993////////////////////////////////////////////////////////////////////////////////
994HRESULT HostUSBDeviceFilter::getName(com::Utf8Str &aName)
995{
996 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
997
998 aName = bd->mData.strName;
999
1000 return S_OK;
1001}
1002
1003
1004HRESULT HostUSBDeviceFilter::setName(const com::Utf8Str &aName)
1005{
1006 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1007
1008 if (bd->mData.strName != aName)
1009 {
1010 bd->mData.strName = aName;
1011
1012 /* leave the lock before informing callbacks */
1013 alock.release();
1014
1015 return mParent->i_onUSBDeviceFilterChange(this);
1016 }
1017
1018 return S_OK;
1019}
1020
1021
1022HRESULT HostUSBDeviceFilter::getActive(BOOL *aActive)
1023{
1024 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1025
1026 *aActive = bd->mData.fActive;
1027
1028 return S_OK;
1029}
1030
1031
1032HRESULT HostUSBDeviceFilter::setActive(BOOL aActive)
1033{
1034 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1035
1036 if (bd->mData.fActive != RT_BOOL(aActive))
1037 {
1038 bd->mData.fActive = RT_BOOL(aActive);
1039
1040 /* leave the lock before informing callbacks */
1041 alock.release();
1042
1043 return mParent->i_onUSBDeviceFilterChange(this, TRUE /* aActiveChanged */);
1044 }
1045
1046 return S_OK;
1047}
1048
1049HRESULT HostUSBDeviceFilter::getVendorId(com::Utf8Str &aVendorId)
1050{
1051 return i_usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1052}
1053
1054HRESULT HostUSBDeviceFilter::setVendorId(const com::Utf8Str &aVendorId)
1055{
1056 return i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1057}
1058
1059HRESULT HostUSBDeviceFilter::getProductId(com::Utf8Str &aProductId)
1060{
1061 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1062}
1063
1064HRESULT HostUSBDeviceFilter::setProductId(const com::Utf8Str &aProductId)
1065{
1066 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1067}
1068
1069HRESULT HostUSBDeviceFilter::getRevision(com::Utf8Str &aRevision)
1070{
1071 return i_usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
1072}
1073
1074HRESULT HostUSBDeviceFilter::setRevision(const com::Utf8Str &aRevision)
1075{
1076 return i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
1077}
1078
1079HRESULT HostUSBDeviceFilter::getManufacturer(com::Utf8Str &aManufacturer)
1080{
1081 return i_usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1082}
1083
1084HRESULT HostUSBDeviceFilter::setManufacturer(const com::Utf8Str &aManufacturer)
1085{
1086 return i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1087}
1088
1089HRESULT HostUSBDeviceFilter::getProduct(com::Utf8Str &aProduct)
1090{
1091 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1092}
1093
1094HRESULT HostUSBDeviceFilter::setProduct(const com::Utf8Str &aProduct)
1095{
1096 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1097}
1098
1099HRESULT HostUSBDeviceFilter::getSerialNumber(com::Utf8Str &aSerialNumber)
1100{
1101 return i_usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1102}
1103
1104HRESULT HostUSBDeviceFilter::setSerialNumber(const com::Utf8Str &aSerialNumber)
1105{
1106 return i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1107}
1108
1109HRESULT HostUSBDeviceFilter::getPort(com::Utf8Str &aPort)
1110{
1111 return i_usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
1112}
1113
1114HRESULT HostUSBDeviceFilter::setPort(const com::Utf8Str &aPort)
1115{
1116 return i_usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
1117}
1118
1119HRESULT HostUSBDeviceFilter::getRemote(com::Utf8Str &aRemote)
1120{
1121 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1122
1123 aRemote = bd->mRemote.string();
1124
1125 return S_OK;
1126}
1127
1128HRESULT HostUSBDeviceFilter::setRemote(const com::Utf8Str & /* aRemote */)
1129{
1130 return setError(E_NOTIMPL,
1131 tr("The remote state filter is not supported by IHostUSBDeviceFilter objects"));
1132}
1133
1134
1135HRESULT HostUSBDeviceFilter::getMaskedInterfaces(ULONG *aMaskedIfs)
1136{
1137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1138
1139 *aMaskedIfs = bd->mData.ulMaskedInterfaces;
1140
1141 return S_OK;
1142}
1143HRESULT HostUSBDeviceFilter::setMaskedInterfaces(ULONG /* aMaskedIfs */)
1144{
1145 return setError(E_NOTIMPL,
1146 tr("The masked interfaces property is not applicable to IHostUSBDeviceFilter objects"));
1147}
1148
1149// wrapped IHostUSBDeviceFilter properties
1150////////////////////////////////////////////////////////////////////////////////
1151HRESULT HostUSBDeviceFilter::getAction(USBDeviceFilterAction_T *aAction)
1152{
1153 CheckComArgOutPointerValid(aAction);
1154
1155 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1156
1157 switch (USBFilterGetFilterType(&bd->mUSBFilter))
1158 {
1159 case USBFILTERTYPE_IGNORE: *aAction = USBDeviceFilterAction_Ignore; break;
1160 case USBFILTERTYPE_CAPTURE: *aAction = USBDeviceFilterAction_Hold; break;
1161 default: *aAction = USBDeviceFilterAction_Null; break;
1162 }
1163
1164 return S_OK;
1165}
1166
1167
1168HRESULT HostUSBDeviceFilter::setAction(USBDeviceFilterAction_T aAction)
1169{
1170 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1171
1172 USBFILTERTYPE filterType;
1173 switch (aAction)
1174 {
1175 case USBDeviceFilterAction_Ignore: filterType = USBFILTERTYPE_IGNORE; break;
1176 case USBDeviceFilterAction_Hold: filterType = USBFILTERTYPE_CAPTURE; break;
1177 case USBDeviceFilterAction_Null:
1178 return setError(E_INVALIDARG,
1179 tr("Action value InvalidUSBDeviceFilterAction is not permitted"));
1180 default:
1181 return setError(E_INVALIDARG,
1182 tr("Invalid action %d"),
1183 aAction);
1184 }
1185 if (USBFilterGetFilterType(&bd->mUSBFilter) != filterType)
1186 {
1187 int vrc = USBFilterSetFilterType(&bd->mUSBFilter, filterType);
1188 if (RT_FAILURE(vrc))
1189 return setError(E_INVALIDARG,
1190 tr("Unexpected error %Rrc"),
1191 vrc);
1192
1193 /* leave the lock before informing callbacks */
1194 alock.release();
1195
1196 return mParent->i_onUSBDeviceFilterChange(this);
1197 }
1198
1199 return S_OK;
1200}
1201
1202
1203// IHostUSBDeviceFilter properties
1204////////////////////////////////////////////////////////////////////////////////
1205/**
1206 * Generic USB filter field getter.
1207 *
1208 * @param aIdx The field index.
1209 * @param aStr Where to store the value.
1210 *
1211 * @return COM status.
1212 */
1213HRESULT HostUSBDeviceFilter::i_usbFilterFieldGetter(USBFILTERIDX aIdx, com::Utf8Str &aStr)
1214{
1215 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1216 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, aStr);
1217 return S_OK;
1218}
1219
1220void HostUSBDeviceFilter::i_saveSettings(settings::USBDeviceFilter &data)
1221{
1222 AutoCaller autoCaller(this);
1223 AssertComRCReturnVoid(autoCaller.hrc());
1224
1225 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1226 data.strName = bd->mData.strName;
1227 data.fActive = bd->mData.fActive;
1228 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_VENDOR_ID, data.strVendorId);
1229 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_ID, data.strProductId);
1230 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_DEVICE, data.strRevision);
1231 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
1232 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_STR, data.strProduct);
1233 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
1234 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PORT, data.strPort);
1235
1236 COMGETTER(Action)(&data.action);
1237}
1238
1239
1240/**
1241 * Generic USB filter field setter.
1242 *
1243 * @param aIdx The field index.
1244 * @param aStr The new value.
1245 *
1246 * @return COM status.
1247 */
1248HRESULT HostUSBDeviceFilter::i_usbFilterFieldSetter(USBFILTERIDX aIdx, const com::Utf8Str &aStr)
1249{
1250 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1251 Utf8Str strOld;
1252 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, strOld);
1253 if (strOld != aStr)
1254 {
1255 //bd.backup();
1256 com::Utf8Str errStr;
1257 HRESULT hrc = USBDeviceFilter::i_usbFilterFieldFromString(&bd->mUSBFilter, aIdx, aStr, errStr);
1258 if (FAILED(hrc))
1259 {
1260 //bd.rollback();
1261 return setError(hrc, "%s", errStr.c_str());
1262 }
1263
1264 /* leave the lock before informing callbacks */
1265 alock.release();
1266
1267 return mParent->i_onUSBDeviceFilterChange(this);
1268 }
1269
1270 return S_OK;
1271}
1272/* 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