You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1919 lines
60 KiB
1919 lines
60 KiB
/*
|
|
|
|
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
|