VirtualBox

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

Last change on this file since 86506 was 82968, checked in by vboxsync, 4 years ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use