Leaked source code of windows server 2003
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

/***************************************************************************
*
* 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