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