VirtualBox

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

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

Main/src-server: rc -> hrc/vrc. Enabled scm rc checks. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.6 KB
Line 
1/* $Id: USBDeviceFilterImpl.cpp 98292 2023-01-25 01:14:53Z 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 mParent->i_removeChild(this);
979
980 unconst(mParent) = NULL;
981}
982
983/**
984 * Most of the USB bits are protect by one lock to simplify things.
985 * This lock is currently the one of the Host object, which happens
986 * to be our parent.
987 */
988RWLockHandle *HostUSBDeviceFilter::lockHandle() const
989{
990 return mParent->lockHandle();
991}
992
993
994// IUSBDeviceFilter properties
995////////////////////////////////////////////////////////////////////////////////
996HRESULT HostUSBDeviceFilter::getName(com::Utf8Str &aName)
997{
998 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
999
1000 aName = bd->mData.strName;
1001
1002 return S_OK;
1003}
1004
1005
1006HRESULT HostUSBDeviceFilter::setName(const com::Utf8Str &aName)
1007{
1008 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1009
1010 if (bd->mData.strName != aName)
1011 {
1012 bd->mData.strName = aName;
1013
1014 /* leave the lock before informing callbacks */
1015 alock.release();
1016
1017 return mParent->i_onUSBDeviceFilterChange(this);
1018 }
1019
1020 return S_OK;
1021}
1022
1023
1024HRESULT HostUSBDeviceFilter::getActive(BOOL *aActive)
1025{
1026 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1027
1028 *aActive = bd->mData.fActive;
1029
1030 return S_OK;
1031}
1032
1033
1034HRESULT HostUSBDeviceFilter::setActive(BOOL aActive)
1035{
1036 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1037
1038 if (bd->mData.fActive != RT_BOOL(aActive))
1039 {
1040 bd->mData.fActive = RT_BOOL(aActive);
1041
1042 /* leave the lock before informing callbacks */
1043 alock.release();
1044
1045 return mParent->i_onUSBDeviceFilterChange(this, TRUE /* aActiveChanged */);
1046 }
1047
1048 return S_OK;
1049}
1050
1051HRESULT HostUSBDeviceFilter::getVendorId(com::Utf8Str &aVendorId)
1052{
1053 return i_usbFilterFieldGetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1054}
1055
1056HRESULT HostUSBDeviceFilter::setVendorId(const com::Utf8Str &aVendorId)
1057{
1058 return i_usbFilterFieldSetter(USBFILTERIDX_VENDOR_ID, aVendorId);
1059}
1060
1061HRESULT HostUSBDeviceFilter::getProductId(com::Utf8Str &aProductId)
1062{
1063 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1064}
1065
1066HRESULT HostUSBDeviceFilter::setProductId(const com::Utf8Str &aProductId)
1067{
1068 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_ID, aProductId);
1069}
1070
1071HRESULT HostUSBDeviceFilter::getRevision(com::Utf8Str &aRevision)
1072{
1073 return i_usbFilterFieldGetter(USBFILTERIDX_DEVICE, aRevision);
1074}
1075
1076HRESULT HostUSBDeviceFilter::setRevision(const com::Utf8Str &aRevision)
1077{
1078 return i_usbFilterFieldSetter(USBFILTERIDX_DEVICE, aRevision);
1079}
1080
1081HRESULT HostUSBDeviceFilter::getManufacturer(com::Utf8Str &aManufacturer)
1082{
1083 return i_usbFilterFieldGetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1084}
1085
1086HRESULT HostUSBDeviceFilter::setManufacturer(const com::Utf8Str &aManufacturer)
1087{
1088 return i_usbFilterFieldSetter(USBFILTERIDX_MANUFACTURER_STR, aManufacturer);
1089}
1090
1091HRESULT HostUSBDeviceFilter::getProduct(com::Utf8Str &aProduct)
1092{
1093 return i_usbFilterFieldGetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1094}
1095
1096HRESULT HostUSBDeviceFilter::setProduct(const com::Utf8Str &aProduct)
1097{
1098 return i_usbFilterFieldSetter(USBFILTERIDX_PRODUCT_STR, aProduct);
1099}
1100
1101HRESULT HostUSBDeviceFilter::getSerialNumber(com::Utf8Str &aSerialNumber)
1102{
1103 return i_usbFilterFieldGetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1104}
1105
1106HRESULT HostUSBDeviceFilter::setSerialNumber(const com::Utf8Str &aSerialNumber)
1107{
1108 return i_usbFilterFieldSetter(USBFILTERIDX_SERIAL_NUMBER_STR, aSerialNumber);
1109}
1110
1111HRESULT HostUSBDeviceFilter::getPort(com::Utf8Str &aPort)
1112{
1113 return i_usbFilterFieldGetter(USBFILTERIDX_PORT, aPort);
1114}
1115
1116HRESULT HostUSBDeviceFilter::setPort(const com::Utf8Str &aPort)
1117{
1118 return i_usbFilterFieldSetter(USBFILTERIDX_PORT, aPort);
1119}
1120
1121HRESULT HostUSBDeviceFilter::getRemote(com::Utf8Str &aRemote)
1122{
1123 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1124
1125 aRemote = bd->mRemote.string();
1126
1127 return S_OK;
1128}
1129
1130HRESULT HostUSBDeviceFilter::setRemote(const com::Utf8Str & /* aRemote */)
1131{
1132 return setError(E_NOTIMPL,
1133 tr("The remote state filter is not supported by IHostUSBDeviceFilter objects"));
1134}
1135
1136
1137HRESULT HostUSBDeviceFilter::getMaskedInterfaces(ULONG *aMaskedIfs)
1138{
1139 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1140
1141 *aMaskedIfs = bd->mData.ulMaskedInterfaces;
1142
1143 return S_OK;
1144}
1145HRESULT HostUSBDeviceFilter::setMaskedInterfaces(ULONG /* aMaskedIfs */)
1146{
1147 return setError(E_NOTIMPL,
1148 tr("The masked interfaces property is not applicable to IHostUSBDeviceFilter objects"));
1149}
1150
1151// wrapped IHostUSBDeviceFilter properties
1152////////////////////////////////////////////////////////////////////////////////
1153HRESULT HostUSBDeviceFilter::getAction(USBDeviceFilterAction_T *aAction)
1154{
1155 CheckComArgOutPointerValid(aAction);
1156
1157 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1158
1159 switch (USBFilterGetFilterType(&bd->mUSBFilter))
1160 {
1161 case USBFILTERTYPE_IGNORE: *aAction = USBDeviceFilterAction_Ignore; break;
1162 case USBFILTERTYPE_CAPTURE: *aAction = USBDeviceFilterAction_Hold; break;
1163 default: *aAction = USBDeviceFilterAction_Null; break;
1164 }
1165
1166 return S_OK;
1167}
1168
1169
1170HRESULT HostUSBDeviceFilter::setAction(USBDeviceFilterAction_T aAction)
1171{
1172 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1173
1174 USBFILTERTYPE filterType;
1175 switch (aAction)
1176 {
1177 case USBDeviceFilterAction_Ignore: filterType = USBFILTERTYPE_IGNORE; break;
1178 case USBDeviceFilterAction_Hold: filterType = USBFILTERTYPE_CAPTURE; break;
1179 case USBDeviceFilterAction_Null:
1180 return setError(E_INVALIDARG,
1181 tr("Action value InvalidUSBDeviceFilterAction is not permitted"));
1182 default:
1183 return setError(E_INVALIDARG,
1184 tr("Invalid action %d"),
1185 aAction);
1186 }
1187 if (USBFilterGetFilterType(&bd->mUSBFilter) != filterType)
1188 {
1189 int vrc = USBFilterSetFilterType(&bd->mUSBFilter, filterType);
1190 if (RT_FAILURE(vrc))
1191 return setError(E_INVALIDARG,
1192 tr("Unexpected error %Rrc"),
1193 vrc);
1194
1195 /* leave the lock before informing callbacks */
1196 alock.release();
1197
1198 return mParent->i_onUSBDeviceFilterChange(this);
1199 }
1200
1201 return S_OK;
1202}
1203
1204
1205// IHostUSBDeviceFilter properties
1206////////////////////////////////////////////////////////////////////////////////
1207/**
1208 * Generic USB filter field getter.
1209 *
1210 * @param aIdx The field index.
1211 * @param aStr Where to store the value.
1212 *
1213 * @return COM status.
1214 */
1215HRESULT HostUSBDeviceFilter::i_usbFilterFieldGetter(USBFILTERIDX aIdx, com::Utf8Str &aStr)
1216{
1217 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1218 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, aStr);
1219 return S_OK;
1220}
1221
1222void HostUSBDeviceFilter::i_saveSettings(settings::USBDeviceFilter &data)
1223{
1224 AutoCaller autoCaller(this);
1225 AssertComRCReturnVoid(autoCaller.hrc());
1226
1227 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1228 data.strName = bd->mData.strName;
1229 data.fActive = bd->mData.fActive;
1230 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_VENDOR_ID, data.strVendorId);
1231 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_ID, data.strProductId);
1232 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_DEVICE, data.strRevision);
1233 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_MANUFACTURER_STR, data.strManufacturer);
1234 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PRODUCT_STR, data.strProduct);
1235 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_SERIAL_NUMBER_STR, data.strSerialNumber);
1236 i_usbFilterFieldToString(&bd->mUSBFilter, USBFILTERIDX_PORT, data.strPort);
1237
1238 COMGETTER(Action)(&data.action);
1239}
1240
1241
1242/**
1243 * Generic USB filter field setter.
1244 *
1245 * @param aIdx The field index.
1246 * @param aStr The new value.
1247 *
1248 * @return COM status.
1249 */
1250HRESULT HostUSBDeviceFilter::i_usbFilterFieldSetter(USBFILTERIDX aIdx, const com::Utf8Str &aStr)
1251{
1252 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1253 Utf8Str strOld;
1254 i_usbFilterFieldToString(&bd->mUSBFilter, aIdx, strOld);
1255 if (strOld != aStr)
1256 {
1257 //bd.backup();
1258 com::Utf8Str errStr;
1259 HRESULT hrc = USBDeviceFilter::i_usbFilterFieldFromString(&bd->mUSBFilter, aIdx, aStr, errStr);
1260 if (FAILED(hrc))
1261 {
1262 //bd.rollback();
1263 return setError(hrc, "%s", errStr.c_str());
1264 }
1265
1266 /* leave the lock before informing callbacks */
1267 alock.release();
1268
1269 return mParent->i_onUSBDeviceFilterChange(this);
1270 }
1271
1272 return S_OK;
1273}
1274/* 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