/* $Id$ */
/** @file
* Implementation of VirtualBox COM components: USBDeviceFilter and HostUSBDeviceFilter
*/
/*
* Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#include "USBDeviceFilterImpl.h"
#include "USBDeviceFiltersImpl.h"
#include "MachineImpl.h"
#include "HostImpl.h"
#include <VBox/settings.h>
#include "AutoStateDep.h"
#include "AutoCaller.h"
#include "Logging.h"
////////////////////////////////////////////////////////////////////////////////
// Internal Helpers
////////////////////////////////////////////////////////////////////////////////
/**
* Converts a USBFilter field into a string.
*
* (This function is also used by HostUSBDeviceFilter.)
*
* @param aFilter The filter.
* @param aIdx The field index.
* @param aStr The output string.
*/
{
{
}
else if (USBFilterIsMethodString(matchingMethod))
{
}
else
}
/*static*/
{
switch (aIdx)
{
default: return "";
}
return "";
}
/**
* Interprets a string and assigns it to a USBFilter field.
*
* (This function is also used by HostUSBDeviceFilter.)
*
* @param aFilter The filter.
* @param aIdx The field index.
* @param aStr The input string.
* @param aName The field name for use in the error string.
* @param aErrStr Where to return the error string on failure.
*
* @return COM status code.
* @remark The idea was to have this as a static function, but tr() doesn't wanna work without a class :-/
*/
{
int vrc;
else
{
if (USBFilterIsNumericField(aIdx))
{
/* Is it a lonely number? */
char *pszNext;
if (RT_SUCCESS(vrc))
if ( vrc == VINF_SUCCESS
&& !*pszNext)
{
if (u64 > 0xffff)
{
// there was a bug writing out "-1" values in earlier versions, which got
// written as "FFFFFFFF"; make sure we don't fail on those
if (u64 == 0xffffffff)
u64 = 0xffff;
else
{
return E_INVALIDARG;
}
}
}
else
}
else
{
/* Any wildcard in the string? */
/* || strchr (psz, '[') - later */
)
else
}
}
if (RT_FAILURE(vrc))
{
if (vrc == VERR_INVALID_PARAMETER)
{
aErrStr = Utf8StrFmt(tr("The %s filter expression '%s' is not valid"), i_describeUSBFilterIdx(aIdx), aValue.c_str());
return E_INVALIDARG;
}
if (vrc == VERR_BUFFER_OVERFLOW)
{
return E_FAIL;
}
return E_FAIL;
}
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
// USBDeviceFilter
////////////////////////////////////////////////////////////////////////////////
// constructor / destructor
////////////////////////////////////////////////////////////////////////////////
{
}
{
}
{
return BaseFinalConstruct();
}
{
uninit();
}
// public initializer/uninitializer for internal purposes only
////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the USB device filter object.
*
* @param aParent Handle of the parent object.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* mPeer is left null */
m_fModified = false;
mData->mMaskedIfs = 0;
/* initialize all filters to any match using null string */
mInList = false;
/* use setters for the attributes below to reuse parsing errors
* handling */
do
{
}
while (0);
/* Confirm successful initialization when it's the case */
return rc;
}
/**
* Initializes the USB device filter object (short version).
*
* @param aParent Handle of the parent object.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* mPeer is left null */
m_fModified = false;
mData->mMaskedIfs = 0;
/* initialize all filters to any match using null string */
mInList = false;
/* Confirm successful initialization */
return S_OK;
}
/**
* Initializes the object given another object
* (a kind of copy constructor). This object shares data with
* the object passed as an argument.
*
* @param aReshare
* When false, the original object will remain a data owner.
* Otherwise, data ownership will be transferred from the original
* object to this one.
*
* @note This object must be destroyed before the original object
* it shares data with is destroyed.
*
* @note Locks @a aThat object for writing if @a aReshare is @c true, or for
* reading if @a aReshare is false.
*/
bool aReshare /* = false */)
{
LogFlowThisFunc(("aParent=%p, aThat=%p, aReshare=%RTbool\n",
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
m_fModified = false;
/* sanity */
if (aReshare)
{
}
else
{
}
/* the arbitrary ID field is not reset because
* the copy is a shadow of the original */
/* Confirm successful initialization */
return S_OK;
}
/**
* Initializes the guest object given another guest object
* (a kind of copy constructor). This object makes a private copy of data
* of the original object passed as an argument.
*
* @note Locks @a aThat object for reading.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* mPeer is left null */
m_fModified = false;
/* sanity */
/* reset the arbitrary ID field
* (this field is something unique that two distinct objects, even if they
* are deep copies of each other, should not share) */
/* Confirm successful initialization */
return S_OK;
}
/**
* Uninitializes the instance and sets the ready flag to FALSE.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
{
LogFlowThisFunc(("\n"));
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
mInList = false;
}
// IUSBDeviceFilter properties
////////////////////////////////////////////////////////////////////////////////
{
return S_OK;
}
{
/* the machine needs to be mutable */
{
m_fModified = true;
// leave the lock before informing callbacks
return mParent->i_onDeviceFilterChange(this);
}
return S_OK;
}
{
return S_OK;
}
{
/* the machine needs to be mutable */
{
m_fModified = true;
// leave the lock before informing callbacks
}
return S_OK;
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
return S_OK;
}
{
/* the machine needs to be mutable */
{
return setError(E_INVALIDARG,
tr("Remote state filter string '%s' is not valid (error at position %d)"),
m_fModified = true;
// leave the lock before informing callbacks
return mParent->i_onDeviceFilterChange(this);
}
return S_OK;
}
{
return S_OK;
}
{
/* the machine needs to be mutable */
{
m_fModified = true;
// leave the lock before informing callbacks
return mParent->i_onDeviceFilterChange(this);
}
return S_OK;
}
// public methods only for internal purposes
////////////////////////////////////////////////////////////////////////////////
{
AutoCaller autoCaller(this);
return m_fModified;
}
/**
* @note Locks this object for writing.
*/
{
/* sanity */
AutoCaller autoCaller(this);
}
/**
* @note Locks this object for writing, together with the peer object (also
* for writing) if there is one.
*/
{
/* sanity */
AutoCaller autoCaller(this);
/* sanity too */
/* lock both for writing since we modify both (mPeer is "master" so locked
* first) */
if (mData.isBackedUp())
{
if (mPeer)
{
/* attach new data to the peer and reshare it */
}
}
}
/**
* Cancels sharing (if any) by making an independent copy of data.
* This operation also resets this object's peer to NULL.
*
* @note Locks this object for writing, together with the peer object
* represented by @a aThat (locked for reading).
*/
{
/* sanity */
AutoCaller autoCaller(this);
/* sanity too */
/* peer is not modified, lock it for reading (mPeer is "master" so locked
* first) */
{
if (!mData.isBackedUp())
}
}
/**
* Generic USB filter field getter; converts the field value to UTF-16.
*
* @param aIdx The field index.
* @param aStr Where to store the value.
*
* @return COM status.
*/
{
return S_OK;
}
/**
* Generic USB filter field setter, expects UTF-8 input.
*
* @param aIdx The field index.
* @param aStr The new value.
*
* @return COM status.
*/
{
/* the machine needs to be mutable */
{
m_fModified = true;
{
}
// leave the lock before informing callbacks
return mParent->i_onDeviceFilterChange(this);
}
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
// HostUSBDeviceFilter
////////////////////////////////////////////////////////////////////////////////
// constructor / destructor
////////////////////////////////////////////////////////////////////////////////
{
}
{
}
{
return S_OK;
}
{
uninit();
}
// public initializer/uninitializer for internal purposes only
////////////////////////////////////////////////////////////////////////////////
/**
* Initializes the USB device filter object.
*
* @param aParent Handle of the parent object.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* register with parent early, since uninit() will unconditionally
* unregister on failure */
mParent->i_addChild(this);
mData->mMaskedIfs = 0;
mInList = false;
/* use setters for the attributes below to reuse parsing errors
* handling */
do
{
}
while (0);
/* Confirm successful initialization when it's the case */
return rc;
}
/**
* Initializes the USB device filter object (short version).
*
* @param aParent Handle of the parent object.
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* register with parent early, since uninit() will unconditionally
* unregister on failure */
mParent->i_addChild(this);
mInList = false;
mData->mMaskedIfs = 0;
/* Confirm successful initialization */
return S_OK;
}
/**
* Uninitializes the instance and sets the ready flag to FALSE.
* Called either from FinalRelease() or by the parent when it gets destroyed.
*/
{
LogFlowThisFunc(("\n"));
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
if (autoUninitSpan.uninitDone())
return;
mInList = false;
mParent->i_removeChild(this);
}
/**
* Most of the USB bits are protect by one lock to simplify things.
* This lock is currently the one of the Host object, which happens
* to be our parent.
*/
{
return mParent->lockHandle();
}
// IUSBDeviceFilter properties
////////////////////////////////////////////////////////////////////////////////
{
return S_OK;
}
{
{
/* leave the lock before informing callbacks */
return mParent->i_onUSBDeviceFilterChange (this);
}
return S_OK;
}
{
return S_OK;
}
{
{
/* leave the lock before informing callbacks */
}
return S_OK;
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
return S_OK;
}
{
tr("The remote state filter is not supported by IHostUSBDeviceFilter objects"));
}
{
return S_OK;
}
{
tr("The masked interfaces property is not applicable to IHostUSBDeviceFilter objects"));
}
// wrapped IHostUSBDeviceFilter properties
////////////////////////////////////////////////////////////////////////////////
{
{
default: *aAction = USBDeviceFilterAction_Null; break;
}
return S_OK;
}
{
switch (aAction)
{
return setError(E_INVALIDARG,
tr("Action value InvalidUSBDeviceFilterAction is not permitted"));
default:
return setError(E_INVALIDARG,
tr("Invalid action %d"),
aAction);
}
{
if (RT_FAILURE(vrc))
return setError(E_INVALIDARG,
tr("Unexpected error %Rrc"),
vrc);
/* leave the lock before informing callbacks */
return mParent->i_onUSBDeviceFilterChange (this);
}
return S_OK;
}
// IHostUSBDeviceFilter properties
////////////////////////////////////////////////////////////////////////////////
/**
* Generic USB filter field getter.
*
* @param aIdx The field index.
* @param aStr Where to store the value.
*
* @return COM status.
*/
{
return S_OK;
}
{
AutoCaller autoCaller(this);
}
/**
* Generic USB filter field setter.
*
* @param aIdx The field index.
* @param aStr The new value.
* @param aName The translated field name (for error messages).
*
* @return COM status.
*/
{
{
//mData.backup();
{
//mData.rollback();
}
/* leave the lock before informing callbacks */
return mParent->i_onUSBDeviceFilterChange(this);
}
return S_OK;
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */