VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months 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.8 KB
Line 
1/* $Id: USBDeviceFilterImpl.cpp 98103 2023-01-17 14:15:46Z 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 rc = S_OK;
247 do
248 {
249 rc = i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
250 if (FAILED(rc)) break;
251
252 rc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
253 if (FAILED(rc)) break;
254
255 rc = i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
256 if (FAILED(rc)) break;
257
258 rc = i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
259 if (FAILED(rc)) break;
260
261 rc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, data.strProduct);
262 if (FAILED(rc)) break;
263
264 rc = i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
265 if (FAILED(rc)) break;
266
267 rc = i_usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
268 if (FAILED(rc)) break;
269
270 rc = COMSETTER(Remote)(Bstr(data.strRemote).raw());
271 if (FAILED(rc)) break;
272
273 rc = COMSETTER(MaskedInterfaces)(data.ulMaskedInterfaces);
274 if (FAILED(rc)) break;
275 }
276 while (0);
277
278 /* Confirm successful initialization when it's the case */
279 if (SUCCEEDED(rc))
280 autoInitSpan.setSucceeded();
281
282 return rc;
283}
284
285/**
286 * Initializes the USB device filter object (short version).
287 *
288 * @param aParent Handle of the parent object.
289 * @param aName Name of the filter.
290 */
291HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, IN_BSTR aName)
292{
293 LogFlowThisFunc(("aParent=%p\n", aParent));
294
295 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
296
297 /* Enclose the state transition NotReady->InInit->Ready */
298 AutoInitSpan autoInitSpan(this);
299 AssertReturn(autoInitSpan.isOk(), E_FAIL);
300
301 unconst(mParent) = aParent;
302 /* mPeer is left null */
303
304 m_fModified = false;
305
306 bd.allocate();
307
308 bd->mData.strName = Utf8Str(aName);
309 bd->mData.fActive = FALSE;
310 bd->mData.ulMaskedInterfaces = 0;
311
312 /* initialize all filters to any match using null string */
313 USBFilterInit(&bd->mUSBFilter, USBFILTERTYPE_CAPTURE);
314 bd->mRemote = NULL;
315
316 mInList = false;
317
318 /* Confirm successful initialization */
319 autoInitSpan.setSucceeded();
320
321 return S_OK;
322}
323
324/**
325 * Initializes the object given another object
326 * (a kind of copy constructor). This object shares data with
327 * the object passed as an argument.
328 *
329 * @param aParent Handle of the parent object.
330 * @param aThat
331 * @param aReshare
332 * When false, the original object will remain a data owner.
333 * Otherwise, data ownership will be transferred from the original
334 * object to this one.
335 *
336 * @note This object must be destroyed before the original object
337 * it shares data with is destroyed.
338 *
339 * @note Locks @a aThat object for writing if @a aReshare is @c true, or for
340 * reading if @a aReshare is false.
341 */
342HRESULT USBDeviceFilter::init(USBDeviceFilters *aParent, USBDeviceFilter *aThat,
343 bool aReshare /* = false */)
344{
345 LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
346 aParent, aThat, aReshare));
347
348 ComAssertRet(aParent && aThat, E_INVALIDARG);
349
350 /* Enclose the state transition NotReady->InInit->Ready */
351 AutoInitSpan autoInitSpan(this);
352 AssertReturn(autoInitSpan.isOk(), E_FAIL);
353
354 unconst(mParent) = aParent;
355
356 m_fModified = false;
357
358 /* sanity */
359 AutoCaller thatCaller(aThat);
360 AssertComRCReturnRC(thatCaller.rc());
361
362 if (aReshare)
363 {
364 AutoWriteLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
365
366 unconst(aThat->mPeer) = this;
367 bd.attach(aThat->bd);
368 }
369 else
370 {
371 unconst(mPeer) = aThat;
372
373 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
374 bd.share(aThat->bd);
375 }
376
377 /* the arbitrary ID field is not reset because
378 * the copy is a shadow of the original */
379
380 mInList = aThat->mInList;
381
382 /* Confirm successful initialization */
383 autoInitSpan.setSucceeded();
384
385 return S_OK;
386}
387
388/**
389 * Initializes the guest object given another guest object
390 * (a kind of copy constructor). This object makes a private copy of data
391 * of the original object passed as an argument.
392 *
393 * @note Locks @a aThat object for reading.
394 */
395HRESULT USBDeviceFilter::initCopy(USBDeviceFilters *aParent, USBDeviceFilter *aThat)
396{
397 LogFlowThisFunc(("aParent=%p, aThat=%p\n", aParent, aThat));
398
399 ComAssertRet(aParent && aThat, E_INVALIDARG);
400
401 /* Enclose the state transition NotReady->InInit->Ready */
402 AutoInitSpan autoInitSpan(this);
403 AssertReturn(autoInitSpan.isOk(), E_FAIL);
404
405 unconst(mParent) = aParent;
406 /* mPeer is left null */
407
408 m_fModified = false;
409
410 /* sanity */
411 AutoCaller thatCaller(aThat);
412 AssertComRCReturnRC(thatCaller.rc());
413
414 AutoReadLock thatLock(aThat COMMA_LOCKVAL_SRC_POS);
415 bd.attachCopy(aThat->bd);
416
417 /* reset the arbitrary ID field
418 * (this field is something unique that two distinct objects, even if they
419 * are deep copies of each other, should not share) */
420 bd->mId = NULL;
421
422 mInList = aThat->mInList;
423
424 /* Confirm successful initialization */
425 autoInitSpan.setSucceeded();
426
427 return S_OK;
428}
429
430/**
431 * Uninitializes the instance and sets the ready flag to FALSE.
432 * Called either from FinalRelease() or by the parent when it gets destroyed.
433 */
434void USBDeviceFilter::uninit()
435{
436 LogFlowThisFunc(("\n"));
437
438 /* Enclose the state transition Ready->InUninit->NotReady */
439 AutoUninitSpan autoUninitSpan(this);
440 if (autoUninitSpan.uninitDone())
441 return;
442
443 mInList = false;
444
445 bd.free();
446
447 unconst(mPeer) = NULL;
448 unconst(mParent) = NULL;
449}
450
451
452// IUSBDeviceFilter properties
453////////////////////////////////////////////////////////////////////////////////
454
455HRESULT USBDeviceFilter::getName(com::Utf8Str &aName)
456{
457 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
458
459 return aName.assignEx(bd->mData.strName);
460}
461
462HRESULT USBDeviceFilter::setName(const com::Utf8Str &aName)
463{
464 /* the machine needs to be mutable */
465 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
466 if (FAILED(adep.rc())) return adep.rc();
467
468 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
469
470 if (bd->mData.strName != aName)
471 {
472 m_fModified = true;
473 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
474
475 bd.backup();
476 bd->mData.strName = aName;
477
478 // leave the lock before informing callbacks
479 alock.release();
480
481 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
482 pMachine->i_setModified(Machine::IsModified_USB);
483 mlock.release();
484
485 return mParent->i_onDeviceFilterChange(this);
486 }
487
488 return S_OK;
489}
490
491HRESULT USBDeviceFilter::getActive(BOOL *aActive)
492{
493 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
494
495 *aActive = bd->mData.fActive;
496
497 return S_OK;
498}
499
500HRESULT USBDeviceFilter::setActive(const BOOL aActive)
501{
502 /* the machine needs to be mutable */
503 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
504 if (FAILED(adep.rc())) return adep.rc();
505
506 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
507
508 if (bd->mData.fActive != RT_BOOL(aActive))
509 {
510 m_fModified = true;
511 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
512
513 bd.backup();
514 bd->mData.fActive = RT_BOOL(aActive);
515
516 // leave the lock before informing callbacks
517 alock.release();
518
519 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
520 pMachine->i_setModified(Machine::IsModified_USB);
521 mlock.release();
522
523 return mParent->i_onDeviceFilterChange(this, TRUE /* aActiveChanged */);
524 }
525
526 return S_OK;
527}
528
529HRESULT USBDeviceFilter::getVendorId(com::Utf8Str &aVendorId)
530{
531 return i_usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
532}
533
534HRESULT USBDeviceFilter::setVendorId(const com::Utf8Str &aVendorId)
535{
536 return i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
537}
538
539HRESULT USBDeviceFilter::getProductId(com::Utf8Str &aProductId)
540{
541 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
542}
543
544HRESULT USBDeviceFilter::setProductId(const com::Utf8Str &aProductId)
545{
546 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
547}
548
549HRESULT USBDeviceFilter::getRevision(com::Utf8Str &aRevision)
550{
551 return i_usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
552}
553
554HRESULT USBDeviceFilter::setRevision(const com::Utf8Str &aRevision)
555{
556 return i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
557}
558
559HRESULT USBDeviceFilter::getManufacturer(com::Utf8Str &aManufacturer)
560{
561 return i_usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
562}
563
564HRESULT USBDeviceFilter::setManufacturer(const com::Utf8Str &aManufacturer)
565{
566 return i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
567}
568
569HRESULT USBDeviceFilter::getProduct(com::Utf8Str &aProduct)
570{
571 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
572}
573
574HRESULT USBDeviceFilter::setProduct(const com::Utf8Str &aProduct)
575{
576 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
577}
578
579HRESULT USBDeviceFilter::getSerialNumber(com::Utf8Str &aSerialNumber)
580{
581 return i_usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
582}
583
584HRESULT USBDeviceFilter::setSerialNumber(const com::Utf8Str &aSerialNumber)
585{
586 return i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
587}
588
589HRESULT USBDeviceFilter::getPort(com::Utf8Str &aPort)
590{
591 return i_usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
592}
593
594HRESULT USBDeviceFilter::setPort(const com::Utf8Str &aPort)
595{
596 return i_usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
597}
598
599
600HRESULT USBDeviceFilter::getRemote(com::Utf8Str &aRemote)
601{
602 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
603
604 aRemote = bd->mRemote.string();
605
606 return S_OK;
607}
608
609HRESULT USBDeviceFilter::setRemote(const com::Utf8Str &aRemote)
610{
611 /* the machine needs to be mutable */
612 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
613 if (FAILED(adep.rc())) return adep.rc();
614 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
615 Bstr bRemote = Bstr(aRemote).raw();
616
617 if (bd->mRemote.string() != bRemote)
618 {
619 BackupableUSBDeviceFilterData::BOOLFilter flt = bRemote;
620 ComAssertRet(!flt.isNull(), E_FAIL);
621 if (!flt.isValid())
622 return setError(E_INVALIDARG,
623 tr("Remote state filter string '%s' is not valid (error at position %d)"),
624 aRemote.c_str(), flt.errorPosition() + 1);
625
626 m_fModified = true;
627 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
628
629 bd.backup();
630 bd->mRemote = flt;
631
632 // leave the lock before informing callbacks
633 alock.release();
634
635 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
636 pMachine->i_setModified(Machine::IsModified_USB);
637 mlock.release();
638
639 return mParent->i_onDeviceFilterChange(this);
640 }
641 return S_OK;
642}
643
644
645HRESULT USBDeviceFilter::getMaskedInterfaces(ULONG *aMaskedIfs)
646{
647 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
648
649 *aMaskedIfs = bd->mData.ulMaskedInterfaces;
650
651 return S_OK;
652}
653
654HRESULT USBDeviceFilter::setMaskedInterfaces(ULONG aMaskedIfs)
655{
656 /* the machine needs to be mutable */
657 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
658 if (FAILED(adep.rc())) return adep.rc();
659
660 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
661
662 if (bd->mData.ulMaskedInterfaces != aMaskedIfs)
663 {
664 m_fModified = true;
665 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
666
667 bd.backup();
668 bd->mData.ulMaskedInterfaces = aMaskedIfs;
669 // leave the lock before informing callbacks
670 alock.release();
671
672 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
673 pMachine->i_setModified(Machine::IsModified_USB);
674 mlock.release();
675
676 return mParent->i_onDeviceFilterChange(this);
677 }
678
679 return S_OK;
680}
681
682// public methods only for internal purposes
683////////////////////////////////////////////////////////////////////////////////
684
685bool USBDeviceFilter::i_isModified()
686{
687 AutoCaller autoCaller(this);
688 AssertComRCReturn(autoCaller.rc(), false);
689
690 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
691 return m_fModified;
692}
693
694/**
695 * @note Locks this object for writing.
696 */
697void USBDeviceFilter::i_rollback()
698{
699 /* sanity */
700 AutoCaller autoCaller(this);
701 AssertComRCReturnVoid(autoCaller.rc());
702
703 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
704
705 bd.rollback();
706}
707
708/**
709 * @note Locks this object for writing, together with the peer object (also
710 * for writing) if there is one.
711 */
712void USBDeviceFilter::i_commit()
713{
714 /* sanity */
715 AutoCaller autoCaller(this);
716 AssertComRCReturnVoid(autoCaller.rc());
717
718 /* sanity too */
719 AutoCaller peerCaller(mPeer);
720 AssertComRCReturnVoid(peerCaller.rc());
721
722 /* lock both for writing since we modify both (mPeer is "master" so locked
723 * first) */
724 AutoMultiWriteLock2 alock(mPeer, this COMMA_LOCKVAL_SRC_POS);
725
726 if (bd.isBackedUp())
727 {
728 bd.commit();
729 if (mPeer)
730 {
731 /* attach new data to the peer and reshare it */
732 mPeer->bd.attach(bd);
733 }
734 }
735}
736
737/**
738 * Cancels sharing (if any) by making an independent copy of data.
739 * This operation also resets this object's peer to NULL.
740 *
741 * @note Locks this object for writing, together with the peer object
742 * represented by @a aThat (locked for reading).
743 */
744void USBDeviceFilter::unshare()
745{
746 /* sanity */
747 AutoCaller autoCaller(this);
748 AssertComRCReturnVoid(autoCaller.rc());
749
750 /* sanity too */
751 AutoCaller peerCaller(mPeer);
752 AssertComRCReturnVoid(peerCaller.rc());
753
754 /* peer is not modified, lock it for reading (mPeer is "master" so locked
755 * first) */
756 AutoReadLock rl(mPeer COMMA_LOCKVAL_SRC_POS);
757 AutoWriteLock wl(this COMMA_LOCKVAL_SRC_POS);
758
759 if (bd.isShared())
760 {
761 if (!bd.isBackedUp())
762 bd.backup();
763
764 bd.commit();
765 }
766
767 unconst(mPeer) = NULL;
768}
769
770/**
771 * Generic USB filter field getter; converts the field value to UTF-16.
772 *
773 * @param aIdx The field index.
774 * @param aStr Where to store the value.
775 *
776 * @return COM status.
777 */
778HRESULT USBDeviceFilter::i_usbFilterFieldGetter(USBFILTERIDX aIdx, com::Utf8Str &aStr)
779{
780 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
781
782 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, aStr);
783 return S_OK;
784}
785
786/**
787 * Generic USB filter field setter, expects UTF-8 input.
788 *
789 * @param aIdx The field index.
790 * @param strNew The new value.
791 *
792 * @return COM status.
793 */
794HRESULT USBDeviceFilter::i_usbFilterFieldSetter(USBFILTERIDX aIdx,
795 const com::Utf8Str &strNew)
796{
797 /* the machine needs to be mutable */
798 AutoMutableOrSavedOrRunningStateDependency adep(mParent->i_getMachine());
799 if (FAILED(adep.rc())) return adep.rc();
800
801 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
802
803
804 com::Utf8Str strOld;
805 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, strOld);
806 if (strOld != strNew)
807 {
808 m_fModified = true;
809 ComObjPtr<Machine> pMachine = mParent->i_getMachine();
810
811 bd.backup();
812
813 com::Utf8Str errStr;
814 HRESULT rc = i_usbFilterFieldFromString(&bd->mUSBFilter, aIdx, strNew, errStr);
815 if (FAILED(rc))
816 {
817 bd.rollback();
818 return setError(rc, "%s", errStr.c_str());
819 }
820
821 // leave the lock before informing callbacks
822 alock.release();
823
824 AutoWriteLock mlock(pMachine COMMA_LOCKVAL_SRC_POS);
825 pMachine->i_setModified(Machine::IsModified_USB);
826 mlock.release();
827
828 return mParent->i_onDeviceFilterChange(this);
829 }
830
831 return S_OK;
832}
833
834
835////////////////////////////////////////////////////////////////////////////////
836// HostUSBDeviceFilter
837////////////////////////////////////////////////////////////////////////////////
838
839// constructor / destructor
840////////////////////////////////////////////////////////////////////////////////
841
842HostUSBDeviceFilter::HostUSBDeviceFilter()
843 : mParent(NULL)
844{
845}
846
847HostUSBDeviceFilter::~HostUSBDeviceFilter()
848{
849}
850
851
852HRESULT HostUSBDeviceFilter::FinalConstruct()
853{
854 return S_OK;
855}
856
857void HostUSBDeviceFilter::FinalRelease()
858{
859 uninit();
860}
861
862// public initializer/uninitializer for internal purposes only
863////////////////////////////////////////////////////////////////////////////////
864
865/**
866 * Initializes the USB device filter object.
867 *
868 * @param aParent Handle of the parent object.
869 * @param data Settings data.
870 */
871HRESULT HostUSBDeviceFilter::init(Host *aParent,
872 const settings::USBDeviceFilter &data)
873{
874 LogFlowThisFunc(("aParent=%p\n", aParent));
875
876 ComAssertRet(aParent && !data.strName.isEmpty(), E_INVALIDARG);
877
878 /* Enclose the state transition NotReady->InInit->Ready */
879 AutoInitSpan autoInitSpan(this);
880 AssertReturn(autoInitSpan.isOk(), E_FAIL);
881
882 unconst(mParent) = aParent;
883
884 /* register with parent early, since uninit() will unconditionally
885 * unregister on failure */
886 mParent->i_addChild(this);
887
888 bd.allocate();
889 bd->mData.strName = data.strName;
890 bd->mData.fActive = data.fActive;
891 USBFilterInit (&bd->mUSBFilter, USBFILTERTYPE_IGNORE);
892 bd->mRemote = NULL;
893 bd->mData.ulMaskedInterfaces = 0;
894
895 mInList = false;
896
897 /* use setters for the attributes below to reuse parsing errors
898 * handling */
899
900 HRESULT rc = S_OK;
901 do
902 {
903 rc = setAction(data.action);
904 if (FAILED(rc)) break;
905
906 rc = i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, data.strVendorId);
907 if (FAILED(rc)) break;
908
909 rc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProductId);
910 if (FAILED(rc)) break;
911
912 rc = i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, data.strRevision);
913 if (FAILED(rc)) break;
914
915 rc = i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
916 if (FAILED(rc)) break;
917
918 rc = i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, data.strProduct);
919 if (FAILED(rc)) break;
920
921 rc = i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
922 if (FAILED(rc)) break;
923
924 rc = i_usbFilterFieldSetter(USBFILTERIDX_PORT, data.strPort);
925 if (FAILED(rc)) break;
926 }
927 while (0);
928
929 /* Confirm successful initialization when it's the case */
930 if (SUCCEEDED(rc))
931 autoInitSpan.setSucceeded();
932
933 return rc;
934}
935
936/**
937 * Initializes the USB device filter object (short version).
938 *
939 * @param aParent Handle of the parent object.
940 * @param aName Filter name.
941 */
942HRESULT HostUSBDeviceFilter::init(Host *aParent, IN_BSTR aName)
943{
944 LogFlowThisFunc(("aParent=%p\n", aParent));
945
946 ComAssertRet(aParent && aName && *aName, E_INVALIDARG);
947
948 /* Enclose the state transition NotReady->InInit->Ready */
949 AutoInitSpan autoInitSpan(this);
950 AssertReturn(autoInitSpan.isOk(), E_FAIL);
951
952 unconst(mParent) = aParent;
953
954 /* register with parent early, since uninit() will unconditionally
955 * unregister on failure */
956 mParent->i_addChild(this);
957
958 bd.allocate();
959
960 bd->mData.strName = Utf8Str(aName);
961 bd->mData.fActive = FALSE;
962 mInList = false;
963 USBFilterInit(&bd->mUSBFilter, USBFILTERTYPE_IGNORE);
964 bd->mRemote = NULL;
965 bd->mData.ulMaskedInterfaces = 0;
966
967 /* Confirm successful initialization */
968 autoInitSpan.setSucceeded();
969
970 return S_OK;
971}
972
973/**
974 * Uninitializes the instance and sets the ready flag to FALSE.
975 * Called either from FinalRelease() or by the parent when it gets destroyed.
976 */
977void HostUSBDeviceFilter::uninit()
978{
979 LogFlowThisFunc(("\n"));
980
981 /* Enclose the state transition Ready->InUninit->NotReady */
982 AutoUninitSpan autoUninitSpan(this);
983 if (autoUninitSpan.uninitDone())
984 return;
985
986 mInList = false;
987
988 bd.free();
989
990 mParent->i_removeChild(this);
991
992 unconst(mParent) = NULL;
993}
994
995/**
996 * Most of the USB bits are protect by one lock to simplify things.
997 * This lock is currently the one of the Host object, which happens
998 * to be our parent.
999 */
1000RWLockHandle *HostUSBDeviceFilter::lockHandle() const
1001{
1002 return mParent->lockHandle();
1003}
1004
1005
1006// IUSBDeviceFilter properties
1007////////////////////////////////////////////////////////////////////////////////
1008HRESULT HostUSBDeviceFilter::getName(com::Utf8Str &aName)
1009{
1010 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1011
1012 aName = bd->mData.strName;
1013
1014 return S_OK;
1015}
1016
1017
1018HRESULT HostUSBDeviceFilter::setName(const com::Utf8Str &aName)
1019{
1020 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1021
1022 if (bd->mData.strName != aName)
1023 {
1024 bd->mData.strName = aName;
1025
1026 /* leave the lock before informing callbacks */
1027 alock.release();
1028
1029 return mParent->i_onUSBDeviceFilterChange(this);
1030 }
1031
1032 return S_OK;
1033}
1034
1035
1036HRESULT HostUSBDeviceFilter::getActive(BOOL *aActive)
1037{
1038 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1039
1040 *aActive = bd->mData.fActive;
1041
1042 return S_OK;
1043}
1044
1045
1046HRESULT HostUSBDeviceFilter::setActive(BOOL aActive)
1047{
1048 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1049
1050 if (bd->mData.fActive != RT_BOOL(aActive))
1051 {
1052 bd->mData.fActive = RT_BOOL(aActive);
1053
1054 /* leave the lock before informing callbacks */
1055 alock.release();
1056
1057 return mParent->i_onUSBDeviceFilterChange(this, TRUE /* aActiveChanged */);
1058 }
1059
1060 return S_OK;
1061}
1062
1063HRESULT HostUSBDeviceFilter::getVendorId(com::Utf8Str &aVendorId)
1064{
1065 return i_usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1066}
1067
1068HRESULT HostUSBDeviceFilter::setVendorId(const com::Utf8Str &aVendorId)
1069{
1070 return i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1071}
1072
1073HRESULT HostUSBDeviceFilter::getProductId(com::Utf8Str &aProductId)
1074{
1075 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1076}
1077
1078HRESULT HostUSBDeviceFilter::setProductId(const com::Utf8Str &aProductId)
1079{
1080 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1081}
1082
1083HRESULT HostUSBDeviceFilter::getRevision(com::Utf8Str &aRevision)
1084{
1085 return i_usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
1086}
1087
1088HRESULT HostUSBDeviceFilter::setRevision(const com::Utf8Str &aRevision)
1089{
1090 return i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
1091}
1092
1093HRESULT HostUSBDeviceFilter::getManufacturer(com::Utf8Str &aManufacturer)
1094{
1095 return i_usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1096}
1097
1098HRESULT HostUSBDeviceFilter::setManufacturer(const com::Utf8Str &aManufacturer)
1099{
1100 return i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1101}
1102
1103HRESULT HostUSBDeviceFilter::getProduct(com::Utf8Str &aProduct)
1104{
1105 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1106}
1107
1108HRESULT HostUSBDeviceFilter::setProduct(const com::Utf8Str &aProduct)
1109{
1110 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1111}
1112
1113HRESULT HostUSBDeviceFilter::getSerialNumber(com::Utf8Str &aSerialNumber)
1114{
1115 return i_usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1116}
1117
1118HRESULT HostUSBDeviceFilter::setSerialNumber(const com::Utf8Str &aSerialNumber)
1119{
1120 return i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1121}
1122
1123HRESULT HostUSBDeviceFilter::getPort(com::Utf8Str &aPort)
1124{
1125 return i_usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
1126}
1127
1128HRESULT HostUSBDeviceFilter::setPort(const com::Utf8Str &aPort)
1129{
1130 return i_usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
1131}
1132
1133HRESULT HostUSBDeviceFilter::getRemote(com::Utf8Str &aRemote)
1134{
1135 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1136
1137 aRemote = bd->mRemote.string();
1138
1139 return S_OK;
1140}
1141
1142HRESULT HostUSBDeviceFilter::setRemote(const com::Utf8Str & /* aRemote */)
1143{
1144 return setError(E_NOTIMPL,
1145 tr("The remote state filter is not supported by IHostUSBDeviceFilter objects"));
1146}
1147
1148
1149HRESULT HostUSBDeviceFilter::getMaskedInterfaces(ULONG *aMaskedIfs)
1150{
1151 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1152
1153 *aMaskedIfs = bd->mData.ulMaskedInterfaces;
1154
1155 return S_OK;
1156}
1157HRESULT HostUSBDeviceFilter::setMaskedInterfaces(ULONG /* aMaskedIfs */)
1158{
1159 return setError(E_NOTIMPL,
1160 tr("The masked interfaces property is not applicable to IHostUSBDeviceFilter objects"));
1161}
1162
1163// wrapped IHostUSBDeviceFilter properties
1164////////////////////////////////////////////////////////////////////////////////
1165HRESULT HostUSBDeviceFilter::getAction(USBDeviceFilterAction_T *aAction)
1166{
1167 CheckComArgOutPointerValid(aAction);
1168
1169 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1170
1171 switch (USBFilterGetFilterType(&bd->mUSBFilter))
1172 {
1173 case USBFILTERTYPE_IGNORE: *aAction = USBDeviceFilterAction_Ignore; break;
1174 case USBFILTERTYPE_CAPTURE: *aAction = USBDeviceFilterAction_Hold; break;
1175 default: *aAction = USBDeviceFilterAction_Null; break;
1176 }
1177
1178 return S_OK;
1179}
1180
1181
1182HRESULT HostUSBDeviceFilter::setAction(USBDeviceFilterAction_T aAction)
1183{
1184 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1185
1186 USBFILTERTYPE filterType;
1187 switch (aAction)
1188 {
1189 case USBDeviceFilterAction_Ignore: filterType = USBFILTERTYPE_IGNORE; break;
1190 case USBDeviceFilterAction_Hold: filterType = USBFILTERTYPE_CAPTURE; break;
1191 case USBDeviceFilterAction_Null:
1192 return setError(E_INVALIDARG,
1193 tr("Action value InvalidUSBDeviceFilterAction is not permitted"));
1194 default:
1195 return setError(E_INVALIDARG,
1196 tr("Invalid action %d"),
1197 aAction);
1198 }
1199 if (USBFilterGetFilterType(&bd->mUSBFilter) != filterType)
1200 {
1201 int vrc = USBFilterSetFilterType(&bd->mUSBFilter, filterType);
1202 if (RT_FAILURE(vrc))
1203 return setError(E_INVALIDARG,
1204 tr("Unexpected error %Rrc"),
1205 vrc);
1206
1207 /* leave the lock before informing callbacks */
1208 alock.release();
1209
1210 return mParent->i_onUSBDeviceFilterChange(this);
1211 }
1212
1213 return S_OK;
1214}
1215
1216
1217// IHostUSBDeviceFilter properties
1218////////////////////////////////////////////////////////////////////////////////
1219/**
1220 * Generic USB filter field getter.
1221 *
1222 * @param aIdx The field index.
1223 * @param aStr Where to store the value.
1224 *
1225 * @return COM status.
1226 */
1227HRESULT HostUSBDeviceFilter::i_usbFilterFieldGetter(USBFILTERIDX aIdx, com::Utf8Str &aStr)
1228{
1229 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1230 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, aStr);
1231 return S_OK;
1232}
1233
1234void HostUSBDeviceFilter::i_saveSettings(settings::USBDeviceFilter &data)
1235{
1236 AutoCaller autoCaller(this);
1237 AssertComRCReturnVoid(autoCaller.rc());
1238
1239 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1240 data.strName = bd->mData.strName;
1241 data.fActive = bd->mData.fActive;
1242 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_VENDOR_ID, data.strVendorId);
1243 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_ID, data.strProductId);
1244 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_DEVICE, data.strRevision);
1245 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
1246 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_STR, data.strProduct);
1247 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
1248 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PORT, data.strPort);
1249
1250 COMGETTER(Action)(&data.action);
1251}
1252
1253
1254/**
1255 * Generic USB filter field setter.
1256 *
1257 * @param aIdx The field index.
1258 * @param aStr The new value.
1259 *
1260 * @return COM status.
1261 */
1262HRESULT HostUSBDeviceFilter::i_usbFilterFieldSetter(USBFILTERIDX aIdx, const com::Utf8Str &aStr)
1263{
1264 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1265 Utf8Str strOld;
1266 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, strOld);
1267 if (strOld != aStr)
1268 {
1269 //bd.backup();
1270 com::Utf8Str errStr;
1271 HRESULT rc = USBDeviceFilter::i_usbFilterFieldFromString(&bd->mUSBFilter, aIdx, aStr, errStr);
1272 if (FAILED(rc))
1273 {
1274 //bd.rollback();
1275 return setError(rc, "%s", errStr.c_str());
1276 }
1277
1278 /* leave the lock before informing callbacks */
1279 alock.release();
1280
1281 return mParent->i_onUSBDeviceFilterChange(this);
1282 }
1283
1284 return S_OK;
1285}
1286/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use