windows-nt/Source/XPSP1/NT/net/tapi/skywalker/mdhcp/cmdhcp.cpp
2020-09-26 16:20:57 +08:00

1920 lines
58 KiB
C++

/*
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
CMDhcp.cpp
Abstract:
Implementation of CMdhcp.
Author:
*/
#include "stdafx.h"
#include <winsock2.h>
#include "mdhcp.h"
#include "CMDhcp.h"
#include "lease.h"
#include "local.h"
// template for collections
#include "collect.h"
// From rendezvous control code:
// sets the first bit to indicate error
// sets the win32 facility code
// this is used instead of the HRESULT_FROM_WIN32 macro
// because that clears the customer flag
inline long
HRESULT_FROM_ERROR_CODE(IN long ErrorCode)
{
return ( 0x80070000 | (0xa000ffff & ErrorCode) );
}
/////////////////////////////////////////////////////////////////////////////
// Helper functions.
/////////////////////////////////////////////////////////////////////////////
HRESULT CMDhcp::CreateWrappers(
DWORD dwScopeCount, // the number of scopes we were given
MCAST_SCOPE_ENTRY * pScopeList, // array of scope structs
IMcastScope *** pppWrappers, // here we will put an array of if ptrs
BOOL fLocal // true = scopes are locally generated
)
{
LOG((MSP_TRACE, "CMDhcp::CreateWrappers enter"));
HRESULT hr;
// Allocate the array of interface pointers.
typedef IMcastScope * ScopeIfPtr;
*pppWrappers = new ScopeIfPtr[dwScopeCount];
if ( (*pppWrappers) == NULL )
{
LOG((MSP_ERROR,
"can't create allocate array of interface pointers"));
return E_OUTOFMEMORY;
}
// For each scope in the list of scopes returned by the C API
for (DWORD i = 0; i < dwScopeCount; i++)
{
// create the com object.
CComObject<CMDhcpScope> * pMDhcpScope;
hr = CComObject<CMDhcpScope>::CreateInstance(&pMDhcpScope);
if ( (FAILED(hr)) || (NULL == pMDhcpScope) )
{
LOG((MSP_ERROR, "can't create MDhcpScope Object (%d/%d): %08x",
i, dwScopeCount, hr));
// get rid of all previously created COM objects
for (DWORD j = 0; j < i; j++) (*pppWrappers)[j]->Release();
delete (*pppWrappers);
return hr;
}
// Get the IMcastScope interface.
hr = pMDhcpScope->_InternalQueryInterface(
IID_IMcastScope,
(void **) (& (*pppWrappers)[i])
);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateWrappers:QueryInterface (%d/%d) failed: %08x",
i, dwScopeCount, hr));
// get rid of all previously created COM objects
for (DWORD j = 0; j < i; j++) (*pppWrappers)[j]->Release();
delete (*pppWrappers);
delete pMDhcpScope; // don't know if it addrefed or not
return hr;
}
// Set the object's info based on the struct. From now on the
// object will be read-only.
hr = pMDhcpScope->Initialize(pScopeList[i], fLocal);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateWrappers:Initialize (%d/%d) failed: %08x",
i, dwScopeCount, hr));
// get rid of all previously created COM objects
for (DWORD j = 0; j < i; j++) (*pppWrappers)[j]->Release();
delete (*pppWrappers);
pMDhcpScope->Release(); // we know it addrefed in the QI
return hr;
}
}
LOG((MSP_TRACE, "CMDhcp::CreateWrappers exit"));
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// Get a list of scopes from the C API.
HRESULT CMDhcp::GetScopeList(
DWORD * pdwScopeCount,
MCAST_SCOPE_ENTRY ** ppScopeList,
BOOL * pfLocal
)
{
LOG((MSP_TRACE, "CMDhcp::GetScopeList enter"));
_ASSERTE( ! IsBadWritePtr(pdwScopeCount, sizeof(DWORD) ) );
_ASSERTE( ! IsBadWritePtr(ppScopeList, sizeof(MCAST_SCOPE_ENTRY *) ) );
HRESULT hr;
DWORD dwScopeLen = 0; // size in bytes of returned scopes structure
DWORD dwCode; // return code
*pfLocal = FALSE; // try mdhcp first
dwCode = LocalEnumerateScopes(NULL, // only want to know how many we have
&dwScopeLen, // # of bytes should be zero
pdwScopeCount, // # of scopes placed here
pfLocal);
// This must succeed for us to continue.
if (dwCode != ERROR_SUCCESS)
{
hr = HRESULT_FROM_ERROR_CODE(dwCode);
LOG((MSP_ERROR, "GetScopeList: First C API call failed "
"(code: %d hresult: %08x)", dwCode, hr));
return hr;
}
do
{
// If there are no scopes to choose from, let's not enumerate them.
// We also need at least the length fields from the first
// UNICODE_STRING.
if ( (dwScopeLen < sizeof(MCAST_SCOPE_ENTRY)) || (*pdwScopeCount < 1) )
{
LOG((MSP_ERROR, "GetScopeList: don't have enough scopes (%d;%d)",
dwScopeLen, *pdwScopeCount));
return E_FAIL;
}
// Now that we know how many there are, allocate an array to hold the
// scope structs returned by the C method.
// The API acts very strangely here. We have to give it dwScopeLen
// bytes as one big chunk. The first dwScopeCount * sizeof(MCAST_SCOPE_ENTRY)
// bytes contain dwScopeCount MCAST_SCOPE_ENTRY structures. Each of these
// structures has a pointer to a wide string. The first of these points
// to the first byte after all the MCAST_SCOPE_ENTRY structures! In this way
// they avoid doing so many mallocs. We therefore have to
// copy each string in the COM wrapper for each scope, and then delete
// this buffer (ppScopeList) all at once after all the wrapping is complete.
*ppScopeList = (MCAST_SCOPE_ENTRY *) new CHAR[dwScopeLen];
if (*ppScopeList == NULL)
{
LOG((MSP_ERROR, "GetScopeList: not enough memory to allocate scope"
" list (size = %d)", dwScopeLen));
return E_OUTOFMEMORY;
}
// *pdwScopeCount still specifies the number of scopes we can get.
// Now ask for all the scopes.
dwCode = LocalEnumerateScopes(*ppScopeList,
&dwScopeLen,
pdwScopeCount,
pfLocal);
// If things changed in this bried time, just try again.
if (dwCode == ERROR_MORE_DATA)
{
LOG((MSP_INFO, "GetScopeList: got more scopes than we were told "
"existed (we though there were %d) -- retrying",
*pdwScopeCount));
delete (*ppScopeList);
}
}
while (dwCode == ERROR_MORE_DATA);
if (dwCode != ERROR_SUCCESS)
{
hr = HRESULT_FROM_ERROR_CODE(dwCode);
LOG((MSP_ERROR, "GetScopeList: Second C API call failed "
"(code: %d hresult: %08x)", dwCode, hr));
delete (*ppScopeList);
return hr;
}
LOG((MSP_TRACE, "CMDhcp::GetScopeList exit"));
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// This is a private helper method that creates a CMDhcpLeaseInfo object and
// uses it to wrap a lease info structure and request ID into an
// IMcastLeaseInfo interface.
HRESULT CMDhcp::WrapMDhcpLeaseInfo(
BOOL fGotTtl,
long lTtl,
BOOL fLocal,
MCAST_LEASE_INFO * pLeaseInfo,
MCAST_CLIENT_UID * pRequestID,
IMcastLeaseInfo ** ppInterface
)
{
LOG((MSP_TRACE, "CMDhcp::WrapMDhcpLeaseInfo enter"));
// We don't check pLeaseInfo or pRequestID -- they'll be comprehensively
// checked in the Wrap call below.
if ( IsBadWritePtr(ppInterface, sizeof(IMcastLeaseInfo *) ) )
{
LOG((MSP_ERROR, "WrapMDhcpLeaseInfo: invalid pointer: %x",
ppInterface));
return E_POINTER;
}
HRESULT hr;
// create the com object.
CComObject<CMDhcpLeaseInfo> * pMDhcpLeaseInfo;
hr = CComObject<CMDhcpLeaseInfo>::CreateInstance(&pMDhcpLeaseInfo);
if ( (FAILED(hr)) || (pMDhcpLeaseInfo == NULL) )
{
LOG((MSP_ERROR, "can't create MDhcpLeaseInfo Object."));
return hr;
}
// Get the IMcastLeaseInfo interface.
hr = pMDhcpLeaseInfo->_InternalQueryInterface(
IID_IMcastLeaseInfo,
(void **)ppInterface
);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "WrapMDhcpLeaseInfo:QueryInterface failed: %x", hr));
delete pMDhcpLeaseInfo;
return hr;
}
// Wrap the object in the interface.
hr = pMDhcpLeaseInfo->Wrap(pLeaseInfo, pRequestID, fGotTtl, lTtl);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "WrapMDhcpLeaseInfo:Wrap failed: %x", hr));
(*ppInterface)->Release();
return hr;
}
hr = pMDhcpLeaseInfo->SetLocal(fLocal);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "WrapMDhcpLeaseInfo: SetLocal failed: %x", hr));
(*ppInterface)->Release();
return hr;
}
LOG((MSP_TRACE, "CMDhcp::WrapMDhcpLeaseInfo exit"));
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// This is a private helper method that munges the arguments into structs
// at the beginning of a Request call.
HRESULT CMDhcp::PrepareArgumentsRequest(
IN IMcastScope * pScope,
IN DATE LeaseStartTime,
IN DATE LeaseStopTime,
IN long lNumAddresses,
OUT MCAST_CLIENT_UID * pRequestIDStruct,
OUT MCAST_SCOPE_CTX * pScopeCtxStruct,
OUT MCAST_LEASE_INFO ** ppLeaseStruct,
OUT BOOL * pfLocal,
OUT long * plTtl
)
{
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsRequest enter"));
_ASSERTE ( ! IsBadReadPtr(pScope, sizeof(IMcastScope) ) );
_ASSERTE ( ! IsBadWritePtr(pRequestIDStruct, sizeof(MCAST_CLIENT_UID) ) );
_ASSERTE ( ! IsBadWritePtr(pScopeCtxStruct, sizeof(MCAST_SCOPE_CTX) ) );
_ASSERTE ( ! IsBadWritePtr(ppLeaseStruct, sizeof(MCAST_LEASE_INFO *) ) );
_ASSERTE ( ! IsBadWritePtr(pfLocal, sizeof(BOOL) ) );
_ASSERTE ( ! IsBadWritePtr(plTtl, sizeof(long) ) );
HRESULT hr;
//
// The start time must be less than the stop time.
//
if ( LeaseStartTime > LeaseStopTime )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"start time is greater than stop time - exit E_INVALIDARG"));
return E_INVALIDARG;
}
//
// lNumAddresses must be stuffed into a WORD for the C API -- check to see if
// it's in range.
//
if ( ( lNumAddresses < 0 ) || ( lNumAddresses > USHRT_MAX ) )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"invalid number of addresses - exit E_INVALIDARG"));
return E_INVALIDARG;
}
//
// dynamic_cast to get an object pointer from the passed-in interface
// pointer. This will cause an exception if the user tries to use their
// own implementation of IMcastScope, which is quite unlikely.
//
CMDhcpScope * pCScope = dynamic_cast<CMDhcpScope *>(pScope);
if (pCScope == NULL)
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"Unsupported CMDhcpScope object"));
return E_POINTER;
}
//
// Find out if this scope uses local alloc.
//
hr = pCScope->GetLocal(pfLocal);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest: "
"GetLocal failed %08x", hr));
return hr;
}
//
// Find out the ttl to stuff in leases from this scope.
//
hr = pCScope->get_TTL( plTtl );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest: "
"get_TTL failed %08x", hr));
return hr;
}
//
// Get the normal scope info.
// ScopeID is stored in network byte order but the get_ method
// returns it in host byte order for the benefit of apps.
//
long lScopeID;
hr = pScope->get_ScopeID( &lScopeID );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"can't get scope ID from scope object - exit 0x%08x", hr));
return hr;
}
pScopeCtxStruct->ScopeID.IpAddrV4 = htonl(lScopeID);
hr = pScope->get_ServerID(
(long *) &(pScopeCtxStruct->ServerID.IpAddrV4) );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"can't get server ID from scope object - exit 0x%08x", hr));
return hr;
}
hr = pScope->get_InterfaceID(
(long *) &(pScopeCtxStruct->Interface.IpAddrV4) );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest - "
"can't get interface ID from scope object - exit 0x%08x", hr));
return hr;
}
//
// Allocate space for the client UID.
//
pRequestIDStruct->ClientUIDLength = MCAST_CLIENT_ID_LEN;
pRequestIDStruct->ClientUID = new BYTE[ MCAST_CLIENT_ID_LEN ];
if ( pRequestIDStruct->ClientUID == NULL )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest: out of memory in "
"buffer allocation"));
return E_OUTOFMEMORY;
}
//
// Generate a random client UID.
//
DWORD dwResult = McastGenUID( pRequestIDStruct );
if ( dwResult != ERROR_SUCCESS )
{
hr = HRESULT_FROM_ERROR_CODE( dwResult );
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsRequest: "
"McastGenUID failed (dw = %d; hr = 0x%08x)", dwResult, hr));
return hr;
}
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsRequest: before MCAST_LEASE_INFO "
"alloc; we are asking for %d addresses", lNumAddresses));
//
// Allocate the lease info structure.
// The caller will delete it after the API call.
// This is a REQUEST, so we do not specify any particular addresses
// in the array -- we do not need space for them.
//
//
(*ppLeaseStruct) = new MCAST_LEASE_INFO;
if ( (*ppLeaseStruct) == NULL )
{
LOG((MSP_ERROR, "CMDhcp::PrepareArgumentsRequest: out of memory in "
"MCAST_LEASE_INFO allocation"));
delete (pRequestIDStruct->ClientUID);
return E_OUTOFMEMORY;
}
//
// Fill in the times.
//
hr = DateToLeaseTime(LeaseStartTime,
&((*ppLeaseStruct)->LeaseStartTime));
if ( FAILED(hr) )
{
delete (pRequestIDStruct->ClientUID);
delete (*ppLeaseStruct);
return hr;
}
hr = DateToLeaseTime(LeaseStopTime,
&((*ppLeaseStruct)->LeaseEndTime));
if ( FAILED(hr) )
{
delete (pRequestIDStruct->ClientUID);
delete (*ppLeaseStruct);
return hr;
}
//
// Fill in the address info fields.
//
(*ppLeaseStruct)->ServerAddress.IpAddrV4 = 0;
(*ppLeaseStruct)->AddrCount = (WORD) lNumAddresses; // checked above
//
// This is a REQUEST, so we do not specify any particular addresses
// in the array -- we make the array NULL.
//
(*ppLeaseStruct)->pAddrBuf = NULL;
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsRequest exit"));
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// This is a private helper method that munges the arguments into structs
// at the beginning of a Renew or Release call.
HRESULT CMDhcp::PrepareArgumentsNonRequest(
IN IMcastLeaseInfo * pLease,
OUT MCAST_CLIENT_UID * pRequestIDStruct,
OUT MCAST_LEASE_INFO ** ppLeaseStruct,
OUT BOOL * pfLocal,
OUT BOOL * pfGotTtl,
OUT long * plTtl
)
{
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsNonRequest enter"));
if ( IsBadReadPtr(pLease, sizeof(IMcastLeaseInfo) ) )
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest: bad pLease pointer argument"));
return E_POINTER;
}
_ASSERTE ( ! IsBadWritePtr(pRequestIDStruct, sizeof(MCAST_CLIENT_UID) ) );
_ASSERTE ( ! IsBadWritePtr(ppLeaseStruct, sizeof(MCAST_LEASE_INFO *) ) );
_ASSERTE ( ! IsBadWritePtr(pfLocal, sizeof(BOOL) ) );
_ASSERTE ( ! IsBadWritePtr(pfGotTtl, sizeof(BOOL) ) );
_ASSERTE ( ! IsBadWritePtr(plTtl, sizeof(long) ) );
HRESULT hr;
// We approach things in a completely different way here, compared
// to the other PrepareArguments method -- we use
// dynamic_cast to get an object pointer from the passed-in interface
// pointer. This will cause an exception if the user tries to use their
// own implementation of IMcastRequestID, which is quite unlikely.
CMDhcpLeaseInfo * pCLease = dynamic_cast<CMDhcpLeaseInfo *>(pLease);
if (pCLease == NULL)
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest: Unsupported CMDhcpLeaseInfo object"));
return E_POINTER;
}
//
// Find out if this lease was obtained using local alloc.
//
hr = pCLease->GetLocal(pfLocal);
if (FAILED(hr))
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest: "
"GetLocal failed %08x", hr));
return hr;
}
//
// If the lease had a TTL set, then retrieve it for use in a
// resulting response. Else just say we don't have a ttl.
//
hr = pCLease->get_TTL( plTtl );
*pfGotTtl = SUCCEEDED(hr);
//
// Get our request ID from the lease info object.
//
pRequestIDStruct->ClientUIDLength = MCAST_CLIENT_ID_LEN;
pRequestIDStruct->ClientUID = new BYTE[ MCAST_CLIENT_ID_LEN ];
if (pRequestIDStruct->ClientUID == NULL)
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest: out of memory in "
"buffer allocation"));
return E_OUTOFMEMORY;
}
hr = pCLease->GetRequestIDBuffer(pRequestIDStruct->ClientUIDLength,
pRequestIDStruct->ClientUID);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest: RequestID "
"GetBuffer failed %08x", hr));
delete (pRequestIDStruct->ClientUID);
return hr;
}
//
// Get the rest of the stuff, which belongs in the straight lease info
// structure, from the lease info object.
//
// this does a new for us
hr = pCLease->GetStruct(ppLeaseStruct);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest - "
"failed to grab pLeaseStruct - 0x%08x", hr));
delete (pRequestIDStruct->ClientUID);
return hr;
}
LOG((MSP_TRACE, "CMDhcp::PrepareArgumentsNonRequest exit"));
return S_OK;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// VerifyAndGetArrayBounds
//
// Helper function for variant/safearrays
//
// Array
// IN Variant that contains a safearray
//
// ppsa
// OUT safearray returned here
//
// pllBound
// OUT array lower bound returned here
//
// pluBound
// OUT array upper bound returned here
//
// RETURNS
//
// verifies that Array contains an array, and returns the array, upper
// and lower bounds.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
static HRESULT
VerifyAndGetArrayBounds(
VARIANT Array,
SAFEARRAY ** ppsa,
long * pllBound,
long * pluBound
)
{
LOG((MSP_TRACE, "VerifyAndGetArrayBounds: enter"));
UINT uDims;
HRESULT hr = S_OK;
//
// see if the variant & safearray are valid
//
try
{
if (!(V_ISARRAY(&Array)))
{
if ( Array.vt == VT_NULL )
{
//
// null is usually valid
//
*ppsa = NULL;
LOG((MSP_INFO, "Returning NULL array"));
return S_FALSE;
}
LOG((MSP_ERROR, "Array - not an array"));
return E_INVALIDARG;
}
if ( Array.parray == NULL )
{
//
// null is usually valide
//
*ppsa = NULL;
LOG((MSP_INFO, "Returning NULL array"));
return S_FALSE;
}
*ppsa = V_ARRAY(&Array);
uDims = SafeArrayGetDim( *ppsa );
}
catch(...)
{
hr = E_POINTER;
}
if (!SUCCEEDED(hr))
{
LOG((MSP_ERROR, "Array - invalid array"));
return hr;
}
//
// verify array
//
if ( uDims != 1 )
{
if ( uDims == 0 )
{
LOG((MSP_ERROR, "Array - has 0 dim"));
return E_INVALIDARG;
}
else
{
LOG((MSP_WARN, "Array - has > 1 dim - will only use 1"));
}
}
//
// Get array bounds
//
SafeArrayGetUBound(
*ppsa,
1,
pluBound
);
SafeArrayGetLBound(
*ppsa,
1,
pllBound
);
LOG((MSP_TRACE, "VerifyAndGetArrayBounds: exit"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// CMDhcp::FinalContruct
//
// Parameters
// none
//
// Return Values
// S_OK Success
// E_OUTOFMEMORY Not enough memory to create free thread marshaler
// E_FAIL We are running the wrong version of dhcpcsvc.dll
//
// Description
// This is called on construction. It creates the free threaded marshaler
// and checks if the C API's DLL is the same version that we were compiled
// with.
//////////////////////////////////////////////////////////////////////////////
HRESULT CMDhcp::FinalConstruct(void)
{
LOG((MSP_TRACE, "CMDhcp::FinalConstruct - enter"));
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
& m_pFTM );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDhcp::FinalConstruct - "
"failed to create FTM - exit 0x%08x", hr));
//
// Now, FinalRelease will get called, and then CoCreate will return
// failure.
//
return hr;
}
// Munil uses this as an IN/OUT parameter.
DWORD dwVersion = MCAST_API_CURRENT_VERSION; // defined in mdhccapi.h
DWORD dwCode;
dwCode = McastApiStartup(&dwVersion);
// dwVersion now contains the actual version of the C API, but we don't
// really care what it is.
if (dwCode == ERROR_SUCCESS)
{
m_fApiIsInitialized = TRUE;
LOG((MSP_TRACE, "CMDhcp::FinalConstruct - C API version "
"is >= our version - exit S_OK"));
return S_OK;
}
else
{
LOG((MSP_ERROR, "CMDhcp::FinalConstruct - C API version "
"is < our version - exit E_FAIL"));
//
// Now, FinalRelease will get called, and then CoCreate will return
// failure.
//
return E_FAIL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// CMDhcp::FinalRelease
//
// Parameters
// none
//
// Return Values
// none
//
// Description
// This is called on destruction. It releases the free threaded marshaler
// and cleans up the C API instance. Note that it is also called if
// FinalConstruct failed.
//
//////////////////////////////////////////////////////////////////////////////
void CMDhcp::FinalRelease(void)
{
LOG((MSP_TRACE, "CMDhcp::FinalRelease - enter"));
if ( m_pFTM )
{
m_pFTM->Release();
}
if ( m_fApiIsInitialized )
{
McastApiCleanup();
}
LOG((MSP_TRACE, "CMDhcp::FinalRelease - exit"));
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation
//
// This is the main interface for the MDHCP address allocation. An
// application will call CoCreateInstance on this interface to create the
// MDHCP client interface object.
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::get_Scopes
//
// Parameters
// pVariant [out] Pointer to a VARIANT that will receive an OLE-standard
// Collection of available multicast scopes. Each scope
// is an IDispatch pointer to an object that implements
// IMcastScope.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_FAIL There are no scopes available
// E_OUTOFMEMORY Not enough memory to create the required objects
// other From MDhcpEnumerateScopes (win32 call)
//
// Description
// This method is primarily for VB and other scripting languages; C++
// programmers use EnumerateScopes instead.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::get_Scopes(
VARIANT * pVariant
)
{
LOG((MSP_TRACE, "CMDhcp::get_Scopes enter"));
// Check argument.
if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
{
LOG((MSP_ERROR, "get_Scopes: invalid pointer passed in "
"(%08x)", pVariant));
return E_POINTER;
}
DWORD i;
DWORD dwScopeCount = 0;
MCAST_SCOPE_ENTRY * pScopeList = NULL;
HRESULT hr;
BOOL fLocal;
//
// Grab the scopes from the C API.
//
hr = GetScopeList(&dwScopeCount, &pScopeList, &fLocal);
if (FAILED(hr))
{
LOG((MSP_ERROR, "get_Scopes: GetScopeList failed "
"(hr = %08x)", hr));
return hr;
}
//
// Now we wrap the array in COM wrappers.
//
IMcastScope ** ppWrappers = NULL;
// this does a new into ppWrappers
// as well as dwScopeCount individual object instantiations
hr = CreateWrappers(dwScopeCount,
pScopeList,
&ppWrappers,
fLocal);
// At this point we've got a bunch of COM objects that contain
// individual scopes, and so we no longer need the array of
// scopes. Even if CreateWrappers failed we must get rid of
// the array of scopes.
delete pScopeList;
if (FAILED(hr))
{
LOG((MSP_ERROR, "get_Scopes: CreateWrappers failed "
"(hr = %08x)", hr));
return hr;
}
//
// create the collection object - see collect.h
//
typedef CTapiIfCollection< IMcastScope * > ScopeCollection;
CComObject<ScopeCollection> * p;
hr = CComObject<ScopeCollection>::CreateInstance( &p );
if ( (FAILED(hr)) || (p == NULL) )
{
LOG((MSP_ERROR, "get_Scopes: Could not create CTapiIfCollection "
"object - return %lx", hr ));
for (DWORD i = 0 ; i < dwScopeCount; i++) delete ppWrappers[i];
delete ppWrappers;
return hr;
}
//
// get the Collection's IDispatch interface
//
IDispatch * pDisp;
hr = p->_InternalQueryInterface( IID_IDispatch, (void **) &pDisp );
if ( FAILED(hr) )
{
// Query interface failed so we don't know that if it addreffed
// or not.
LOG((MSP_ERROR, "get_Scopes: QI for IDispatch failed on "
"ScopeCollection - %lx", hr ));
delete p;
//
// PREFIXBUG 433295 - VLD
// ppWrappers was allocated into CreateWrappers() method
// we should deallocate it
//
for (DWORD i = 0 ; i < dwScopeCount; i++) delete ppWrappers[i];
delete ppWrappers;
return hr;
}
// initialize it using an iterator -- pointers to the beginning and
// the ending element plus one.
hr = p->Initialize( dwScopeCount,
ppWrappers,
ppWrappers + dwScopeCount );
// ZoltanS fixed:
// We started off by creating and calling QI on each object in
// CreateWrappers. Then we passed the array of pointers to objects to
// the Initialize method of the collection object. This method
// called QI on each object to get each object's IDispatch pointer.
// So now we are at refcount 2. We now Release() each object and get
// back to refcount 1 on each object. Of course we must even do this
// if the initialize failed (in that case to delete them outright).
for (i = 0; i < dwScopeCount; i++)
{
ppWrappers[i]->Release();
}
// The array of pointers must now be deleted -- we now store the
// objects in the collection instead. (or nowhere if initialize failed)
delete ppWrappers;
if (FAILED(hr))
{
// Initialize has failed -- we assume it did nothing, so we must
// release all the COM objects ourselves
LOG((MSP_ERROR, "get_Scopes: Could not initialize "
"ScopeCollection object - return %lx", hr ));
p->Release();
return hr;
}
//
// put the IDispatch interface pointer into the variant
//
LOG((MSP_INFO, "placing IDispatch value %08x in variant", pDisp));
VariantInit(pVariant);
pVariant->vt = VT_DISPATCH;
pVariant->pdispVal = pDisp;
LOG((MSP_TRACE, "CMDhcp::get_Scopes exit - return %lx", hr ));
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::EnumerateScopes
//
// Parameters
// ppEnumMcastScope [out] Returns a pointer to a new IEnumMcastScope
// object. IEnumMcastScope is a standard
// enumerator interface that enumerates
// IMcastScope objects.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_FAIL There are no scopes available
// E_OUTOFMEMORY Not enough memory to create the required objects
// other From MDhcpEnumerateScopes (win32 call)
//
// Description
// This method is primarily for C++ programmers; VB and other scripting
// languages use get_Scopes instead.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::EnumerateScopes(
IEnumMcastScope ** ppEnumMcastScope
)
{
LOG((MSP_TRACE, "CMDhcp::EnumerateScopes enter"));
if ( IsBadWritePtr(ppEnumMcastScope, sizeof(IEnumMcastScope *) ) )
{
LOG((MSP_ERROR, "EnumerateScopes: bad pointer argument "
"(%08x)", ppEnumMcastScope));
return E_POINTER;
}
DWORD dwScopeCount = 0;
MCAST_SCOPE_ENTRY * pScopeList = NULL;
HRESULT hr;
BOOL fLocal;
//
// Grab the scopes from the C API.
//
hr = GetScopeList(&dwScopeCount, &pScopeList, &fLocal);
if (FAILED(hr))
{
LOG((MSP_ERROR, "EnumerateScopes: GetScopeList failed "
"(hr = %08x)", hr));
return hr;
}
//
// Now we wrap the array in COM wrappers.
//
IMcastScope ** ppWrappers = NULL;
// this does a new into ppWrappers
hr = CreateWrappers(dwScopeCount,
pScopeList,
&ppWrappers,
fLocal);
// At this point we've got a bunch of COM objects that contain
// individual scopes, and so we no longer need the array of
// scopes. Even if CreateWrappers failed we must get rid of
// the array of scopes.
delete pScopeList;
if (FAILED(hr))
{
LOG((MSP_ERROR, "EnumerateScopes: CreateWrappers failed "
"(hr = %08x)", hr));
return hr;
}
//
// Now we create and set up the enumerator.
//
typedef _CopyInterface<IMcastScope> CCopy;
typedef CSafeComEnum<IEnumMcastScope, &IID_IEnumMcastScope,
IMcastScope *, CCopy> CEnumerator;
CComObject<CEnumerator> *pEnum = NULL;
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
if ((FAILED(hr)) || (pEnum == NULL))
{
LOG((MSP_ERROR, "Couldn't create enumerator object: %08x", hr));
delete ppWrappers;
return hr;
}
// Get the IEnumMcastScope interface.
hr = pEnum->_InternalQueryInterface(
IID_IEnumMcastScope,
(void **)ppEnumMcastScope
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "QI on enumerator object failed: %08x", hr));
delete ppWrappers;
delete pEnum;
return hr;
}
// This takes ownership of the wrapper list so we will no longer
// delete the wrapper list if this succeeds.
hr = pEnum->Init(ppWrappers, ppWrappers + dwScopeCount, NULL,
AtlFlagTakeOwnership);
if (FAILED(hr))
{
LOG((MSP_ERROR, "Init enumerator object failed: %08x", hr));
delete ppWrappers;
pEnum->Release();
return hr;
}
LOG((MSP_TRACE, "CMDhcp::EnumerateScopes exit"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::RequestAddress
//
// Parameters
// pScope [in] This identifies the multicast scope from which
// the application wants to be given an address.
// The application first calls get_Scopes or
// EnumerateScopes to obtain a list of available
// scopes.
// LeaseStartTime [in] Requested time for the lease on these addresses
// to start / begin. The start time that is
// actually granted may be different.
// LeaseStopTime [in] Requested time for the lease on these addresses
// to stop / end. The stop time that is actually
// granted may be different.
// NumAddresses [in] The number of addresses requested. Fewer
// addresses may actually be granted. NOTE:
// although these COM interfaces and their
// implementation support allocation of multiple
// addresses at a time, this is not currently
// supported by the underlying Win32 calls. You
// may need to use a loop instead.
// ppLeaseResponse [out] Pointer to an interface pointer that will be set
// to point to a new IMcastLeaseInfo object. This
// interface can then be used to discover the
// actual attributes of the granted lease. See
// below for a description of IMcastScope.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_OUTOFMEMORY Not enough memory to create the required objects
// E_INVALIDARG Requested too many addresses, format conversion
// failed for the start time or stop time, or the stop
// time is less than the start time
// other From MdhcpRequestAddress (win32 call)
//
// Description
// Call this method to obtain a new lease for one or more multicast
// addresses. You will first need to call EnumerateScopes or get_Scopes,
// as well as CreateMDhcpRequestID.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::RequestAddress(IMcastScope * pScope,
DATE LeaseStartTime,
DATE LeaseStopTime,
long NumAddresses,
IMcastLeaseInfo ** ppLeaseResponse)
{
LOG((MSP_TRACE, "CMDhcp::RequestAddress enter: asking for %d addresses",
NumAddresses));
if ( IsBadReadPtr( pScope, sizeof(IMcastScope) ) )
{
LOG((MSP_ERROR, "CMDhcp::RequestAddress - "
"bad scope pointer - exit E_POINTER"));
return E_POINTER;
}
// no need to check ppLeaseResponse -- WrapMDhcpLeaseInfo handles it
MCAST_CLIENT_UID requestID;
MCAST_SCOPE_CTX scopeCtx;
MCAST_LEASE_INFO * pLeaseRequest;
HRESULT hr;
BOOL fLocal;
long lTtl;
// Munge input arguments into three structs for passing to the C API.
// pLeaseRequest and requestID->ClientUID are allocated. We must delete them when
// we're done.
hr = PrepareArgumentsRequest(pScope, // goes into scopeCtx
LeaseStartTime, // goes into leaseRequest
LeaseStopTime, // goes into leaseRequest
NumAddresses, // goes into leaseRequest
&requestID, // we generate it
&scopeCtx,
&pLeaseRequest,
&fLocal,
&lTtl
);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CMDHcp::RequestAddress - "
"PrepareArgumentsRequest failed - exit 0x%08x", hr));
return hr;
}
MCAST_LEASE_INFO * pLeaseResponse = (MCAST_LEASE_INFO *) new BYTE
[ sizeof(MCAST_LEASE_INFO) + sizeof(DWORD) * NumAddresses ];
if (pLeaseResponse == NULL)
{
LOG((MSP_ERROR, "RequestAddress: out of memory in response alloc"));
delete requestID.ClientUID;
delete pLeaseRequest;
return E_OUTOFMEMORY;
}
DWORD dwCode;
dwCode = LocalRequestAddress(fLocal,
&requestID,
&scopeCtx,
pLeaseRequest,
pLeaseResponse);
// No matter what, we no longer need this.
delete pLeaseRequest;
if (dwCode != ERROR_SUCCESS)
{
LOG((MSP_ERROR, "RequestAddress: C API call failed "
"(code = %d)", dwCode));
delete requestID.ClientUID;
delete pLeaseResponse;
return HRESULT_FROM_ERROR_CODE(dwCode);
}
// Wrap the lease response, along with the requestID, in an interface
// and return it.
// The wrapper assumes ownership of the lease structure and
// requestID.clientuid.
hr = WrapMDhcpLeaseInfo(TRUE,
lTtl,
fLocal,
pLeaseResponse,
&requestID,
ppLeaseResponse);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "RequestAddress: WrapMDhcpLeaseInfo failed "
"(hr = %08x)", hr));
delete pLeaseResponse;
delete requestID.ClientUID;
return hr;
}
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::RenewAddress
//
// Parameters
// pRenewRequest [in] Pointer to an IMcastLeaseInfo object specifying
// the attributes of the requested renewal, such
// as which address(es) to renew. This is
// obtained by calling CreateLeaseInfo.
// ppRenewResponse [out] Pointer to an interface pointer that will be set
// to point to a new IMcastLeaseInfo object. This
// interface can then be used to discover the
// attributes of the renewed lease. See below for
// a description of IMcastScope.
//
// Return Values
// S_OK Success
// E_OUTOFMEMORY Not enough memory to create the required objects
// E_POINTER The caller passed in an invalid pointer argument
// E_INVALIDARG Start time is greater than stop time
// other From MdhcpRenewAddress (win32 call)
//
// Description
// To renew a lease, call CreateLeaseInfo to specify the parameters of
// the renewal request, and then call this method to make the request.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::RenewAddress(
long lReserved, // unused
IMcastLeaseInfo * pRenewRequest,
IMcastLeaseInfo ** ppRenewResponse
)
{
LOG((MSP_TRACE, "CMDhcp::RenewAddress enter"));
// no need to check pRequestID or pRenewRequest --
// PrepareArgumentsNonRequest handles that.
// ppRenewResponse check handled by WrapMDhcpLeaseInfo
MCAST_CLIENT_UID requestID;
MCAST_LEASE_INFO * pRenewRequestStruct;
HRESULT hr;
BOOL fLocal;
BOOL fGotTtl;
long lTtl;
// Munge input arguments into three structs for passing to the C API.
// pLeaseRequest and requestID->ClientUID are allocated. We must delete them when
// we're done.
hr = PrepareArgumentsNonRequest(pRenewRequest,
&requestID,
&pRenewRequestStruct,
&fLocal,
&fGotTtl,
&lTtl);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "RenewAddress: PrepareArgumentsNonRequest failed "
"(hr = %08x)", hr));
return hr;
}
//
// Check that the start time is less than the stop time
//
if ( pRenewRequestStruct->LeaseStartTime >
pRenewRequestStruct->LeaseEndTime )
{
LOG((MSP_ERROR, "PrepareArgumentsNonRequest - "
"start time %d is greater than stop time %d - exit E_INVALIDARG",
pRenewRequestStruct->LeaseStartTime,
pRenewRequestStruct->LeaseEndTime));
delete requestID.ClientUID;
delete pRenewRequestStruct;
return E_INVALIDARG;
}
MCAST_LEASE_INFO * pRenewResponse = (MCAST_LEASE_INFO *) new BYTE
[ sizeof(MCAST_LEASE_INFO) +
sizeof(DWORD) * pRenewRequestStruct->AddrCount ];
if ( pRenewResponse == NULL )
{
LOG((MSP_ERROR, "RenewAddress: out of memory in response alloc"));
delete requestID.ClientUID;
delete pRenewRequestStruct;
return E_OUTOFMEMORY;
}
DWORD dwCode = LocalRenewAddress(fLocal,
&requestID,
pRenewRequestStruct,
pRenewResponse);
//
// We have performed the renew request so we no longer need the struct
// for the request, even if the request failed.
//
delete pRenewRequestStruct;
if ( dwCode != ERROR_SUCCESS )
{
LOG((MSP_ERROR, "RenewAddress: C API call failed "
"(code = %d)", dwCode));
delete requestID.ClientUID;
delete pRenewResponse;
return HRESULT_FROM_ERROR_CODE(dwCode);
}
//
// Wrap pRenewResponse and the requestID in an interface and return it.
// the wrapper takes ownership of the requestID.clientUID and the
// response struct
//
hr = WrapMDhcpLeaseInfo(fGotTtl,
lTtl,
fLocal,
pRenewResponse,
&requestID,
ppRenewResponse);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "RenewAddress: WrapMDhcpLeaseInfo failed "
"(hr = %08x)", hr));
delete requestID.ClientUID;
delete pRenewResponse;
return hr;
}
LOG((MSP_TRACE, "CMDhcp::RenewAddress exit"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::ReleaseAddress
//
// Parameters
// pReleaseRequest [in] Pointer to an IMcastLeaseInfo object specifying
// the which address(es) to release. This is
// returned from a previous RequestAddress call or
// obtained by calling CreateLeaseInfo.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_OUTOFMEMORY Not enough memory to make the request
// other From MdhcpReleaseAddress (win32 call)
//
// Description
// Use this method to release a lease that was obtained previously.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::ReleaseAddress(
IMcastLeaseInfo * pReleaseRequest
)
{
LOG((MSP_TRACE, "CMDhcp::ReleaseAddress enter"));
// no need to check pReleaseRequest --
// PrepareArgumentsNonRequest handles that.
MCAST_CLIENT_UID requestID;
MCAST_LEASE_INFO * pReleaseRequestStruct;
HRESULT hr;
BOOL fLocal;
BOOL fGotTtl; // unused after call
long lTtl; // unused after call
hr = PrepareArgumentsNonRequest(pReleaseRequest,
&requestID,
&pReleaseRequestStruct,
&fLocal,
&fGotTtl,
&lTtl
);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "ReleaseAddress: PrepareArgumentsNonRequest failed "
"(hr = %08x)", hr));
return hr;
}
DWORD dwCode;
dwCode = LocalReleaseAddress(fLocal,
&requestID,
pReleaseRequestStruct);
//
// These were allocated by PrepareArgumentsNonRequest and there is no one
// to own them now -- we delete them. This is true even if the
// LocalReleaseAddress call failed.
//
delete pReleaseRequestStruct;
delete requestID.ClientUID;
if ( dwCode != ERROR_SUCCESS )
{
LOG((MSP_ERROR, "ReleaseAddress: C API call failed "
"(code = %d)", dwCode));
return HRESULT_FROM_ERROR_CODE(dwCode);
}
LOG((MSP_TRACE, "CMDhcp::ReleaseAddress exit"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::CreateLeaseInfo
//
// Parameters
// LeaseStartTime [in] The start time of the lease.
// LeaseStopTime [in] The stop time of the lease.
// dwNumAddresses [in] The number of addresses associated with the
// lease.
// ppAddresses [in] An array of LPWSTRs of size dwNumAddresses. Each
// LPWSTR (Unicode string pointer) is an IPv4
// address in "dot-quad" notation; e.g.
// "123.234.12.17".
// pRequestID [in] An LPWSTR (Unicode string pointer) specifying
// the request ID for the original request.
// pServerAddress [in] An LPWSTR (Unicode string pointer) specifying
// the address of the server that granted the
// original request. This address is an IPv4
// address in "dot quad" notation; e.g.
// "123.234.12.17".
// ppReleaseRequest [out] Returns a pointer to the IMcastLeaseInfo
// interface on the newly created lease
// information object.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_OUTOFMEMORY Not enough memory to create the required objects
// E_INVALIDARG An error occured during the date format conversion
//
// Description
// Use this method to create a lease information object for a subsequent
// RenewAddress or ReleaseAddress call. This method is primarily for C++
// programmers; VB and other scripting languages use
// CreateLeaseInfoFromVariant instead.
// The dwNumAddresses, ppAddresses, pRequestID, and pServerAddress
// parameters are normally obtained by calling the corresponding
// IMcastLeaseInfo methods on the lease info object corresponding to the
// original request. These values should be saved in persistent storage
// between executions of the application program. If you are renewing or
// releasing a lease that was requested during the same run of the
// application, you have no reason to use CreateLeaseInfo; just pass the
// existing IMcastLeaseInfo pointer to RenewAddress or ReleaseAddress.
//////////////////////////////////////////////////////////////////////////////
#include <atlwin.cpp>
STDMETHODIMP CMDhcp::CreateLeaseInfo(
DATE LeaseStartTime,
DATE LeaseStopTime,
DWORD dwNumAddresses,
LPWSTR * ppAddresses,
LPWSTR pRequestID,
LPWSTR pServerAddress,
IMcastLeaseInfo ** ppReleaseRequest
)
{
LOG((MSP_TRACE, "CMDhcp::CreateLeaseInfo enter"));
if ( IsBadWritePtr(ppReleaseRequest, sizeof(IMcastLeaseInfo *) ) )
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfo - "
"invalid lease return pointer: 0x%08x - exit E_POINTER",
ppReleaseRequest));
return E_POINTER;
}
if ( IsBadStringPtr(pRequestID, (UINT) -1 ) )
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfo - "
"invalid RequestID pointer: 0x%08x - exit E_POINTER",
pRequestID));
return E_POINTER;
}
if ( ( dwNumAddresses < 1 ) || ( dwNumAddresses > USHRT_MAX ) )
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfo - "
"invalid number of addresses: %d - exit E_INVALIDARG",
dwNumAddresses));
return E_INVALIDARG;
}
if (IsBadReadPtr(ppAddresses, sizeof(LPWSTR) * dwNumAddresses) )
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfo - "
"invalid addresses array pointer: 0x%08x - exit E_POINTER",
ppAddresses));
return E_POINTER;
}
if ( IsBadStringPtr(pServerAddress, (UINT) -1 ) )
{
LOG((MSP_ERROR, "CreateLeaseInfo: invalid Server Address pointer: %08x",
pRequestID));
return E_POINTER;
}
HRESULT hr;
// create the com object.
CComObject<CMDhcpLeaseInfo> * pMDhcpLeaseInfo;
hr = CComObject<CMDhcpLeaseInfo>::CreateInstance(&pMDhcpLeaseInfo);
if ( (FAILED(hr)) || (pMDhcpLeaseInfo == NULL) )
{
LOG((MSP_ERROR, "CreateLeaseInfo: can't create MDhcpLeaseInfo Object."));
return hr;
}
// Get the IMcastLeaseInfo interface.
hr = pMDhcpLeaseInfo->_InternalQueryInterface(
IID_IMcastLeaseInfo,
(void **)ppReleaseRequest
);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateLeaseInfo: QueryInterface failed: %x", hr));
delete pMDhcpLeaseInfo;
return hr;
}
// Fill in the object with the stuff the user wanted.
hr = pMDhcpLeaseInfo->Initialize(LeaseStartTime,
LeaseStopTime,
dwNumAddresses,
ppAddresses,
pRequestID,
pServerAddress);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CreateLeaseInfo: Initialize failed: %x", hr));
delete pMDhcpLeaseInfo;
return hr;
}
LOG((MSP_TRACE, "CMDhcp::CreateLeaseInfo exit"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// IMcastAddressAllocation::CreateLeaseInfoFromVariant
//
// Parameters
// LeaseStartTime [in] The start time of the lease.
// LeaseStopTime [in] The stop time of the lease.
// vAddresses [in] A VARIANT containing a SafeArray of BSTRs. Each
// BSTR (size-tagged Unicode string pointer) is
// an IPv4 address in "dot-quad" notation; e.g.
// "123.234.12.17".
// pRequestID [in] A BSTR (size-tagged Unicode string pointer)
// specifying the request ID for the original
// request.
// pServerAddress [in] A BSTR (size-tagged Unicode string pointer)
// specifying the address of the server that
// granted the original request. This address is
// an IPv4 address in "dot quad" notation; e.g.
// "123.234.12.17".
// ppReleaseRequest [out] Returns a pointer to the IMcastLeaseInfo
// interface on the newly created lease
// information object.
//
// Return Values
// S_OK Success
// E_POINTER The caller passed in an invalid pointer argument
// E_OUTOFMEMORY Not enough memory to create the required objects
// E_INVALIDARG An error occured during the date format conversion
//
// Description
// Use this method to create a lease information object for a subsequent
// RenewAddress or ReleaseAddress call. This method is primarily for VB
// and other scripting languages; C++ programmers should use
// CreateLeaseInfo instead.
// The dwNumAddresses, ppAddresses, pRequestID, and pServerAddress
// parameters are normally obtained by calling the corresponding
// IMcastLeaseInfo methods on the lease info object corresponding to the
// original request. These values should be saved in persistent storage
// between executions of the application program. If you are renewing or
// releasing a lease that was requested during the same run of the
// application, you have no reason to use CreateLeaseInfoFromVariant; just
// pass the existing IMcastLeaseInfo pointer to RenewAddress or
// ReleaseAddress.
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CMDhcp::CreateLeaseInfoFromVariant(
DATE LeaseStartTime,
DATE LeaseStopTime,
VARIANT vAddresses,
BSTR pRequestID,
BSTR pServerAddress,
IMcastLeaseInfo ** ppReleaseRequest
)
{
LOG((MSP_TRACE, "CMDhcp::CreateLeaseInfoFromVariant enter"));
// We will check the pointers in CreateLeaseInfo.
HRESULT hr;
// Get from the variant:
DWORD dwNumAddresses;
LPWSTR * ppAddresses;
SAFEARRAY * psaAddresses = NULL; // SafeArray with the addresses
long lLowerBound = 0; // lower bound of safearray
long lUpperBound = 0; // upper bound of safearray
hr = VerifyAndGetArrayBounds(
vAddresses,
&psaAddresses,
&lLowerBound,
&lUpperBound);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfoFromVariant: invalid "
"VARIANT"));
return E_INVALIDARG;
}
// This is how many addresses we *expect* (may have fewer).
long lAddrCount = lUpperBound - lLowerBound + 1;
if (lAddrCount < 1)
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfoFromVariant: too few "
"addresses (check #1) (%d)", lAddrCount));
return E_INVALIDARG;
}
// We allocate as many as we are told to expect, but some of this
// space may end up getting "wasted" if there are fewer valid ones
// after all.
ppAddresses = new LPWSTR[lAddrCount];
if (ppAddresses == NULL)
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfoFromVariant: "
"out of memory in array allocation"));
return E_OUTOFMEMORY;
}
long lCurrSrc; // the current element in the safearray (source)
long lCurrDest = 0; // the current element in the struct's array (destination)
// Get the addresses from the SafeArray and put them in our array.
for (lCurrSrc = lLowerBound; lCurrSrc <= lUpperBound; lCurrSrc++)
{
hr = SafeArrayGetElement(
psaAddresses,
&lCurrSrc,
& ( ppAddresses[lCurrDest] )
);
if ( FAILED(hr) )
{
LOG((MSP_INFO, "CMDhcp::CreateLeaseInfoFromVariant: "
"failed to get safearray element %d"
" - skipping (array range %d-%d)",
lCurrSrc, lLowerBound, lUpperBound));
}
else if ( ppAddresses[lCurrDest] == 0 )
{
LOG((MSP_INFO, "CMDhcp::CreateLeaseInfoFromVariant: "
"got ZERO address from safearray "
"element %d - skipping (array range %d-%d)",
lCurrSrc, lLowerBound, lUpperBound));
}
else
{
// We got an element.
lCurrDest++;
}
}
// note the number of addresses we actually placed in the array
dwNumAddresses = (DWORD) lCurrDest;
if (dwNumAddresses < 1)
{
LOG((MSP_ERROR, "CMDhcp::CreateLeaseInfoFromVariant: "
"too few addresses (check #2)"
"(%d)", lAddrCount));
delete ppAddresses;
return E_INVALIDARG;
}
hr = CreateLeaseInfo(LeaseStartTime,
LeaseStopTime,
dwNumAddresses,
ppAddresses,
pRequestID,
pServerAddress,
ppReleaseRequest
);
// No matter what, we no longer need this.
delete ppAddresses;
if (FAILED(hr))
{
LOG((MSP_TRACE, "CMDhcp::CreateLeaseInfoFromVariant : "
"CreateLeaseInfo returned %08x", hr));
return hr;
}
LOG((MSP_TRACE, "CMDhcp::CreateLeaseInfoFromVariant exit"));
return S_OK;
}
// eof