You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4072 lines
88 KiB
4072 lines
88 KiB
/***************************************************************************
|
|
*
|
|
* Copyright (C) 2001-2002 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: spwrapper.cpp
|
|
*
|
|
* Content: DP8SIM main SP interface wrapper object class.
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ======== ======== =========
|
|
* 04/23/01 VanceO Created.
|
|
*
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "dp8simi.h"
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Dynamically loaded function prototypes
|
|
//=============================================================================
|
|
typedef HRESULT (WINAPI * PFN_DLLGETCLASSOBJECT)(REFCLSID, REFIID, LPVOID *);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::CDP8SimSP"
|
|
//=============================================================================
|
|
// CDP8SimSP constructor
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Initializes the new CDP8SimSP object.
|
|
//
|
|
// Arguments:
|
|
// GUID * pguidFakeSP - Pointer to guid of fake SP.
|
|
// GUID * pguidRealSP - Pointer to guid of real SP being wrapped.
|
|
//
|
|
// Returns: None (the object).
|
|
//=============================================================================
|
|
CDP8SimSP::CDP8SimSP(const GUID * const pguidFakeSP, const GUID * const pguidRealSP)
|
|
{
|
|
this->m_blList.Initialize();
|
|
|
|
|
|
this->m_Sig[0] = 'S';
|
|
this->m_Sig[1] = 'P';
|
|
this->m_Sig[2] = 'W';
|
|
this->m_Sig[3] = 'P';
|
|
|
|
this->m_lRefCount = 1; // someone must have a pointer to this object
|
|
this->m_dwFlags = 0;
|
|
CopyMemory(&this->m_guidFakeSP, pguidFakeSP, sizeof(GUID));
|
|
CopyMemory(&this->m_guidRealSP, pguidRealSP, sizeof(GUID));
|
|
this->m_pDP8SimCB = NULL;
|
|
this->m_pDP8SP = NULL;
|
|
this->m_dwSendsPending = 0;
|
|
this->m_hLastPendingSendEvent = NULL;
|
|
this->m_dwReceivesPending = 0;
|
|
//this->m_hLastPendingReceiveEvent = NULL;
|
|
} // CDP8SimSP::CDP8SimSP
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::~CDP8SimSP"
|
|
//=============================================================================
|
|
// CDP8SimSP destructor
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Frees the CDP8SimSP object.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
CDP8SimSP::~CDP8SimSP(void)
|
|
{
|
|
DNASSERT(this->m_blList.IsEmpty());
|
|
|
|
|
|
DNASSERT(this->m_lRefCount == 0);
|
|
DNASSERT(this->m_dwFlags == 0);
|
|
DNASSERT(this->m_pDP8SimCB == NULL);
|
|
DNASSERT(this->m_pDP8SP == NULL);
|
|
DNASSERT(this->m_dwSendsPending == 0);
|
|
DNASSERT(this->m_hLastPendingSendEvent == NULL);
|
|
DNASSERT(this->m_dwReceivesPending == 0);
|
|
//DNASSERT(this->m_hLastPendingReceiveEvent == NULL);
|
|
|
|
//
|
|
// For grins, change the signature before deleting the object.
|
|
//
|
|
this->m_Sig[3] = 'p';
|
|
} // CDP8SimSP::~CDP8SimSP
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::QueryInterface"
|
|
//=============================================================================
|
|
// CDP8SimSP::QueryInterface
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Retrieves a new reference for an interfaces supported by this
|
|
// CDP8SimSP object.
|
|
//
|
|
// Arguments:
|
|
// REFIID riid - Reference to interface ID GUID.
|
|
// LPVOID * ppvObj - Place to store pointer to object.
|
|
//
|
|
// Returns: HRESULT
|
|
// S_OK - Returning a valid interface pointer.
|
|
// DPNHERR_INVALIDOBJECT - The interface object is invalid.
|
|
// DPNHERR_INVALIDPOINTER - The destination pointer is invalid.
|
|
// E_NOINTERFACE - Invalid interface was specified.
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::QueryInterface(REFIID riid, LPVOID * ppvObj)
|
|
{
|
|
HRESULT hr = DPN_OK;
|
|
|
|
|
|
DPFX(DPFPREP, 3, "(0x%p) Parameters: (REFIID, 0x%p)", this, ppvObj);
|
|
|
|
|
|
//
|
|
// Validate the object.
|
|
//
|
|
if (! this->IsValidObject())
|
|
{
|
|
DPFX(DPFPREP, 0, "Invalid DP8Sim object!");
|
|
hr = DPNERR_INVALIDOBJECT;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Validate the parameters.
|
|
//
|
|
|
|
if ((! IsEqualIID(riid, IID_IUnknown)) &&
|
|
(! IsEqualIID(riid, IID_IDP8ServiceProvider)))
|
|
{
|
|
DPFX(DPFPREP, 0, "Unsupported interface!");
|
|
hr = E_NOINTERFACE;
|
|
goto Failure;
|
|
}
|
|
|
|
if ((ppvObj == NULL) ||
|
|
(IsBadWritePtr(ppvObj, sizeof(void*))))
|
|
{
|
|
DPFX(DPFPREP, 0, "Invalid interface pointer specified!");
|
|
hr = DPNERR_INVALIDPOINTER;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Add a reference, and return the interface pointer (which is actually
|
|
// just the object pointer, they line up because CDP8SimSP inherits from
|
|
// the interface declaration).
|
|
//
|
|
this->AddRef();
|
|
(*ppvObj) = this;
|
|
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 3, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::QueryInterface
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::AddRef"
|
|
//=============================================================================
|
|
// CDP8SimSP::AddRef
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Adds a reference to this CDP8SimSP object.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: New refcount.
|
|
//=============================================================================
|
|
STDMETHODIMP_(ULONG) CDP8SimSP::AddRef(void)
|
|
{
|
|
LONG lRefCount;
|
|
|
|
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// There must be at least 1 reference to this object, since someone is
|
|
// calling AddRef.
|
|
//
|
|
DNASSERT(this->m_lRefCount > 0);
|
|
|
|
lRefCount = InterlockedIncrement(&this->m_lRefCount);
|
|
|
|
DPFX(DPFPREP, 3, "[0x%p] RefCount [0x%lx]", this, lRefCount);
|
|
|
|
return lRefCount;
|
|
} // CDP8SimSP::AddRef
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Release"
|
|
//=============================================================================
|
|
// CDP8SimSP::Release
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Removes a reference to this CDP8SimSP object. When the
|
|
// refcount reaches 0, this object is destroyed.
|
|
// You must NULL out your pointer to this object after calling
|
|
// this function.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: New refcount.
|
|
//=============================================================================
|
|
STDMETHODIMP_(ULONG) CDP8SimSP::Release(void)
|
|
{
|
|
LONG lRefCount;
|
|
|
|
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
//
|
|
// There must be at least 1 reference to this object, since someone is
|
|
// calling Release.
|
|
//
|
|
DNASSERT(this->m_lRefCount > 0);
|
|
|
|
lRefCount = InterlockedDecrement(&this->m_lRefCount);
|
|
|
|
//
|
|
// Was that the last reference? If so, we're going to destroy this object.
|
|
//
|
|
if (lRefCount == 0)
|
|
{
|
|
DPFX(DPFPREP, 3, "[0x%p] RefCount hit 0, destroying object.", this);
|
|
|
|
//
|
|
// First pull it off the global list.
|
|
//
|
|
DNEnterCriticalSection(&g_csGlobalsLock);
|
|
|
|
this->m_blList.RemoveFromList();
|
|
|
|
DNASSERT(g_lOutstandingInterfaceCount > 0);
|
|
g_lOutstandingInterfaceCount--; // update count so DLL can unload now works correctly
|
|
|
|
DNLeaveCriticalSection(&g_csGlobalsLock);
|
|
|
|
|
|
//
|
|
// Make sure it's closed.
|
|
//
|
|
if (this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED)
|
|
{
|
|
//
|
|
// Assert so that the user can fix his/her broken code!
|
|
//
|
|
DNASSERT(! "DP8SimSP object being released without calling Close first!");
|
|
|
|
//
|
|
// Then go ahead and do the right thing. Ignore error, we can't do
|
|
// much about it.
|
|
//
|
|
this->Close();
|
|
}
|
|
|
|
|
|
//
|
|
// Then uninitialize the object.
|
|
//
|
|
this->UninitializeObject();
|
|
|
|
//
|
|
// Finally delete this (!) object.
|
|
//
|
|
delete this;
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 3, "[0x%p] RefCount [0x%lx]", this, lRefCount);
|
|
}
|
|
|
|
return lRefCount;
|
|
} // CDP8SimSP::Release
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Initialize"
|
|
//=============================================================================
|
|
// CDP8SimSP::Initialize
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPINITIALIZEDATA pspid - Pointer to parameter block to use when
|
|
// initializing.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Initialize(PSPINITIALIZEDATA pspid)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fHaveLock = FALSE;
|
|
BOOL fInitializedIPCObject = FALSE;
|
|
SPINITIALIZEDATA spidModified;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspid);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspid != NULL);
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
fHaveLock = TRUE;
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags == 0);
|
|
|
|
|
|
//
|
|
// Connect the shared memory.
|
|
//
|
|
hr = this->m_DP8SimIPC.Initialize();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't initialize IPC object!");
|
|
goto Failure;
|
|
}
|
|
|
|
fInitializedIPCObject = TRUE;
|
|
|
|
|
|
//
|
|
// Create a wrapper for the callback interface.
|
|
//
|
|
this->m_pDP8SimCB = new CDP8SimCB(this, pspid->pIDP);
|
|
if (this->m_pDP8SimCB == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
//
|
|
// Initialize the callback interface wrapper object.
|
|
//
|
|
hr = this->m_pDP8SimCB->InitializeObject();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't initialize callback interface wrapper object!");
|
|
|
|
delete this->m_pDP8SimCB;
|
|
this->m_pDP8SimCB = NULL;
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Instantiate the real SP.
|
|
//
|
|
hr = CoCreateInstance(this->m_guidRealSP,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IDP8ServiceProvider,
|
|
(PVOID*) (&this->m_pDP8SP));
|
|
if (hr != S_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't instantiate real SP object (pointer = 0x%p)!",
|
|
this->m_pDP8SP);
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 1, "Object 0x%p wrapping real SP 0x%p, inserting callback interface 0x%p before 0x%p.",
|
|
this, this->m_pDP8SP, this->m_pDP8SimCB, pspid->pIDP);
|
|
|
|
|
|
|
|
//
|
|
// Initialize the real SP.
|
|
//
|
|
|
|
ZeroMemory(&spidModified, sizeof(spidModified));
|
|
spidModified.pIDP = this->m_pDP8SimCB;
|
|
spidModified.dwFlags = pspid->dwFlags;
|
|
|
|
hr = this->m_pDP8SP->Initialize(&spidModified);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed initializing real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// We're now initialized.
|
|
//
|
|
this->m_dwFlags |= DP8SIMSPOBJ_INITIALIZED;
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (this->m_pDP8SP != NULL)
|
|
{
|
|
this->m_pDP8SP->Release();
|
|
this->m_pDP8SP = NULL;
|
|
}
|
|
|
|
if (this->m_pDP8SimCB != NULL)
|
|
{
|
|
this->m_pDP8SimCB->Release();
|
|
this->m_pDP8SimCB = NULL;
|
|
}
|
|
|
|
if (fInitializedIPCObject)
|
|
{
|
|
this->m_DP8SimIPC.Close();
|
|
fInitializedIPCObject = FALSE;
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::Initialize
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Close"
|
|
//=============================================================================
|
|
// CDP8SimSP::Close
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Close(void)
|
|
{
|
|
HRESULT hr;
|
|
//BOOL fHaveLock = FALSE;
|
|
BOOL fWait = FALSE;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Enter", this);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
//fHaveLock = TRUE;
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
|
|
|
|
//
|
|
// Figure out if we need to wait for all sends to complete.
|
|
//
|
|
if (this->m_dwSendsPending > 0)
|
|
{
|
|
DNASSERT(this->m_hLastPendingSendEvent == NULL);
|
|
|
|
this->m_hLastPendingSendEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (this->m_hLastPendingSendEvent == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "Couldn't create last send pending event (err = %u)!", hr);
|
|
}
|
|
else
|
|
{
|
|
fWait = TRUE;
|
|
}
|
|
}
|
|
|
|
this->m_dwFlags |= DP8SIMSPOBJ_CLOSING;
|
|
|
|
//
|
|
// Drop the lock, nobody should be touching this object now.
|
|
//
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
//fHaveLock = FALSE;
|
|
|
|
|
|
if (fWait)
|
|
{
|
|
DPFX(DPFPREP, 1, "Waiting for ~%u pending sends to complete.",
|
|
this->m_dwSendsPending);
|
|
|
|
|
|
//
|
|
// Wait for all the sends to complete. Nobody should touch
|
|
// m_hLastPendingSendEvent except the thread triggering it, so
|
|
// referring to it without the lock should be safe.
|
|
// Ignore any errors.
|
|
//
|
|
WaitForSingleObject(this->m_hLastPendingSendEvent, INFINITE);
|
|
|
|
|
|
//
|
|
// Take the lock while removing the handle, to be paranoid.
|
|
//
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
//
|
|
// Remove the handle.
|
|
//
|
|
CloseHandle(this->m_hLastPendingSendEvent);
|
|
this->m_hLastPendingSendEvent = NULL;
|
|
|
|
|
|
//
|
|
// Drop the lock again.
|
|
//
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
|
|
//
|
|
// Shutdown the global worker thread if we launched it.
|
|
//
|
|
if (this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD)
|
|
{
|
|
StopGlobalWorkerThread();
|
|
|
|
this->m_dwFlags &= ~DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD;
|
|
}
|
|
|
|
|
|
//
|
|
// Close the real SP.
|
|
//
|
|
hr = this->m_pDP8SP->Close();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed closing real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
//
|
|
// Release the real SP object.
|
|
//
|
|
this->m_pDP8SP->Release();
|
|
this->m_pDP8SP = NULL;
|
|
|
|
|
|
//
|
|
// Release the callback interceptor object.
|
|
//
|
|
this->m_pDP8SimCB->Release();
|
|
this->m_pDP8SimCB = NULL;
|
|
|
|
|
|
//
|
|
// Disconnect the shared memory.
|
|
//
|
|
this->m_DP8SimIPC.Close();
|
|
|
|
|
|
//
|
|
// Turn off the initialized and closing flags.
|
|
//
|
|
this->m_dwFlags &= ~(DP8SIMSPOBJ_INITIALIZED | DP8SIMSPOBJ_CLOSING);
|
|
DNASSERT(this->m_dwFlags == 0);
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
/*
|
|
Failure:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
goto Exit;
|
|
*/
|
|
} // CDP8SimSP::Close
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Connect"
|
|
//=============================================================================
|
|
// CDP8SimSP::Connect
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPCONNECTDATA pspcd - Pointer to parameter block to use when
|
|
// connecting.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Connect(PSPCONNECTDATA pspcd)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fHaveLock = FALSE;
|
|
SPCONNECTDATA spcdModified;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspcd);
|
|
|
|
|
|
ZeroMemory(&spcdModified, sizeof(spcdModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspcd != NULL);
|
|
DNASSERT(pspcd->pAddressHost != NULL);
|
|
DNASSERT(pspcd->pAddressDeviceInfo != NULL);
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
fHaveLock = TRUE;
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
//
|
|
// Fire up the global worker thread, if it hasn't been already.
|
|
//
|
|
if (! (this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD))
|
|
{
|
|
hr = StartGlobalWorkerThread();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting global worker thread!");
|
|
goto Failure;
|
|
}
|
|
|
|
this->m_dwFlags |= DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD;
|
|
}
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
fHaveLock = FALSE;
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_CONNECT;
|
|
CommandFPMContext.pvUserContext = pspcd->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspcd->pAddressHost->Duplicate(&spcdModified.pAddressHost);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate host address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
spcdModified.pAddressHost = pspcd->pAddressHost;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = spcdModified.pAddressHost->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change host address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspcd->pAddressDeviceInfo->Duplicate(&spcdModified.pAddressDeviceInfo);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate device info address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
spcdModified.pAddressDeviceInfo = pspcd->pAddressDeviceInfo;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = spcdModified.pAddressDeviceInfo->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change device info address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Add a reference for the connect command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
DNASSERT(pspcd->dwReserved == 0);
|
|
//spcdModified.dwReserved = pspcd->dwReserved;
|
|
spcdModified.dwFlags = pspcd->dwFlags;
|
|
spcdModified.pvContext = pDP8SimCommand;
|
|
//spcdModified.hCommand = pspcd->hCommand; // filled in by real SP
|
|
//spcdModified.dwCommandDescriptor = pspcd->dwCommandDescriptor; // filled in by real SP
|
|
|
|
|
|
|
|
//
|
|
// Start connecting with the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->Connect(&spcdModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting to connect with real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
#pragma BUGBUG(vanceo, "Handle DPN_OK and investigate command completing before this function returns")
|
|
DNASSERT(spcdModified.hCommand != NULL);
|
|
|
|
|
|
//
|
|
// Save the output parameters.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(spcdModified.hCommand,
|
|
spcdModified.dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Generate the output parameters for the caller.
|
|
//
|
|
pspcd->hCommand = (HANDLE) pDP8SimCommand;
|
|
pspcd->dwCommandDescriptor = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
if (pDP8SimCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
/*
|
|
if (spcdModified.pAddressDeviceInfo != NULL)
|
|
{
|
|
spcdModified.pAddressDeviceInfo->Release();
|
|
spcdModified.pAddressDeviceInfo = NULL;
|
|
}
|
|
|
|
if (spcdModified.pAddressHost != NULL)
|
|
{
|
|
spcdModified.pAddressHost->Release();
|
|
spcdModified.pAddressHost = NULL;
|
|
}
|
|
*/
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::Connect
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Disconnect"
|
|
//=============================================================================
|
|
// CDP8SimSP::Disconnect
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPDISCONNECTDATA pspdd - Pointer to parameter block to use when
|
|
// disconnecting.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Disconnect(PSPDISCONNECTDATA pspdd)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fHaveLock = FALSE;
|
|
CDP8SimEndpoint * pDP8SimEndpoint;
|
|
SPDISCONNECTDATA spddModified;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspdd);
|
|
|
|
|
|
ZeroMemory(&spddModified, sizeof(spddModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspdd != NULL);
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
fHaveLock = TRUE;
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
fHaveLock = FALSE;
|
|
|
|
|
|
pDP8SimEndpoint = (CDP8SimEndpoint*) pspdd->hEndpoint;
|
|
DNASSERT(pDP8SimEndpoint->IsValidObject());
|
|
|
|
//
|
|
// Mark the endpoint as disconnecting to prevent additional sends/receives.
|
|
//
|
|
pDP8SimEndpoint->Lock();
|
|
pDP8SimEndpoint->NoteDisconnecting();
|
|
pDP8SimEndpoint->Unlock();
|
|
|
|
|
|
//
|
|
// Flush any delayed sends that were already going to this endpoint to make
|
|
// sure they hit the wire.
|
|
//
|
|
FlushAllDelayedSendsToEndpoint(pDP8SimEndpoint, FALSE);
|
|
|
|
|
|
//
|
|
// Drop any delayed receives from this endpoint, the upper layer doesn't
|
|
// want to receive anything else after disconnecting.
|
|
//
|
|
FlushAllDelayedReceivesFromEndpoint(pDP8SimEndpoint, TRUE);
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_DISCONNECT;
|
|
CommandFPMContext.pvUserContext = pspdd->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
|
|
//
|
|
// Add a reference for the disconnect command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
spddModified.hEndpoint = pDP8SimEndpoint->GetRealSPEndpoint();
|
|
spddModified.dwFlags = pspdd->dwFlags;
|
|
spddModified.pvContext = pDP8SimCommand;
|
|
//spddModified.hCommand = pspdd->hCommand; // filled in by real SP
|
|
//spddModified.dwCommandDescriptor = pspdd->dwCommandDescriptor; // filled in by real SP
|
|
|
|
|
|
|
|
//
|
|
// Tell the real service provider to disconnect.
|
|
//
|
|
hr = this->m_pDP8SP->Disconnect(&spddModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed having real SP object (0x%p) disconnect!",
|
|
this->m_pDP8SP);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
if (hr == DPNSUCCESS_PENDING)
|
|
{
|
|
DNASSERT(spddModified.hCommand != NULL);
|
|
|
|
|
|
//
|
|
// Save the output parameters.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(spddModified.hCommand,
|
|
spddModified.dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Generate the output parameters for the caller.
|
|
//
|
|
pspdd->hCommand = (HANDLE) pDP8SimCommand;
|
|
pspdd->dwCommandDescriptor = 0;
|
|
}
|
|
else
|
|
{
|
|
DNASSERT(spddModified.hCommand == NULL);
|
|
|
|
DPFX(DPFPREP, 7, "Releasing completed command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
if (pDP8SimCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::Disconnect
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Listen"
|
|
//=============================================================================
|
|
// CDP8SimSP::Listen
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPLISTENDATA pspld - Pointer to parameter block to use when listening.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Listen(PSPLISTENDATA pspld)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fHaveLock = FALSE;
|
|
SPLISTENDATA spldModified;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspld);
|
|
|
|
|
|
ZeroMemory(&spldModified, sizeof(spldModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspld != NULL);
|
|
DNASSERT(pspld->pAddressDeviceInfo != NULL);
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
fHaveLock = TRUE;
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
//
|
|
// Fire up the global worker thread, if it hasn't been already.
|
|
//
|
|
if (! (this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD))
|
|
{
|
|
hr = StartGlobalWorkerThread();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting global worker thread!");
|
|
goto Failure;
|
|
}
|
|
|
|
this->m_dwFlags |= DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD;
|
|
}
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
fHaveLock = FALSE;
|
|
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_LISTEN;
|
|
CommandFPMContext.pvUserContext = pspld->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspld->pAddressDeviceInfo->Duplicate(&spldModified.pAddressDeviceInfo);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate device info address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
spldModified.pAddressDeviceInfo = pspld->pAddressDeviceInfo;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = spldModified.pAddressDeviceInfo->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change device info address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Add a reference for the listen command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
|
|
spldModified.dwFlags = pspld->dwFlags;
|
|
spldModified.pvContext = pDP8SimCommand;
|
|
//spldModified.hCommand = pspld->hCommand; // filled in by real SP
|
|
//spldModified.dwCommandDescriptor = pspld->dwCommandDescriptor; // filled in by real SP
|
|
|
|
|
|
|
|
//
|
|
// Start listening with the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->Listen(&spldModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed to start listening with the real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
DNASSERT(spldModified.hCommand != NULL);
|
|
|
|
|
|
//
|
|
// Save the output parameters.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(spldModified.hCommand,
|
|
spldModified.dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Generate the output parameters for the caller.
|
|
//
|
|
pspld->hCommand = (HANDLE) pDP8SimCommand;
|
|
pspld->dwCommandDescriptor = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
if (pDP8SimCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
/*
|
|
if (spldModified.pAddressDeviceInfo != NULL)
|
|
{
|
|
spldModified.pAddressDeviceInfo->Release();
|
|
spldModified.pAddressDeviceInfo = NULL;
|
|
}
|
|
*/
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::Listen
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::SendData"
|
|
//=============================================================================
|
|
// CDP8SimSP::SendData
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPSENDDATA pspsd - Pointer to parameter block to use when sending.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::SendData(PSPSENDDATA pspsd)
|
|
{
|
|
HRESULT hr;
|
|
DP8SIM_PARAMETERS dp8sp;
|
|
CDP8SimEndpoint * pDP8SimEndpoint;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
SPSENDDATA spsdModified;
|
|
CDP8SimSend * pDP8SimSend = NULL;
|
|
IDP8SPCallback * pDP8SPCB;
|
|
DWORD dwMsgSize;
|
|
DWORD dwTemp;
|
|
DWORD dwBandwidthDelay;
|
|
DWORD dwLatencyDelay;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspsd);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspsd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Determine the total size of the message.
|
|
//
|
|
dwMsgSize = 0;
|
|
for(dwTemp = 0; dwTemp < pspsd->dwBufferCount; dwTemp++)
|
|
{
|
|
DNASSERT((pspsd->pBuffers[dwTemp].pBufferData != NULL) && (pspsd->pBuffers[dwTemp].dwBufferSize > 0));
|
|
dwMsgSize += pspsd->pBuffers[dwTemp].dwBufferSize;
|
|
}
|
|
|
|
|
|
//
|
|
// Get the current send settings.
|
|
//
|
|
ZeroMemory(&dp8sp, sizeof(dp8sp));
|
|
dp8sp.dwSize = sizeof(dp8sp);
|
|
this->m_DP8SimIPC.GetAllSendParameters(&dp8sp);
|
|
|
|
|
|
//
|
|
// Determine if we need to drop this send.
|
|
//
|
|
if (this->ShouldDrop(dp8sp.fPacketLossPercent))
|
|
{
|
|
//
|
|
// Update the statistics.
|
|
//
|
|
this->IncrementStatsSendDropped(dwMsgSize);
|
|
|
|
|
|
//
|
|
// Indicate send completion (with a bogus handle) immediately.
|
|
//
|
|
|
|
pDP8SPCB = this->m_pDP8SimCB->GetRealCallbackInterface();
|
|
|
|
DPFX(DPFPREP, 2, "Indicating successful send completion (dropped, context = 0x%p) to interface 0x%p.",
|
|
pspsd->pvContext, pDP8SPCB);
|
|
|
|
hr = pDP8SPCB->CommandComplete(NULL, DPN_OK, pspsd->pvContext);
|
|
|
|
DPFX(DPFPREP, 2, "Returning from command complete [0x%lx].", hr);
|
|
|
|
|
|
//
|
|
// Ignore any error and return DPNSUCCESS_PENDING, even though we've
|
|
// completed the send already.
|
|
//
|
|
hr = DPNSUCCESS_PENDING;
|
|
|
|
|
|
//
|
|
// Return bogus output parameters for the caller, it's already complete
|
|
// from their perspective.
|
|
//
|
|
pspsd->hCommand = NULL;
|
|
pspsd->dwCommandDescriptor = 0;
|
|
|
|
|
|
//
|
|
// We're done here.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Figure out how much latency needs to be added based on the bandwidth
|
|
// and random latency settings.
|
|
//
|
|
// If we're not supposed to delay the sends, fire it off right away.
|
|
// Otherwise submit a timed job to be performed later.
|
|
//
|
|
if (! this->GetDelay(dp8sp.dwBandwidthBPS,
|
|
dp8sp.dwPacketHeaderSize,
|
|
dwMsgSize,
|
|
dp8sp.dwMinLatencyMS,
|
|
dp8sp.dwMaxLatencyMS,
|
|
&dwBandwidthDelay,
|
|
&dwLatencyDelay))
|
|
{
|
|
pDP8SimEndpoint = (CDP8SimEndpoint*) pspsd->hEndpoint;
|
|
DNASSERT(pDP8SimEndpoint->IsValidObject());
|
|
|
|
|
|
//
|
|
// If the endpoint is disconnecting, don't try to send.
|
|
//
|
|
pDP8SimEndpoint->Lock();
|
|
if (pDP8SimEndpoint->IsDisconnecting())
|
|
{
|
|
pDP8SimEndpoint->Unlock();
|
|
|
|
DPFX(DPFPREP, 0, "Endpoint 0x%p is disconnecting, can't send!",
|
|
pDP8SimEndpoint);
|
|
|
|
hr = DPNERR_NOCONNECTION;
|
|
goto Failure;
|
|
}
|
|
pDP8SimEndpoint->Unlock();
|
|
|
|
|
|
|
|
DPFX(DPFPREP, 6, "Sending %u bytes of data immmediately.", dwMsgSize);
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_SENDDATA_IMMEDIATE;
|
|
CommandFPMContext.pvUserContext = pspsd->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
//
|
|
// Save the message's size for incrementing stats at send completion.
|
|
//
|
|
pDP8SimCommand->SetMessageSize(dwMsgSize);
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
ZeroMemory(&spsdModified, sizeof(spsdModified));
|
|
spsdModified.hEndpoint = pDP8SimEndpoint->GetRealSPEndpoint();
|
|
spsdModified.pBuffers = pspsd->pBuffers;
|
|
spsdModified.dwBufferCount = pspsd->dwBufferCount;
|
|
spsdModified.dwFlags = pspsd->dwFlags;
|
|
spsdModified.pvContext = pDP8SimCommand;
|
|
//spsdModified.hCommand = NULL; // filled in by real SP
|
|
//spsdModified.dwCommandDescriptor = 0; // filled in by real SP
|
|
|
|
|
|
//
|
|
// Add a reference for the send command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
|
|
//
|
|
// Increase the pending sends counter.
|
|
//
|
|
this->IncSendsPending();
|
|
|
|
|
|
|
|
//
|
|
// Issue the send to the real SP.
|
|
//
|
|
hr = this->m_pDP8SP->SendData(&spsdModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed sending immediate data (err = 0x%lx)!", hr);
|
|
|
|
|
|
//
|
|
// Remove the send counter.
|
|
//
|
|
this->DecSendsPending();
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
|
|
//
|
|
// Continue.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
if (hr != DPNSUCCESS_PENDING)
|
|
{
|
|
//
|
|
// The command completed right away.
|
|
//
|
|
DNASSERT(hr == DPN_OK);
|
|
|
|
hr = this->m_pDP8SimCB->CommandComplete(spsdModified.hCommand,
|
|
hr,
|
|
pDP8SimCommand);
|
|
DNASSERT(hr == DPN_OK);
|
|
|
|
//
|
|
// Be sure to still return pending for the caller even though
|
|
// we just completed it to him.
|
|
//
|
|
hr = DPNSUCCESS_PENDING;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save the output parameters returned by the SP.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(spsdModified.hCommand,
|
|
spsdModified.dwCommandDescriptor);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
|
|
|
|
//
|
|
// We're done here.
|
|
//
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// If we're here, we must be delaying the send.
|
|
//
|
|
|
|
DPFX(DPFPREP, 6, "Delaying %u byte send for %u + %u ms.",
|
|
dwMsgSize, dwBandwidthDelay, dwLatencyDelay);
|
|
|
|
|
|
//
|
|
// Get a send object, duplicating the send data given to us by our caller
|
|
// for submission some time in the future.
|
|
//
|
|
pDP8SimSend = (CDP8SimSend*)g_FPOOLSend.Get(pspsd);
|
|
if (pDP8SimSend == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New send 0x%p.", pDP8SimSend);
|
|
|
|
|
|
//
|
|
// Store the latency that is about be added to this send.
|
|
//
|
|
pDP8SimSend->SetLatencyAdded(dwBandwidthDelay + dwLatencyDelay);
|
|
|
|
|
|
//
|
|
// Transfer local pDP8SimSend reference to the job queue.
|
|
//
|
|
|
|
|
|
//
|
|
// Increment the send counter.
|
|
//
|
|
this->IncSendsPending();
|
|
|
|
|
|
//
|
|
// Queue it to be sent at a later time, depending on the latency value
|
|
// requested. If there's a bandwidth restriction, enforce the sending
|
|
// order as well so that earlier sends that are still ongoing hold up later
|
|
// ones.
|
|
//
|
|
hr = AddWorkerJob(DP8SIMJOBTYPE_DELAYEDSEND,
|
|
pDP8SimSend,
|
|
this,
|
|
dwBandwidthDelay,
|
|
dwLatencyDelay,
|
|
DP8SIMJOBFLAG_PERFORMBLOCKINGPHASEFIRST);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't add delayed send worker job (0x%p)!",
|
|
pDP8SimSend);
|
|
|
|
|
|
//
|
|
// Remove the send counter.
|
|
//
|
|
this->DecSendsPending();
|
|
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Indicate send completion (with a bogus handle) immediately.
|
|
//
|
|
|
|
pDP8SPCB = this->m_pDP8SimCB->GetRealCallbackInterface();
|
|
|
|
DPFX(DPFPREP, 2, "Indicating successful send completion (delayed, context = 0x%p) to interface 0x%p.",
|
|
pspsd->pvContext, pDP8SPCB);
|
|
|
|
hr = pDP8SPCB->CommandComplete(NULL, DPN_OK, pspsd->pvContext);
|
|
|
|
DPFX(DPFPREP, 2, "Returning from command complete [0x%lx].", hr);
|
|
|
|
|
|
//
|
|
// Ignore any error and return DPNSUCCESS_PENDING, even though we've
|
|
// completed the send already.
|
|
//
|
|
hr = DPNSUCCESS_PENDING;
|
|
|
|
|
|
//
|
|
// Return bogus output parameters for the caller, it's already complete
|
|
// from their perspective.
|
|
//
|
|
pspsd->hCommand = NULL;
|
|
pspsd->dwCommandDescriptor = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (pDP8SimSend != NULL)
|
|
{
|
|
pDP8SimSend->Release();
|
|
pDP8SimSend = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::SendData
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::EnumQuery"
|
|
//=============================================================================
|
|
// CDP8SimSP::EnumQuery
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPENUMQUERYDATA pspeqd - Pointer to parameter block to use when
|
|
// enumerating.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::EnumQuery(PSPENUMQUERYDATA pspeqd)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fHaveLock = FALSE;
|
|
SPENUMQUERYDATA speqdModified;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspeqd);
|
|
|
|
|
|
ZeroMemory(&speqdModified, sizeof(speqdModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspeqd != NULL);
|
|
DNASSERT(pspeqd->pAddressHost != NULL);
|
|
DNASSERT(pspeqd->pAddressDeviceInfo != NULL);
|
|
|
|
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
fHaveLock = TRUE;
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
//
|
|
// Fire up the global worker thread, if it hasn't been already.
|
|
//
|
|
if (! (this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD))
|
|
{
|
|
hr = StartGlobalWorkerThread();
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting global worker thread!");
|
|
goto Failure;
|
|
}
|
|
|
|
this->m_dwFlags |= DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD;
|
|
}
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
fHaveLock = FALSE;
|
|
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_ENUMQUERY;
|
|
CommandFPMContext.pvUserContext = pspeqd->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspeqd->pAddressHost->Duplicate(&speqdModified.pAddressHost);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate host address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
speqdModified.pAddressHost = pspeqd->pAddressHost;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = speqdModified.pAddressHost->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change host address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspeqd->pAddressDeviceInfo->Duplicate(&speqdModified.pAddressDeviceInfo);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate device info address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
speqdModified.pAddressDeviceInfo = pspeqd->pAddressDeviceInfo;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = speqdModified.pAddressDeviceInfo->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change device info address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Add a reference for the enum query command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
|
|
speqdModified.pBuffers = pspeqd->pBuffers;
|
|
speqdModified.dwBufferCount = pspeqd->dwBufferCount;
|
|
speqdModified.dwTimeout = pspeqd->dwTimeout;
|
|
speqdModified.dwRetryCount = pspeqd->dwRetryCount;
|
|
speqdModified.dwRetryInterval = pspeqd->dwRetryInterval;
|
|
speqdModified.dwFlags = pspeqd->dwFlags;
|
|
speqdModified.pvContext = pDP8SimCommand;
|
|
//speqdModified.hCommand = pspeqd->hCommand; // filled in by real SP
|
|
//speqdModified.dwCommandDescriptor = pspeqd->dwCommandDescriptor; // filled in by real SP
|
|
|
|
|
|
//
|
|
// Start the enumeration via the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->EnumQuery(&speqdModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed starting the enumeration via the real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
DNASSERT(speqdModified.hCommand != NULL);
|
|
|
|
|
|
//
|
|
// Save the output parameters.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(speqdModified.hCommand,
|
|
speqdModified.dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Generate the output parameters for the caller.
|
|
//
|
|
pspeqd->hCommand = (HANDLE) pDP8SimCommand;
|
|
pspeqd->dwCommandDescriptor = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
if (pDP8SimCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
/*
|
|
if (speqdModified.pAddressDeviceInfo != NULL)
|
|
{
|
|
speqdModified.pAddressDeviceInfo->Release();
|
|
speqdModified.pAddressDeviceInfo = NULL;
|
|
}
|
|
|
|
if (speqdModified.pAddressHost != NULL)
|
|
{
|
|
speqdModified.pAddressHost->Release();
|
|
speqdModified.pAddressHost = NULL;
|
|
}
|
|
*/
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (fHaveLock)
|
|
{
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::EnumQuery
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::EnumRespond"
|
|
//=============================================================================
|
|
// CDP8SimSP::EnumRespond
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPENUMRESPONDDATA psperd - Pointer to parameter block to use when
|
|
// responding.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::EnumRespond(PSPENUMRESPONDDATA psperd)
|
|
{
|
|
HRESULT hr;
|
|
SPENUMRESPONDDATA sperdModified;
|
|
ENUMQUERYDATAWRAPPER * pEnumQueryDataWrapper;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, psperd);
|
|
|
|
|
|
ZeroMemory(&sperdModified, sizeof(sperdModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(psperd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_ENUMRESPOND;
|
|
CommandFPMContext.pvUserContext = psperd->pvContext;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
hr = DPNERR_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
//
|
|
// We wrapped the enum query data structure, get the original object.
|
|
//
|
|
pEnumQueryDataWrapper = ENUMQUERYEVENTWRAPPER_FROM_SPIEQUERY(psperd->pQuery);
|
|
|
|
DNASSERT(*((DWORD*) (&pEnumQueryDataWrapper->m_Sig)) == 0x57455145); // 0x57 0x45 0x51 0x45 = 'WEQE' = 'EQEW' in Intel order
|
|
|
|
sperdModified.pQuery = pEnumQueryDataWrapper->pOriginalQuery;
|
|
|
|
|
|
//
|
|
// Add a reference for the enum respond command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
|
|
sperdModified.pBuffers = psperd->pBuffers;
|
|
sperdModified.dwBufferCount = psperd->dwBufferCount;
|
|
sperdModified.dwFlags = psperd->dwFlags;
|
|
sperdModified.pvContext = pDP8SimCommand;
|
|
//sperdModified.hCommand = psperd->hCommand; // filled in by real SP
|
|
//sperdModified.dwCommandDescriptor = psperd->dwCommandDescriptor; // filled in by real SP
|
|
|
|
|
|
//
|
|
// Respond to the enumeration via the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->EnumRespond(&sperdModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed responding to enumeration via the real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Save the output parameters.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(sperdModified.hCommand,
|
|
sperdModified.dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Generate the output parameters for the caller.
|
|
//
|
|
psperd->hCommand = (HANDLE) pDP8SimCommand;
|
|
psperd->dwCommandDescriptor = 0;
|
|
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
if (pDP8SimCommand != NULL)
|
|
{
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::EnumRespond
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::CancelCommand"
|
|
//=============================================================================
|
|
// CDP8SimSP::CancelCommand
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// HANDLE hCommand - Handle to command to cancel.
|
|
// DWORD dwCommandDescriptor - Unique descriptor of command to cancel.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::CancelCommand(HANDLE hCommand, DWORD dwCommandDescriptor)
|
|
{
|
|
HRESULT hr;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p, %u)",
|
|
this, hCommand, dwCommandDescriptor);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(hCommand != NULL);
|
|
DNASSERT(dwCommandDescriptor == 0);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*) hCommand;
|
|
DNASSERT(pDP8SimCommand->IsValidObject());
|
|
|
|
|
|
//
|
|
// Cancel the real service provider's command.
|
|
//
|
|
hr = this->m_pDP8SP->CancelCommand(pDP8SimCommand->GetRealSPCommand(),
|
|
pDP8SimCommand->GetRealSPCommandDescriptor());
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed cancelling real SP object (0x%p)'s command!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::CancelCommand
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::EnumMulticastScopes"
|
|
//=============================================================================
|
|
// CDP8SimSP::EnumMulticastScopes
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPENUMMULTICASTSCOPESDATA pspemsd - Pointer to parameter block to use
|
|
// when enumerating scopes.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::EnumMulticastScopes(PSPENUMMULTICASTSCOPESDATA pspemsd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspemsd);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspemsd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Have the real service provider enumerate multicast scopes.
|
|
//
|
|
hr = this->m_pDP8SP->EnumMulticastScopes(pspemsd);
|
|
if (hr != DPN_OK)
|
|
{
|
|
if (hr != DPNERR_BUFFERTOOSMALL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed enumerating multicast scopes on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
}
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::EnumMulticastScopes
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::ShareEndpointInfo"
|
|
//=============================================================================
|
|
// CDP8SimSP::ShareEndpointInfo
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPSHAREENDPOINTINFODATA pspseid - Pointer to parameter block.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::ShareEndpointInfo(PSPSHAREENDPOINTINFODATA pspseid)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspseid);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspseid != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Have the real service provider share the endpoint info.
|
|
//
|
|
hr = this->m_pDP8SP->ShareEndpointInfo(pspseid);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed sharing endpoint info on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::ShareEndpointInfo
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::GetEndpointByAddress"
|
|
//=============================================================================
|
|
// CDP8SimSP::GetEndpointByAddress
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPGETENDPOINTBYADDRESSDATA pspgebad - Pointer to parameter block.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::GetEndpointByAddress(PSPGETENDPOINTBYADDRESSDATA pspgebad)
|
|
{
|
|
HRESULT hr;
|
|
#ifndef DPNBUILD_NOMULTICAST
|
|
SPGETENDPOINTBYADDRESSDATA spgebadModified;
|
|
|
|
|
|
ZeroMemory(&spgebadModified, sizeof(spgebadModified));
|
|
#endif // ! DPNBUILD_NOMULTICAST
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspgebad);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspgebad != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
#ifdef DPNBUILD_NOMULTICAST
|
|
hr = DPNERR_UNSUPPORTED;
|
|
goto Failure;
|
|
#else // ! DPNBUILD_NOMULTICAST
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspgebad->pAddressHost->Duplicate(&spgebadModified.pAddressHost);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate host address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
spgebadModified.pAddressHost = pspgebad->pAddressHost;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = spgebadModified.pAddressHost->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change host address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = pspgebad->pAddressDeviceInfo->Duplicate(&spgebadModified.pAddressDeviceInfo);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate device info address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
spgebadModified.pAddressDeviceInfo = pspgebad->pAddressDeviceInfo;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = spgebadModified.pAddressDeviceInfo->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change device info address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve the real service provider's endpoint.
|
|
//
|
|
hr = this->m_pDP8SP->GetEndpointByAddress(&spgebadModified);
|
|
if (hr == DPN_OK)
|
|
{
|
|
CDP8SimEndpoint * pDP8SimEndpoint;
|
|
|
|
|
|
//
|
|
// Convert our user context into the real user's context, and
|
|
// return the endpoint handle that our user should see.
|
|
//
|
|
pDP8SimEndpoint = (CDP8SimEndpoint*) spgebadModified.pvEndpointContext;
|
|
pspgebad->hEndpoint = pDP8SimEndpoint;
|
|
pspgebad->pvEndpointContext = pDP8SimEndpoint->GetUserContext();
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed getting endpoint by address on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
#endif // ! DPNBUILD_NOMULTICAST
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
/*
|
|
#ifndef DPNBUILD_NOMULTICAST
|
|
if (spgebadModified.pAddressDeviceInfo != NULL)
|
|
{
|
|
spgebadModified.pAddressDeviceInfo->Release();
|
|
spgebadModified.pAddressDeviceInfo = NULL;
|
|
}
|
|
|
|
if (spgebadModified.pAddressHost != NULL)
|
|
{
|
|
spgebadModified.pAddressHost->Release();
|
|
spgebadModified.pAddressHost = NULL;
|
|
}
|
|
#endif // ! DPNBUILD_NOMULTICAST
|
|
*/
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::GetEndpointByAddress
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::Update"
|
|
//=============================================================================
|
|
// CDP8SimSP::Update
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPUNUSEDDATA pspud - Pointer to parameter block.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::Update(PSPUPDATEDATA pspud)
|
|
{
|
|
HRESULT hr;
|
|
SPUPDATEDATA spudModified;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspud);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspud != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Update the real service provider's as appropriate.
|
|
//
|
|
spudModified.UpdateType = pspud->UpdateType;
|
|
switch (spudModified.UpdateType)
|
|
{
|
|
case SP_UPDATE_HOST_MIGRATE:
|
|
case SP_UPDATE_ALLOW_ENUMS:
|
|
case SP_UPDATE_DISALLOW_ENUMS:
|
|
{
|
|
CDP8SimEndpoint * pDP8SimEndpoint;
|
|
|
|
|
|
//
|
|
// Convert our endpoint into the real SP's endpoint.
|
|
//
|
|
pDP8SimEndpoint = (CDP8SimEndpoint*) pspud->hEndpoint;
|
|
spudModified.hEndpoint = pDP8SimEndpoint->GetRealSPEndpoint();
|
|
|
|
hr = this->m_pDP8SP->Update(&spudModified);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed updating real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DPFX(DPFPREP, 0, "Unrecognized update type %u!", spudModified.UpdateType);
|
|
DNASSERT(! "Unrecognized update type!");
|
|
hr = DPNERR_UNSUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::Update
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::GetCaps"
|
|
//=============================================================================
|
|
// CDP8SimSP::GetCaps
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPGETCAPSDATA pspgcd - Pointer to parameter block to use when retrieving
|
|
// the capabilities.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::GetCaps(PSPGETCAPSDATA pspgcd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspgcd);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspgcd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Retrieve the capabilities of the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->GetCaps(pspgcd);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed getting caps on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Add in the network simulator flag.
|
|
//
|
|
pspgcd->dwFlags |= DPNSPCAPS_NETWORKSIMULATOR;
|
|
}
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::GetCaps
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::SetCaps"
|
|
//=============================================================================
|
|
// CDP8SimSP::SetCaps
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPSETCAPSDATA pspscd - Pointer to parameter block to use when setting
|
|
// the capabilities.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::SetCaps(PSPSETCAPSDATA pspscd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspscd);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspscd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Store the capabilities of the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->SetCaps(pspscd);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed setting caps on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::SetCaps
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::ReturnReceiveBuffers"
|
|
//=============================================================================
|
|
// CDP8SimSP::ReturnReceiveBuffers
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPRECEIVEDBUFFER psprb - Array of receive buffers to return.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::ReturnReceiveBuffers(PSPRECEIVEDBUFFER psprb)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, psprb);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(psprb != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Return the receive buffers to the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->ReturnReceiveBuffers(psprb);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed returning receive buffers to real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::ReturnReceiveBuffers
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::GetAddressInfo"
|
|
//=============================================================================
|
|
// CDP8SimSP::GetAddressInfo
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPGETADDRESSINFODATA pspgaid - Pointer to parameter block to use when
|
|
// getting address info.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::GetAddressInfo(PSPGETADDRESSINFODATA pspgaid)
|
|
{
|
|
HRESULT hr;
|
|
CDP8SimEndpoint * pDP8SimEndpoint;
|
|
SPGETADDRESSINFODATA spgaidModified;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspgaid);
|
|
|
|
|
|
ZeroMemory(&spgaidModified, sizeof(spgaidModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspgaid != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
pDP8SimEndpoint = (CDP8SimEndpoint*) pspgaid->hEndpoint;
|
|
DNASSERT(pDP8SimEndpoint->IsValidObject());
|
|
|
|
|
|
|
|
//
|
|
// Initialize return value to NULL.
|
|
//
|
|
pspgaid->pAddress = NULL;
|
|
|
|
|
|
//
|
|
// If the endpoint is disconnecting, don't try to get the address info.
|
|
//
|
|
pDP8SimEndpoint->Lock();
|
|
if (pDP8SimEndpoint->IsDisconnecting())
|
|
{
|
|
pDP8SimEndpoint->Unlock();
|
|
|
|
DPFX(DPFPREP, 0, "Endpoint 0x%p is disconnecting, can't get address info!",
|
|
pDP8SimEndpoint);
|
|
|
|
hr = DPNERR_NOCONNECTION;
|
|
goto Failure;
|
|
}
|
|
pDP8SimEndpoint->Unlock();
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
spgaidModified.hEndpoint = pDP8SimEndpoint->GetRealSPEndpoint();
|
|
spgaidModified.pAddress = NULL; // filled in by real SP
|
|
spgaidModified.Flags = pspgaid->Flags;
|
|
|
|
|
|
|
|
//
|
|
// Get real service provider address info.
|
|
//
|
|
hr = this->m_pDP8SP->GetAddressInfo(&spgaidModified);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed getting real SP object (0x%p) address info!",
|
|
this->m_pDP8SP);
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Modify the address so that the SP uses our GUID, if there was an address
|
|
// returned.
|
|
//
|
|
if (spgaidModified.pAddress != NULL)
|
|
{
|
|
hr = spgaidModified.pAddress->SetSP(&this->m_guidFakeSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change address' SP!");
|
|
goto Failure;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Return the modified address to the user.
|
|
//
|
|
pspgaid->pAddress = spgaidModified.pAddress;
|
|
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
if (spgaidModified.pAddress != NULL)
|
|
{
|
|
spgaidModified.pAddress->Release();
|
|
spgaidModified.pAddress = NULL;
|
|
}
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::GetAddressInfo
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::IsApplicationSupported"
|
|
//=============================================================================
|
|
// CDP8SimSP::IsApplicationSupported
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPISAPPLICATIONSUPPORTEDDATA pspiasd - Pointer to parameter block to use
|
|
// when checking application
|
|
// support.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::IsApplicationSupported(PSPISAPPLICATIONSUPPORTEDDATA pspiasd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspiasd);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspiasd != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Check availability with the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->IsApplicationSupported(pspiasd);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed checking if application is supported by real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
//Exit:
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
//Failure:
|
|
|
|
// goto Exit;
|
|
} // CDP8SimSP::IsApplicationSupported
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::EnumAdapters"
|
|
//=============================================================================
|
|
// CDP8SimSP::EnumAdapters
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPENUMADAPTERSDATA pspead - Pointer to parameter block to use when
|
|
// enumerating the adapters.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::EnumAdapters(PSPENUMADAPTERSDATA pspead)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwTemp;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, pspead);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pspead != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
//
|
|
// Enumerate the adapters available to the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->EnumAdapters(pspead);
|
|
if (hr == DPN_OK)
|
|
{
|
|
//
|
|
// Set the NETWORKSIMULATORDEVICE flag for all of the adapters.
|
|
//
|
|
for(dwTemp = 0; dwTemp < pspead->dwAdapterCount; dwTemp++)
|
|
{
|
|
pspead->pAdapterData[dwTemp].dwFlags |= DPNSPINFO_NETWORKSIMULATORDEVICE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hr != DPNERR_BUFFERTOOSMALL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed enumerating adapters on real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
}
|
|
|
|
//
|
|
// Continue...
|
|
//
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
} // CDP8SimSP::EnumAdapters
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::ProxyEnumQuery"
|
|
//=============================================================================
|
|
// CDP8SimSP::ProxyEnumQuery
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: ?
|
|
//
|
|
// Arguments:
|
|
// PSPPROXYENUMQUERYDATA psppeqd - Pointer to parameter block to use when
|
|
// proxying the enum query.
|
|
//
|
|
// Returns: HRESULT
|
|
//=============================================================================
|
|
STDMETHODIMP CDP8SimSP::ProxyEnumQuery(PSPPROXYENUMQUERYDATA psppeqd)
|
|
{
|
|
HRESULT hr;
|
|
SPPROXYENUMQUERYDATA sppeqdModified;
|
|
ENUMQUERYDATAWRAPPER * pEnumQueryDataWrapper;
|
|
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Parameters: (0x%p)", this, psppeqd);
|
|
|
|
|
|
ZeroMemory(&sppeqdModified, sizeof(sppeqdModified));
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(psppeqd != NULL);
|
|
DNASSERT(psppeqd->pDestinationAdapter != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
DNASSERT(! (this->m_dwFlags & DP8SIMSPOBJ_CLOSING));
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
//
|
|
// Copy the parameter block, modifying as necessary.
|
|
//
|
|
|
|
/*
|
|
//
|
|
// Duplicate the host address.
|
|
//
|
|
hr = psppeqd->pDestinationAdapter->Duplicate(&sppeqdModified.pDestinationAdapter);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't duplicate destination adapter address!");
|
|
goto Failure;
|
|
}
|
|
*/
|
|
sppeqdModified.pDestinationAdapter = psppeqd->pDestinationAdapter;
|
|
|
|
|
|
//
|
|
// Change the service provider GUID so it matches the one we're
|
|
// calling.
|
|
//
|
|
hr = sppeqdModified.pDestinationAdapter->SetSP(&this->m_guidRealSP);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't change destination adapter address' SP!");
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// We wrapped the enum query data structure, get the original object.
|
|
//
|
|
pEnumQueryDataWrapper = ENUMQUERYEVENTWRAPPER_FROM_SPIEQUERY(psppeqd->pIncomingQueryData);
|
|
|
|
DNASSERT(*((DWORD*) (&pEnumQueryDataWrapper->m_Sig)) == 0x57455145); // 0x57 0x45 0x51 0x45 = 'WEQE' = 'EQEW' in Intel order
|
|
|
|
sppeqdModified.pIncomingQueryData = pEnumQueryDataWrapper->pOriginalQuery;
|
|
|
|
|
|
sppeqdModified.dwFlags = psppeqd->dwFlags;
|
|
|
|
|
|
//
|
|
// Proxy the enum query through the real service provider.
|
|
//
|
|
hr = this->m_pDP8SP->ProxyEnumQuery(&sppeqdModified);
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed proxying enum query through real SP object (0x%p)!",
|
|
this->m_pDP8SP);
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
|
|
Exit:
|
|
|
|
/*
|
|
if (sppeqdModified.pDestinationAdapter != NULL)
|
|
{
|
|
sppeqdModified.pDestinationAdapter->Release();
|
|
sppeqdModified.pDestinationAdapter = NULL;
|
|
}
|
|
*/
|
|
|
|
DPFX(DPFPREP, 2, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::ProxyEnumQuery
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::InitializeObject"
|
|
//=============================================================================
|
|
// CDP8SimSP::InitializeObject
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Sets up the object for use like the constructor, but may
|
|
// fail with OUTOFMEMORY. Should only be called by class factory
|
|
// creation routine.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: HRESULT
|
|
// S_OK - Initialization was successful.
|
|
// E_OUTOFMEMORY - There is not enough memory to initialize.
|
|
//=============================================================================
|
|
HRESULT CDP8SimSP::InitializeObject(void)
|
|
{
|
|
HRESULT hr;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Enter", this);
|
|
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Create the lock.
|
|
//
|
|
|
|
if (! DNInitializeCriticalSection(&this->m_csLock))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Failure;
|
|
}
|
|
|
|
|
|
//
|
|
// Don't allow critical section reentry.
|
|
//
|
|
DebugSetCriticalSectionRecursionCount(&this->m_csLock, 0);
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
Exit:
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Returning: [0x%lx]", this, hr);
|
|
|
|
return hr;
|
|
|
|
|
|
Failure:
|
|
|
|
goto Exit;
|
|
} // CDP8SimSP::InitializeObject
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::UninitializeObject"
|
|
//=============================================================================
|
|
// CDP8SimSP::UninitializeObject
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Cleans up the object like the destructor, mostly to balance
|
|
// InitializeObject.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::UninitializeObject(void)
|
|
{
|
|
DPFX(DPFPREP, 5, "(0x%p) Enter", this);
|
|
|
|
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
DNDeleteCriticalSection(&this->m_csLock);
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Leave", this);
|
|
} // CDP8SimSP::UninitializeObject
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::PerformDelayedSend"
|
|
//=============================================================================
|
|
// CDP8SimSP::PerformDelayedSend
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Performs a delayed send.
|
|
//
|
|
// Arguments:
|
|
// PVOID pvContext - Pointer to context to use when performing delayed
|
|
// send.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::PerformDelayedSend(PVOID const pvContext)
|
|
{
|
|
HRESULT hr;
|
|
CDP8SimSend * pDP8SimSend = (CDP8SimSend*) pvContext;
|
|
DP8SIMCOMMAND_FPMCONTEXT CommandFPMContext;
|
|
CDP8SimCommand * pDP8SimCommand = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p)", this, pvContext);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pvContext != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
//
|
|
// Prepare a command object.
|
|
//
|
|
|
|
ZeroMemory(&CommandFPMContext, sizeof(CommandFPMContext));
|
|
CommandFPMContext.dwType = CMDTYPE_SENDDATA_DELAYED;
|
|
CommandFPMContext.pvUserContext = pDP8SimSend;
|
|
|
|
pDP8SimCommand = (CDP8SimCommand*)g_FPOOLCommand.Get(&CommandFPMContext);
|
|
if (pDP8SimCommand == NULL)
|
|
{
|
|
DPFX(DPFPREP, 0, "Couldn't allocate memory for new command object!");
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 7, "New command 0x%p.", pDP8SimCommand);
|
|
|
|
|
|
//
|
|
// Add a reference for the send command.
|
|
//
|
|
pDP8SimCommand->AddRef();
|
|
|
|
pDP8SimSend->SetSendDataBlockContext(pDP8SimCommand);
|
|
|
|
|
|
//
|
|
// Issue the send to the real SP. Essentially ignore the return value
|
|
// since we already indicated completion to the upper layer.
|
|
//
|
|
hr = this->m_pDP8SP->SendData(pDP8SimSend->GetSendDataBlockPtr());
|
|
if (FAILED(hr))
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed sending delayed data (err = 0x%lx)!", hr);
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted command 0x%p.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
|
|
|
|
//
|
|
// Remove the send counter.
|
|
//
|
|
this->DecSendsPending();
|
|
|
|
|
|
DPFX(DPFPREP, 7, "Releasing aborted send 0x%p.", pDP8SimSend);
|
|
pDP8SimSend->Release();
|
|
|
|
|
|
//
|
|
// Continue.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
if (hr != DPNSUCCESS_PENDING)
|
|
{
|
|
//
|
|
// The command completed right away.
|
|
//
|
|
DNASSERT(hr == DPN_OK);
|
|
|
|
hr = this->m_pDP8SimCB->CommandComplete(pDP8SimSend->GetSendDataBlockCommand(),
|
|
hr,
|
|
pDP8SimCommand);
|
|
DNASSERT(hr == DPN_OK);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Save the output parameters returned by the SP.
|
|
//
|
|
pDP8SimCommand->SetRealSPCommand(pDP8SimSend->GetSendDataBlockCommand(),
|
|
pDP8SimSend->GetSendDataBlockCommandDescriptor());
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Give up local reference.
|
|
//
|
|
DPFX(DPFPREP, 7, "Releasing command 0x%p local reference.", pDP8SimCommand);
|
|
pDP8SimCommand->Release();
|
|
pDP8SimCommand = NULL;
|
|
}
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Leave", this);
|
|
} // CDP8SimSP::PerformDelayedSend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::PerformDelayedReceive"
|
|
//=============================================================================
|
|
// CDP8SimSP::PerformDelayedReceive
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Performs a delayed receive.
|
|
//
|
|
// Arguments:
|
|
// PVOID pvContext - Pointer to context to use when performing delayed
|
|
// receive.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::PerformDelayedReceive(PVOID const pvContext)
|
|
{
|
|
HRESULT hr;
|
|
CDP8SimReceive * pDP8SimReceive = (CDP8SimReceive*) pvContext;
|
|
IDP8SPCallback * pDP8SPCallback;
|
|
SPIE_DATA * pData;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Parameters: (0x%p)", this, pvContext);
|
|
|
|
|
|
//
|
|
// Validate (actually assert) the object.
|
|
//
|
|
DNASSERT(this->IsValidObject());
|
|
|
|
|
|
//
|
|
// Assert the parameters.
|
|
//
|
|
DNASSERT(pvContext != NULL);
|
|
|
|
|
|
#ifdef DEBUG
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
#endif // DEBUG
|
|
|
|
|
|
pDP8SPCallback = this->m_pDP8SimCB->GetRealCallbackInterface();
|
|
pData = pDP8SimReceive->GetReceiveDataBlockPtr();
|
|
|
|
|
|
//
|
|
// Indicate the event to the real callback interface.
|
|
//
|
|
|
|
DPFX(DPFPREP, 2, "Indicating event SPEV_DATA (message = 0x%p) to interface 0x%p.",
|
|
pData, pDP8SPCallback);
|
|
|
|
hr = pDP8SPCallback->IndicateEvent(SPEV_DATA, pData);
|
|
|
|
DPFX(DPFPREP, 2, "Returning from event SPEV_DATA [0x%lx].", hr);
|
|
|
|
|
|
//
|
|
// Update the statistics.
|
|
//
|
|
this->IncrementStatsReceiveTransmitted(pData->pReceivedData->BufferDesc.dwBufferSize,
|
|
pDP8SimReceive->GetLatencyAdded());
|
|
|
|
|
|
//
|
|
// Return the buffers to the real SP unless the user wanted to keep them.
|
|
//
|
|
if (hr != DPNSUCCESS_PENDING)
|
|
{
|
|
DPFX(DPFPREP, 8, "Returning receive data 0x%p to real SP 0x%p.",
|
|
pData->pReceivedData, this->m_pDP8SP);
|
|
|
|
|
|
hr = this->m_pDP8SP->ReturnReceiveBuffers(pData->pReceivedData);
|
|
if (hr != DPN_OK)
|
|
{
|
|
DPFX(DPFPREP, 0, "Failed returning receive buffers 0x%p (err = 0x%lx)! Ignoring.",
|
|
pData->pReceivedData, hr);
|
|
|
|
//
|
|
// Ignore failure.
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, 8, "Callback interface 0x%p keeping receive data 0x%p.",
|
|
pDP8SPCallback, pData->pReceivedData);
|
|
|
|
//
|
|
// Our user needs to return the buffers at some point.
|
|
//
|
|
}
|
|
|
|
|
|
//
|
|
// Remove the receive counter.
|
|
//
|
|
this->DecReceivesPending();
|
|
|
|
|
|
//
|
|
// Release the delayed receive reference.
|
|
//
|
|
DPFX(DPFPREP, 7, "Releasing receive 0x%p.", pDP8SimReceive);
|
|
pDP8SimReceive->Release();
|
|
pDP8SimReceive = NULL;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Leave", this);
|
|
} // CDP8SimSP::PerformDelayedReceive
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::IncSendsPending"
|
|
//=============================================================================
|
|
// CDP8SimSP::IncSendsPending
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Increments the counter tracking the number of sends pending.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::IncSendsPending(void)
|
|
{
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
//
|
|
// Increment the counters.
|
|
//
|
|
this->m_dwSendsPending++;
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Sends now pending = %u.",
|
|
this, this->m_dwSendsPending);
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
} // CDP8SimSP::IncSendsPending
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::DecSendsPending"
|
|
//=============================================================================
|
|
// CDP8SimSP::DecSendsPending
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Decrements the counter tracking the number of sends pending.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::DecSendsPending(void)
|
|
{
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
//
|
|
// Decrement the counters.
|
|
//
|
|
DNASSERT(this->m_dwSendsPending > 0);
|
|
this->m_dwSendsPending--;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Sends now pending = %u.",
|
|
this, this->m_dwSendsPending);
|
|
|
|
//
|
|
// If that was the last send pending and someone is waiting for all of them
|
|
// to complete, notify him.
|
|
//
|
|
if ((this->m_dwSendsPending == 0) &&
|
|
(this->m_hLastPendingSendEvent != NULL))
|
|
{
|
|
DPFX(DPFPREP, 1, "Last pending send, notifying waiting thread.");
|
|
|
|
SetEvent(this->m_hLastPendingSendEvent);
|
|
}
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
} // CDP8SimSP::DecSendsPending
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::IncReceivesPending"
|
|
//=============================================================================
|
|
// CDP8SimSP::IncReceivesPending
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Increments the counter tracking the number of receives pending.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::IncReceivesPending(void)
|
|
{
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
//
|
|
// Increment the counters.
|
|
//
|
|
this->m_dwReceivesPending++;
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Receives now pending = %u.",
|
|
this, this->m_dwReceivesPending);
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
} // CDP8SimSP::IncReceivesPending
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::DecReceivesPending"
|
|
//=============================================================================
|
|
// CDP8SimSP::DecReceivesPending
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Decrements the counter tracking the number of receives pending.
|
|
//
|
|
// Arguments: None.
|
|
//
|
|
// Returns: None.
|
|
//=============================================================================
|
|
void CDP8SimSP::DecReceivesPending(void)
|
|
{
|
|
DNEnterCriticalSection(&this->m_csLock);
|
|
|
|
|
|
//
|
|
// Assert the object state.
|
|
//
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_INITIALIZED);
|
|
DNASSERT(this->m_dwFlags & DP8SIMSPOBJ_STARTEDGLOBALWORKERTHREAD);
|
|
|
|
//
|
|
// Decrement the counters.
|
|
//
|
|
DNASSERT(this->m_dwReceivesPending > 0);
|
|
this->m_dwReceivesPending--;
|
|
|
|
|
|
DPFX(DPFPREP, 5, "(0x%p) Receives now pending = %u.",
|
|
this, this->m_dwReceivesPending);
|
|
|
|
/*
|
|
//
|
|
// If that was the last receive pending and someone is waiting for all of
|
|
// them to complete, notify him.
|
|
//
|
|
if ((this->m_dwReceivesPending == 0) &&
|
|
(this->m_hLastPendingReceiveEvent != NULL))
|
|
{
|
|
DPFX(DPFPREP, 1, "Last pending receive, notifying waiting thread.");
|
|
|
|
SetEvent(this->m_hLastPendingReceiveEvent);
|
|
}
|
|
*/
|
|
|
|
|
|
DNLeaveCriticalSection(&this->m_csLock);
|
|
} // CDP8SimSP::DecReceivesPending
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::ShouldDrop"
|
|
//=============================================================================
|
|
// CDP8SimSP::ShouldDrop
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Returns TRUE if it is determined that the packet should be
|
|
// dropped, or FALSE if not.
|
|
//
|
|
// Arguments:
|
|
// FLOAT fDropPercentage - Percentage chance that the packet should be
|
|
// dropped.
|
|
//
|
|
// Returns: BOOL
|
|
//=============================================================================
|
|
BOOL CDP8SimSP::ShouldDrop(const FLOAT fDropPercentage)
|
|
{
|
|
double dRand;
|
|
|
|
|
|
if (fDropPercentage == 0.0)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DNASSERT((fDropPercentage >= 0.0) && (fDropPercentage <= 100.0));
|
|
dRand = GetGlobalRand() * 100.0;
|
|
|
|
return ((dRand < fDropPercentage) ? TRUE: FALSE);
|
|
} // CDP8SimSP::ShouldDrop
|
|
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "CDP8SimSP::GetDelay"
|
|
//=============================================================================
|
|
// CDP8SimSP::GetDelay
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Description: Determines a delay factors based on the given bandwidth,
|
|
// data size, and random latency values.
|
|
//
|
|
// This function returns TRUE if some delay should be added,
|
|
// FALSE if not.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwBandwidthBPS - Bandwidth settings.
|
|
// DWORD dwPacketHeaderSize - Size of fixed transport header.
|
|
// DWORD dwDataSize - Size of packet being sent/received.
|
|
// DWORD dwMinRandMS - Minimum random latency value.
|
|
// DWORD dwMaxRandMS - Maximum random latency value.
|
|
// DWORD * pdwBandwidthDelay - Place to store delay caused by bandwidth.
|
|
// DWORD * pdwLatencyDelay - Place to store delay caused by latency.
|
|
//
|
|
// Returns: BOOL
|
|
//=============================================================================
|
|
BOOL CDP8SimSP::GetDelay(const DWORD dwBandwidthBPS,
|
|
const DWORD dwPacketHeaderSize,
|
|
const DWORD dwDataSize,
|
|
const DWORD dwMinRandMS,
|
|
const DWORD dwMaxRandMS,
|
|
DWORD * const pdwBandwidthDelay,
|
|
DWORD * const pdwLatencyDelay)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
double dTransferTime;
|
|
double dHalfDistance;
|
|
double dRand1;
|
|
double dRand2;
|
|
double dTemp;
|
|
|
|
|
|
//
|
|
// If there's no bandwidth limit, there's no delay.
|
|
//
|
|
if (dwBandwidthBPS == 0)
|
|
{
|
|
(*pdwBandwidthDelay) = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Otherwise, find out how many seconds it will take to transfer the
|
|
// data and add it to the base random latency.
|
|
//
|
|
dTransferTime = dwPacketHeaderSize + dwDataSize;
|
|
dTransferTime /= dwBandwidthBPS;
|
|
dTransferTime *= 1000;
|
|
|
|
|
|
//
|
|
// Round the value down to an even number of milliseconds.
|
|
//
|
|
(*pdwBandwidthDelay) = (DWORD) dTransferTime;
|
|
|
|
fResult = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If the min and max are equal, we can use either as the latency.
|
|
// If it's not zero, then we need to note the delay.
|
|
//
|
|
if (dwMinRandMS == dwMaxRandMS)
|
|
{
|
|
(*pdwLatencyDelay) = dwMinRandMS;
|
|
if (dwMinRandMS > 0)
|
|
{
|
|
fResult = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// First store half the distance between the min and max.
|
|
//
|
|
dHalfDistance = dwMaxRandMS - dwMinRandMS;
|
|
dHalfDistance /= 2;
|
|
|
|
|
|
//
|
|
// Now pick a number using a normal (bell curve) distribution.
|
|
// This requires two randomly generated numbers and some fancy math.
|
|
//
|
|
|
|
do
|
|
{
|
|
dRand1 = 2.0 * GetGlobalRand() - 1.0;
|
|
dRand2 = 2.0 * GetGlobalRand() - 1.0;
|
|
dTemp = (dRand1 * dRand1) + (dRand2 * dRand2);
|
|
}
|
|
while ((dTemp >= 1.0) || (dTemp == 0.0));
|
|
|
|
dTemp = sqrt(-2.0 * log(dTemp) / dTemp);
|
|
//dTemp = dHalfDistance + (dRand1 * dTemp) * (dHalfDistance * 0.25);
|
|
dTemp = dHalfDistance + (dRand1 * dTemp) * (dHalfDistance * 0.36666);
|
|
|
|
//
|
|
// Cap the values, because our bell curve fattening factor (0.36666
|
|
// instead of 0.25) causes the distribution to leak out past the edges.
|
|
//
|
|
if (dTemp < 0.0)
|
|
{
|
|
dTemp = 0.0;
|
|
}
|
|
else if (dTemp > (dwMaxRandMS - dwMinRandMS))
|
|
{
|
|
dTemp = dwMaxRandMS - dwMinRandMS;
|
|
}
|
|
|
|
|
|
//
|
|
// Round the normally distributed value down to an even number of
|
|
// milliseconds and add it to the minimum for the final base latency.
|
|
//
|
|
(*pdwLatencyDelay) = dwMinRandMS + (DWORD) dTemp;
|
|
|
|
fResult = TRUE;
|
|
}
|
|
|
|
return fResult;
|
|
} // CDP8SimSP::GetDelay
|