1334 lines
40 KiB
C++
1334 lines
40 KiB
C++
/*
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
lease.cpp
|
|
|
|
Abstract:
|
|
Implementation of CMDhcpLeaseInfo.
|
|
|
|
Author:
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "mdhcp.h"
|
|
#include "lease.h"
|
|
#include "collect.h"
|
|
|
|
#include <winsock2.h>
|
|
#include <time.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Convert an OLE DATE (64-bit floating point) to the time format used in
|
|
// an MDHCP lease info structure (currently time_t).
|
|
|
|
HRESULT DateToLeaseTime(DATE date, LONG * pLeaseTime)
|
|
{
|
|
//
|
|
// Note:
|
|
//
|
|
// pLeaseTime is intentionally a pointer to LONG instead of a pointer to
|
|
// time_t. This is because this function is used to convert 32-bit time
|
|
// values that are sent over the wire.
|
|
//
|
|
|
|
LOG((MSP_TRACE, "DateToLeaseTime: enter"));
|
|
|
|
if ( IsBadWritePtr(pLeaseTime, sizeof(LONG)) )
|
|
{
|
|
LOG((MSP_ERROR, "DateToLeaseTime: invalid pLeaseTime pointer "
|
|
"(ptr = %p)", pLeaseTime));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Step one: convert variant time to system time.
|
|
//
|
|
|
|
SYSTEMTIME systemTime;
|
|
time_t scratchTime;
|
|
|
|
// This is TRUE or FALE, not a Win32 result code.
|
|
INT iCode;
|
|
|
|
iCode = VariantTimeToSystemTime(date, &systemTime);
|
|
|
|
if (iCode == 0)
|
|
{
|
|
LOG((MSP_ERROR, "DateToLeaseTime: VariantTimeToSystemTime call failed "
|
|
"(code = %d)", iCode));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Step two: Convert system time to time_t.
|
|
//
|
|
|
|
tm Tm;
|
|
|
|
Tm.tm_year = (int) systemTime.wYear - 1900;
|
|
Tm.tm_mon = (int) systemTime.wMonth - 1;
|
|
Tm.tm_mday = (int) systemTime.wDay;
|
|
Tm.tm_wday = (int) systemTime.wDayOfWeek;
|
|
Tm.tm_hour = (int) systemTime.wHour;
|
|
Tm.tm_min = (int) systemTime.wMinute;
|
|
Tm.tm_sec = (int) systemTime.wSecond;
|
|
Tm.tm_isdst = -1; // ask win32 to compute DST for us (crucial!)
|
|
// not filled in: Tm.tm_yday;
|
|
|
|
scratchTime = mktime(&Tm);
|
|
if ( scratchTime == -1 )
|
|
{
|
|
LOG((MSP_ERROR, "DateToLeaseTime: mktime call failed "));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Now truncate scratchTime and store in out param. This will be
|
|
// truncated in 2038.
|
|
//
|
|
|
|
*pLeaseTime = (LONG)scratchTime;
|
|
|
|
|
|
LOG((MSP_TRACE, "DateToLeaseTime: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Convert to an OLE DATE structure from a time_t (which is what the MDHCP
|
|
// lease info structure now uses).
|
|
|
|
HRESULT LeaseTimeToDate(time_t leaseTime, DATE * pDate)
|
|
{
|
|
LOG((MSP_TRACE, "LeaseTimeToDate: enter"));
|
|
|
|
if ( IsBadWritePtr(pDate, sizeof(DATE)) )
|
|
{
|
|
LOG((MSP_ERROR, "LeaseTimeToDate: invalid pDate pointer "
|
|
"(ptr = %08x)", pDate));
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Step one: Convert the time_t to a system time.
|
|
//
|
|
|
|
// get the tm struct for this time value
|
|
tm * pTm = localtime(&leaseTime);
|
|
|
|
if (pTm == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "LeaseTimeToDate: localtime call failed - "
|
|
"exit E_INVALIDARG"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
SYSTEMTIME systemTime;
|
|
|
|
// set the ref parameters to the tm struct values
|
|
systemTime.wYear = (WORD) pTm->tm_year + 1900; // years since 1900
|
|
systemTime.wMonth = (WORD) pTm->tm_mon + 1; // months SINCE january (0,11)
|
|
systemTime.wDay = (WORD) pTm->tm_mday;
|
|
systemTime.wDayOfWeek = (WORD) pTm->tm_wday;
|
|
systemTime.wHour = (WORD) pTm->tm_hour;
|
|
systemTime.wMinute = (WORD) pTm->tm_min;
|
|
systemTime.wSecond = (WORD) pTm->tm_sec;
|
|
systemTime.wMilliseconds = 0;
|
|
|
|
//
|
|
// Step 2: Convert the system time to a variant time.
|
|
//
|
|
|
|
int iCode = SystemTimeToVariantTime(&systemTime, pDate);
|
|
|
|
if (iCode == 0)
|
|
{
|
|
LOG((MSP_ERROR, "LeaseTimeToDate: SystemToVariantTime call failed "
|
|
"(code = %d)", iCode));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "LeaseTimeToDate: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Now for the CMDhcpLeaseInfo class.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Constructors.
|
|
|
|
CMDhcpLeaseInfo::CMDhcpLeaseInfo(void) :
|
|
m_pLease(NULL),
|
|
m_fGotTtl(FALSE),
|
|
m_lTtl(0),
|
|
m_pFTM(NULL),
|
|
m_fLocal(FALSE)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo constructor: enter"));
|
|
|
|
m_RequestID.ClientUID = NULL;
|
|
m_RequestID.ClientUIDLength = 0;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo constructor: exit"));
|
|
}
|
|
|
|
HRESULT CMDhcpLeaseInfo::FinalConstruct(void)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::FinalConstruct: enter"));
|
|
|
|
HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
|
|
& m_pFTM );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::FinalConstruct: "
|
|
"create FTM failed 0x%08x", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
hr = m_CriticalSection.Initialize();
|
|
if( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::FinalConstruct: "
|
|
"critical section initialize failed 0x%08x", hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::FinalConstruct: exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Destructors.
|
|
|
|
void CMDhcpLeaseInfo::FinalRelease(void)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::FinalRelease: enter"));
|
|
|
|
delete m_pLease;
|
|
|
|
delete m_RequestID.ClientUID;
|
|
|
|
if ( m_pFTM )
|
|
{
|
|
m_pFTM->Release();
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::FinalRelease: exit"));
|
|
}
|
|
|
|
CMDhcpLeaseInfo::~CMDhcpLeaseInfo(void)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo destructor: enter"));
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo destructor: exit"));
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The simplest way to initialize our structure. This happens when the C API
|
|
// returns a pointer to an MCAST_LEASE_INFO and we want to return our wrapped
|
|
// interface to the user of our COM API, along with the MCAST_CLIENT_UID
|
|
// (request ID) that was used.
|
|
//
|
|
// The MCAST_LEASE_INFO that we're pointing to was created by a COM method in
|
|
// IMcastAddressAllocation... it was created via "new" according to the number of addresses
|
|
// we expected to get back. We now take ownership of it and it will be deleted
|
|
// when we are destroyed. Since this method is not accessible via COM, we trust
|
|
// our own IMcastAddressAllocation implementation to do the allocation for us. However we still
|
|
// do asserts for debug builds.
|
|
//
|
|
// We also take ownership of the RequestID; we are responsible for deleting it
|
|
// upon our destruction.
|
|
//
|
|
|
|
HRESULT CMDhcpLeaseInfo::Wrap(
|
|
MCAST_LEASE_INFO * pLease,
|
|
MCAST_CLIENT_UID * pRequestID,
|
|
BOOL fGotTtl,
|
|
long lTtl
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::Wrap: enter"));
|
|
|
|
_ASSERTE( ! IsBadReadPtr(pLease, sizeof(MCAST_LEASE_INFO)) );
|
|
_ASSERTE( ! IsBadReadPtr(pLease, sizeof(MCAST_LEASE_INFO) +
|
|
(pLease->AddrCount - 1) * sizeof(DWORD)) );
|
|
_ASSERTE( ! IsBadWritePtr(pLease, sizeof(MCAST_LEASE_INFO) +
|
|
(pLease->AddrCount - 1) * sizeof(DWORD)) );
|
|
|
|
_ASSERTE( ! IsBadReadPtr(pRequestID, sizeof(MCAST_CLIENT_UID)) );
|
|
_ASSERTE( pRequestID->ClientUIDLength == MCAST_CLIENT_ID_LEN );
|
|
_ASSERTE( ! IsBadReadPtr(pRequestID->ClientUID,
|
|
pRequestID->ClientUIDLength) );
|
|
|
|
//
|
|
// Takes ownership of the following dynamically-allocated items:
|
|
// * lease info
|
|
// * requestId.clientUID.
|
|
//
|
|
|
|
m_fGotTtl = fGotTtl;
|
|
m_lTtl = lTtl;
|
|
m_pLease = pLease;
|
|
m_RequestID = *pRequestID;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::Wrap: exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Allocate a variable-sized MCAST_LEASE_INFO structure, copy our structure
|
|
// into it, and return a pointer to the new structure.
|
|
|
|
HRESULT CMDhcpLeaseInfo::GetStruct(MCAST_LEASE_INFO ** ppLease)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetStruct: enter"));
|
|
|
|
if ( IsBadWritePtr(ppLease, sizeof(MCAST_LEASE_INFO *)) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::GetStruct: bad pointer passed in"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Compute the size of the existing structure.
|
|
//
|
|
|
|
DWORD dwSize = sizeof(MCAST_LEASE_INFO) +
|
|
m_pLease->AddrCount * sizeof(DWORD);
|
|
|
|
//
|
|
// New an appropriately-sized struct. The caller will delete it after
|
|
// the API call.
|
|
//
|
|
|
|
(*ppLease) = (MCAST_LEASE_INFO *) new BYTE[dwSize];
|
|
|
|
if ((*ppLease) == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "GetStruct: out of memory in "
|
|
"MCAST_LEASE_INFO allocation"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
//
|
|
// Copy to the new structure.
|
|
//
|
|
|
|
CopyMemory(*ppLease, m_pLease, dwSize);
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetStruct: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Initialize the fields of the structure. This is the case where the user
|
|
// has called IMcastAddressAllocation::CreateLeaseInfo and intends to do a renew or release
|
|
// right after this.
|
|
//
|
|
// Note: the addresses are in NETWORK byte order and remain so.
|
|
//
|
|
|
|
HRESULT CMDhcpLeaseInfo::Initialize(DATE LeaseStartTime,
|
|
DATE LeaseStopTime,
|
|
DWORD dwNumAddresses,
|
|
LPWSTR * ppAddresses,
|
|
LPWSTR pRequestID,
|
|
LPWSTR pServerAddress)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::Initialize (create): enter"));
|
|
|
|
// For ATL string type conversion macros.
|
|
USES_CONVERSION;
|
|
|
|
// These should already have been checked by CreateLeaseInfo
|
|
_ASSERTE( dwNumAddresses >= 1 );
|
|
_ASSERTE( dwNumAddresses <= USHRT_MAX );
|
|
_ASSERTE( ! IsBadReadPtr (ppAddresses, sizeof(LPWSTR) * dwNumAddresses) );
|
|
_ASSERTE( ! IsBadStringPtr(pRequestID, (UINT) -1 ) );
|
|
_ASSERTE( ! IsBadStringPtr(pServerAddress, (UINT) -1 ) );
|
|
|
|
// Let's check all the addresses here before we get too deep into this...
|
|
DWORD i;
|
|
for ( i = 0; i < dwNumAddresses; i++ )
|
|
{
|
|
if ( IsBadStringPtr(ppAddresses[i], (UINT) -1 ) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::Initialize (create): bad "
|
|
"string pointer found"));
|
|
return E_POINTER;
|
|
}
|
|
}
|
|
|
|
// Set the request ID via a private method. No need to check pRequestID --
|
|
// this checks it for us. (It's no problem that it's not really a BSTR,
|
|
// because we don't use the size tag anywhere.)
|
|
|
|
HRESULT hr = put_RequestID(pRequestID);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "Initialize: failed to set RequestID"));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// Allocate space for as many addresses as needed.
|
|
// NOTE: If we fail from here on, we DO NOT need to delete this buffer,
|
|
// because returning a failure from this function will cause the whole
|
|
// CMDhcpLeaseInfo to be deleted, which will cause m_pLease to be deleted.
|
|
|
|
m_pLease = (MCAST_LEASE_INFO *) new BYTE
|
|
[ sizeof(MCAST_LEASE_INFO) + sizeof(DWORD) * dwNumAddresses ];
|
|
|
|
if (m_pLease == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "Initialize: out of memory in struct allocation"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
// note the number of addresses in the structure
|
|
m_pLease->AddrCount = (WORD) dwNumAddresses;
|
|
|
|
m_pLease->pAddrBuf = ( (PBYTE) m_pLease ) + sizeof( MCAST_LEASE_INFO );
|
|
|
|
// note: assumes ipv4
|
|
DWORD * pdwAddresses = (DWORD *) m_pLease->pAddrBuf;
|
|
|
|
// Get the addresses from the array and put them in our structure.
|
|
for (i = 0; i < dwNumAddresses; i++)
|
|
{
|
|
// we already checked the BSTR
|
|
pdwAddresses[i] = inet_addr(W2A(ppAddresses[i]));
|
|
}
|
|
|
|
hr = DateToLeaseTime(LeaseStartTime, &(m_pLease->LeaseStartTime));
|
|
if (FAILED(hr)) return hr;
|
|
|
|
hr = DateToLeaseTime(LeaseStopTime, &(m_pLease->LeaseEndTime));
|
|
if (FAILED(hr)) return hr;
|
|
|
|
//
|
|
// We don't know the TTL. Leave it alone.
|
|
//
|
|
|
|
//
|
|
// Set the server address. If the server addess is 127.0.0.1
|
|
// (in net byte order) then mark this as a local lease.
|
|
//
|
|
|
|
m_pLease->ServerAddress.IpAddrV4 = inet_addr(W2A(pServerAddress));
|
|
|
|
SetLocal( m_pLease->ServerAddress.IpAddrV4 == 0x0100007f );
|
|
|
|
//
|
|
// All done...
|
|
//
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::Initialize (create): exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// This is a small helper function to print an IP address to a Unicode string.
|
|
// We can't use inet_ntoa because we need Unicode.
|
|
|
|
static inline void ipAddressToStringW(WCHAR * wszDest, DWORD dwAddress)
|
|
{
|
|
// The IP address is always stored in NETWORK byte order.
|
|
// So we need to take something like 0x0100007f and produce a string like
|
|
// "127.0.0.1".
|
|
|
|
wsprintf(wszDest, L"%d.%d.%d.%d",
|
|
dwAddress & 0xff,
|
|
(dwAddress >> 8) & 0xff,
|
|
(dwAddress >> 16) & 0xff,
|
|
dwAddress >> 24 );
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Private helper funciton to make an array of BSTRs from our array of
|
|
// DWORD addresses.
|
|
//
|
|
|
|
HRESULT CMDhcpLeaseInfo::MakeBstrArray(BSTR ** ppbszArray)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::MakeBstrArray: enter"));
|
|
|
|
if ( IsBadWritePtr(ppbszArray, sizeof(BSTR *)) )
|
|
{
|
|
LOG((MSP_ERROR, "MakeBstrArray: invalid pointer argument passed in"));
|
|
return E_POINTER;
|
|
}
|
|
|
|
*ppbszArray = new BSTR[m_pLease->AddrCount];
|
|
|
|
if ( (*ppbszArray) == NULL)
|
|
{
|
|
LOG((MSP_ERROR, "MakeBstrArray: out of memory in array allocation"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
WCHAR wszBuffer[100]; // quite big enough for this
|
|
|
|
for (DWORD i = 0 ; i < m_pLease->AddrCount; i++)
|
|
{
|
|
// note: we do not support ipv6
|
|
ipAddressToStringW( wszBuffer, ((DWORD *) m_pLease->pAddrBuf)[i] );
|
|
|
|
(*ppbszArray)[i] = SysAllocString(wszBuffer);
|
|
|
|
if ( (*ppbszArray)[i] == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "MakeBstrArray: out of memory in string allocation"));
|
|
|
|
for ( DWORD j = 0; j < i; j++ )
|
|
{
|
|
SysFreeString((*ppbszArray)[j]);
|
|
}
|
|
|
|
delete (*ppbszArray);
|
|
*ppbszArray = NULL;
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::MakeBstrArray: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Private helper method
|
|
// CMDhcpLeaseInfo::GetRequestIDBuffer
|
|
//
|
|
// Parameters
|
|
// lBufferSize [in] This argument indicates the size of the buffer
|
|
// pointed to by pBuffer.
|
|
// pBuffer [in, out] This argument points to a buffer that the caller
|
|
// has allocated, of size lBufferSize. This
|
|
// buffer will be filled with a copy of the
|
|
// unique identifier.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_INVALIDARG The supplied buffer is too small
|
|
//
|
|
// Description
|
|
// Use this method to obtain a copy of the unique identifier.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CMDhcpLeaseInfo::GetRequestIDBuffer(
|
|
long lBufferSize,
|
|
BYTE * pBuffer
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetRequestIDBuffer: enter"));
|
|
|
|
//
|
|
// Check return pointer.
|
|
//
|
|
|
|
if ( IsBadWritePtr(pBuffer, lBufferSize) )
|
|
{
|
|
LOG((MSP_ERROR, "requestID GetRequestIDBuffer: bad pointer passed in"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Check that the caller has enough space to grab the entire client id.
|
|
//
|
|
|
|
if ( lBufferSize < MCAST_CLIENT_ID_LEN )
|
|
{
|
|
LOG((MSP_ERROR, "requestID GetRequestIDBuffer: specified buffer too small"));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Copy the info to the caller's buffer.
|
|
//
|
|
|
|
m_CriticalSection.Lock();
|
|
|
|
CopyMemory( pBuffer, m_RequestID.ClientUID, MCAST_CLIENT_ID_LEN );
|
|
|
|
m_CriticalSection.Unlock();
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetRequestIDBuffer: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
BYTE HexDigitValue( WCHAR c )
|
|
{
|
|
_ASSERTE( iswxdigit(c) );
|
|
|
|
c = towlower(c);
|
|
|
|
if ( ( c >= L'0' ) && ( c <= L'9' ) )
|
|
{
|
|
return c - L'0';
|
|
}
|
|
else
|
|
{
|
|
return c - L'a' + 10;
|
|
}
|
|
}
|
|
|
|
HRESULT CMDhcpLeaseInfo::put_RequestID(
|
|
BSTR bszGuid
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_RequestID: enter"));
|
|
|
|
// (UINT) -1 is as big a value as we can give it -- we don't want any
|
|
// limitation on the number of characters it checks.
|
|
if ( IsBadStringPtr(bszGuid, (UINT) -1 ) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::put_RequestID: "
|
|
"bad BSTR; fail"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Determine the byte buffer we need to set based on the string.
|
|
// The string should be MCAST_CLIENT_ID_LEN * 2 characters long;
|
|
// each byte is represented by two hexadecimal digits, starting
|
|
// with the most significant byte.
|
|
//
|
|
// Note that this format is intentionally not specified in the interface
|
|
// spec; the client should not depend on the specific format. The format
|
|
// we happen to use is convenient because it's printable, contains no
|
|
// spaces, and is easy to generate and parse.
|
|
//
|
|
|
|
if ( lstrlenW( bszGuid ) < 2 * MCAST_CLIENT_ID_LEN )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::put_RequestID - "
|
|
"string is only %d characters long; "
|
|
"we require at least %d characters - exit E_INVALIDARG",
|
|
lstrlenW( bszGuid ), 2 * MCAST_CLIENT_ID_LEN));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
BYTE NewUID [ MCAST_CLIENT_ID_LEN ];
|
|
|
|
for ( DWORD i = 0; i < MCAST_CLIENT_ID_LEN; i++ )
|
|
{
|
|
if ( ( ! iswxdigit( bszGuid[ 2 * i ] ) ) ||
|
|
( ! iswxdigit( bszGuid[ 2 * i + 1 ] ) ) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::put_RequestID - "
|
|
"invalid value for byte %d / %d - exit E_INVALIDARG",
|
|
i + 1, MCAST_CLIENT_ID_LEN ));
|
|
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Compute value of byte based on corresponding hex digits in string.
|
|
//
|
|
|
|
NewUID[ i ] = ( ( HexDigitValue( bszGuid[ 2 * i ] ) ) << 4 ) +
|
|
HexDigitValue( bszGuid[ 2 * i + 1 ] );
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize the request id structure accordingly.
|
|
// We do this only during initialization, so there is no need to
|
|
// use the critical section.
|
|
//
|
|
// We could have just used this new'ed buffer above and avoided the
|
|
// copy, but this makes the code a bit more straightforward as we
|
|
// don't have to worry about cleaning up the allocation if something's
|
|
// wrong with the string. No one will notice the overhead.
|
|
//
|
|
|
|
m_RequestID.ClientUIDLength = MCAST_CLIENT_ID_LEN;
|
|
m_RequestID.ClientUID = new BYTE[ MCAST_CLIENT_ID_LEN ];
|
|
|
|
if ( m_RequestID.ClientUID == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::put_RequestID - "
|
|
"buffer allocation failed - exit E_OUTOFMEMORY"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
CopyMemory(m_RequestID.ClientUID,
|
|
NewUID,
|
|
MCAST_CLIENT_ID_LEN
|
|
);
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_RequestID - exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo
|
|
//
|
|
// This interface can be obtained by calling IMcastAddressAllocation::CreateLeaseInfo. This
|
|
// interface can also be obtained as the result of an IMcastAddressAllocation::RequestAddress
|
|
// or IMcastAddressAllocation::RenewAddress call, in which case it indicates the properties of
|
|
// a lease that has been granted or renewed. This is a "read-only" interface
|
|
// in that it has "get" methods but no "put" methods.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_RequestID
|
|
//
|
|
// Parameters
|
|
// ppRequestID [out] Pointer to a BSTR (size-tagged Unicode string
|
|
// pointer) that will receive the request ID for this
|
|
// lease. The request ID uniquely identifies this
|
|
// lease request to the server. The string is
|
|
// allocated using SysAllocString(); when the caller
|
|
// no longer needs the string, it should free it using
|
|
// SysFreeString().
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_FAIL The lease info object contains an invalid request ID
|
|
// E_OUTOFMEMORY Not enough memory to allocate the BSTR
|
|
//
|
|
// Description
|
|
// Use this method to obtain the request ID for a lease. The primary
|
|
// purpose of this method is to allow you to save the request ID after
|
|
// your application exits, so that you can call IMcastAddressAllocation::CreateLeaseInfo to
|
|
// recreate the lease info object during a subsequent run. This allows you
|
|
// to renew or release a lease after the instance of your program that
|
|
// originally requested the lease has exited.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_RequestID(
|
|
BSTR * pbszGuid
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_RequestID: enter"));
|
|
|
|
//
|
|
// Check the return pointer.
|
|
//
|
|
|
|
if ( IsBadWritePtr(pbszGuid, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::get_RequestID: "
|
|
"bad BSTR pointer; fail"));
|
|
|
|
return E_POINTER;
|
|
}
|
|
|
|
//
|
|
// Construct the string; 2 characters of string space per byte of
|
|
// request ID space, plus trailing L'\0'.
|
|
//
|
|
|
|
WCHAR wszBuffer[ 2 * MCAST_CLIENT_ID_LEN + 1 ] = L"";
|
|
|
|
WCHAR wszThisByte[ 3 ]; // string representation of one byte plus space
|
|
|
|
m_CriticalSection.Lock();
|
|
|
|
for ( DWORD i = 0; i < MCAST_CLIENT_ID_LEN; i++ )
|
|
{
|
|
swprintf( wszThisByte, L"%02x", m_RequestID.ClientUID[i] );
|
|
|
|
lstrcatW( wszBuffer, wszThisByte );
|
|
}
|
|
|
|
m_CriticalSection.Unlock();
|
|
|
|
//
|
|
// Allocate a BSTR and return it.
|
|
//
|
|
|
|
*pbszGuid = SysAllocString(wszBuffer);
|
|
|
|
if ( (*pbszGuid) == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "CMDhcpLeaseInfo::get_RequestID: "
|
|
"failed to SysAllocString - exit E_OUTOFMEMORY"));
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_RequestID: exit"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_LeaseStartTime
|
|
//
|
|
// Parameters
|
|
// pTime [out] Pointer to a DATE that will receive the start time of the
|
|
// lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_INVALIDARG A failure occurred during date format conversion
|
|
//
|
|
// Description
|
|
// Use this method to obtain the start time of the lease.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_LeaseStartTime(
|
|
DATE *pTime
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_LeaseStartTime: enter"));
|
|
|
|
m_CriticalSection.Lock();
|
|
HRESULT hr = LeaseTimeToDate(m_pLease->LeaseStartTime, pTime);
|
|
m_CriticalSection.Unlock();
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_LeaseStartTime: exit; hr = %08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::put_LeaseStartTime
|
|
//
|
|
// Parameters
|
|
// time [in] A DATE specifying the start time of the lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_INVALIDARG A failure occurred during date format conversion
|
|
//
|
|
// Description
|
|
// Use this method to set the start time of the lease. This method, along
|
|
// with put_LeaseStopTime, allows you to renew a lease without calling
|
|
// IMcastAddressAllocation::CreateLeaseInfo.
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::put_LeaseStartTime(
|
|
DATE time
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_LeaseStartTime: enter"));
|
|
|
|
m_CriticalSection.Lock();
|
|
HRESULT hr = DateToLeaseTime(time, &(m_pLease->LeaseStartTime));
|
|
m_CriticalSection.Unlock();
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_LeaseStartTime: exit; hr = %08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_LeaseStopTime
|
|
//
|
|
// Parameters
|
|
// pTime [out] Pointer to a DATE that will receive the stop time of the
|
|
// lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_INVALIDARG A failure occurred during date format conversion
|
|
//
|
|
// Description
|
|
// Use this method to obtain the stop time of the lease.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_LeaseStopTime(
|
|
DATE *pTime
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_LeaseStopTime: enter"));
|
|
|
|
m_CriticalSection.Lock();
|
|
HRESULT hr = LeaseTimeToDate(m_pLease->LeaseEndTime, pTime);
|
|
m_CriticalSection.Unlock();
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_LeaseStopTime: exit; hr = %08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::put_LeaseStopTime
|
|
//
|
|
// Parameters
|
|
// time [in] A DATE specifying the stop time of the lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_INVALIDARG A failure occurred during date format conversion
|
|
//
|
|
// Description
|
|
// Use this method to set the stop time of the lease. This method,
|
|
// along with put_LeaseStartTime, allows you to renew a lease without
|
|
// calling IMcastAddressAllocation::CreateLeaseInfo.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::put_LeaseStopTime(
|
|
DATE time
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_LeaseStopTime: enter"));
|
|
|
|
m_CriticalSection.Lock();
|
|
HRESULT hr = DateToLeaseTime(time, &(m_pLease->LeaseEndTime));
|
|
m_CriticalSection.Unlock();
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::put_LeaseStopTime: exit; hr = %08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_AddressCount
|
|
//
|
|
// Parameters
|
|
// pCount [out] Pointer to a long that will receive the number of
|
|
// addresses requested or granted in this lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
//
|
|
// Description
|
|
// Use this method to obtain the number of addresses requested or granted
|
|
// in this lease.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_AddressCount(
|
|
long *pCount
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_AddressCount: enter"));
|
|
|
|
if ( IsBadWritePtr(pCount, sizeof(long)) )
|
|
{
|
|
LOG((MSP_ERROR, "get_AddressCount: invalid pCount pointer "
|
|
"(ptr = %08x)", pCount));
|
|
return E_POINTER;
|
|
}
|
|
|
|
// we checked when we set it that we didn't overflow a long
|
|
*pCount = (long) m_pLease->AddrCount;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_AddressCount: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_ServerAddress
|
|
//
|
|
// Parameters
|
|
// ppAddress [out] Pointer to a BSTR (size-tagged Unicode string pointer)
|
|
// that will receive a string representation of the
|
|
// address of the server granting this request or
|
|
// renewal, if this is the case. If lease information
|
|
// object does not describe a granted lease, i.e., was
|
|
// not returned by IMcastAddressAllocation::RequestAddress or
|
|
// IMcastAddressAllocation::RenewAddress, then the address is reported as
|
|
// the string "Unspecified".
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// S_FALSE Server address unspecified
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_OUTOFMEMORY Not enough memory to allocate the string
|
|
//
|
|
// Description
|
|
// Use this method to obtain a string representing the address of the
|
|
// MDHCP server granting this lease.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_ServerAddress(
|
|
BSTR *ppAddress
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_ServerAddress: enter"));
|
|
|
|
if ( IsBadWritePtr(ppAddress, sizeof(BSTR)) )
|
|
{
|
|
LOG((MSP_ERROR, "get_ServerAddress: invalid ppAddress pointer "
|
|
"(ptr = %08x)", ppAddress));
|
|
return E_POINTER;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
WCHAR wszBuffer[100]; // no danger of overflow (see below)
|
|
|
|
// SPECBUG: We should discuss what sort of behavior we want for
|
|
// this case.
|
|
if ( m_pLease->ServerAddress.IpAddrV4 == 0 )
|
|
{
|
|
wsprintf(wszBuffer, L"Unspecified");
|
|
hr = S_FALSE;
|
|
}
|
|
else
|
|
{
|
|
ipAddressToStringW(wszBuffer, m_pLease->ServerAddress.IpAddrV4);
|
|
}
|
|
|
|
// This allocates space on OLE's heap, copies the wide character string
|
|
// to that space, fille in the BSTR length field, and returns a pointer
|
|
// to the wchar array part of the BSTR.
|
|
*ppAddress = SysAllocString(wszBuffer);
|
|
|
|
if ( *ppAddress == NULL )
|
|
{
|
|
LOG((MSP_ERROR, "get_ServerAddress: out of memory in string allocation"));
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_ServerAddress: exit: hr = %08x", hr));
|
|
return hr;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_TTL
|
|
//
|
|
// Parameters
|
|
// pTTL [out] Pointer to a long that will receive the TTL value associated
|
|
// with this lease.
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_FAIL There is no TTL associated with this lease
|
|
//
|
|
// Description
|
|
// Use this method to obtain the TTL value associated with this lease.
|
|
// This is more or less significant in the implementation of multicast
|
|
// routing; generally, the higher the TTL value, the "larger" or more
|
|
// inclusive the multicast scope. Probably, most applications need not
|
|
// worry about the TTL.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_TTL(
|
|
long *pTTL
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_TTL: enter"));
|
|
|
|
if ( IsBadWritePtr(pTTL, sizeof(long)) )
|
|
{
|
|
LOG((MSP_ERROR, "get_TTL: invalid pTTL pointer "
|
|
"(ptr = %08x)", pTTL));
|
|
return E_POINTER;
|
|
}
|
|
|
|
if ( ! m_fGotTtl )
|
|
{
|
|
LOG((MSP_ERROR, "get_TTL: no TTL set"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// we should check when we set it that we don't overflow a long
|
|
// (only 0 - 255 is actually meaningful, right?)
|
|
*pTTL = (long) m_lTtl;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_TTL: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::get_Addresses
|
|
//
|
|
// Parameters
|
|
// pVariant [out] Pointer to a VARIANT that will receive an OLE-standard
|
|
// Collection of addresses. Each address is represented
|
|
// as a BSTR (size-tagged Unicode string pointer) in
|
|
// "dot-quad" notation: e.g., "245.1.2.3".
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_OUTOFMEMORY Not enough memory to allocate the Collection
|
|
//
|
|
// Description
|
|
// Use this method to obtain the collection of multicast addresses that
|
|
// are the subject of this lease or lease request. This method is
|
|
// primarily for VB and other scripting languages; C++ programmers use
|
|
// EnumerateAddresses instead.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::get_Addresses(
|
|
VARIANT * pVariant
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_Addresses: enter"));
|
|
|
|
if (IsBadWritePtr(pVariant, sizeof(VARIANT)))
|
|
{
|
|
LOG((MSP_ERROR, "get_Addresses: "
|
|
"invalid pVariant pointer "
|
|
"(ptr = %08x)", pVariant));
|
|
return E_POINTER;
|
|
}
|
|
|
|
BSTR * pbszArray = NULL;
|
|
|
|
// This performs a new and as many SysAllocStrings as there are addresses.
|
|
HRESULT hr = MakeBstrArray(&pbszArray);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "get_Addresses: MakeBstrArray failed"));
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// create the collection object - use the tapi collection
|
|
//
|
|
|
|
CComObject<CTapiBstrCollection> * p;
|
|
hr = CComObject<CTapiBstrCollection>::CreateInstance( &p );
|
|
|
|
if (FAILED(hr) || (p == NULL))
|
|
{
|
|
LOG((MSP_ERROR, "get_Addresses: Could not create CTapiBstrCollection "
|
|
"object - return %lx", hr ));
|
|
|
|
for (DWORD i = 0 ; i < m_pLease->AddrCount; i++)
|
|
{
|
|
SysFreeString(pbszArray[i]);
|
|
}
|
|
delete pbszArray;
|
|
return hr;
|
|
}
|
|
|
|
// initialize it using an iterator -- pointers to the beginning and
|
|
// the ending element plus one. The collection takes ownership of the
|
|
// BSTRs. We no longer need the array they were kept in.
|
|
hr = p->Initialize(m_pLease->AddrCount,
|
|
pbszArray,
|
|
pbszArray + m_pLease->AddrCount);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "get_Addresses: Could not initialize "
|
|
"ScopeCollection object - return %lx", hr ));
|
|
|
|
for (DWORD i = 0 ; i < m_pLease->AddrCount; i++)
|
|
{
|
|
SysFreeString(pbszArray[i]);
|
|
}
|
|
delete pbszArray;
|
|
|
|
delete p;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// The collection takes ownership of the BSTRs.
|
|
// We no longer need the array they were kept in.
|
|
|
|
delete pbszArray;
|
|
|
|
// get the 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_Addresses: QI for IDispatch failed on "
|
|
"ScopeCollection - %lx", hr ));
|
|
|
|
delete p;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// put it in the variant
|
|
|
|
LOG((MSP_INFO, "placing IDispatch value %08x in variant", pDisp));
|
|
|
|
VariantInit(pVariant);
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = pDisp;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::get_Addresses: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// IMcastLeaseInfo::EnumerateAddresses
|
|
//
|
|
// Parameters
|
|
// ppEnumAddresses [out] Returns a pointer to a new IEnumBstr object.
|
|
// IEnumBstr is a standard enumerator interface
|
|
// that enumerates BSTRs (size-tagged Unicode string
|
|
// pointers). Each string is in "dot-quad" notation:
|
|
// e.g., "245.1.2.3".
|
|
//
|
|
// Return Values
|
|
// S_OK Success
|
|
// E_POINTER The caller passed in an invalid pointer argument
|
|
// E_OUTOFMEMORY Not enough memory to allocate the enumerator
|
|
//
|
|
// Description
|
|
// Use this method to obtain the collection of multicast addresses that
|
|
// are the subject of this lease or lease request. This method is
|
|
// primarily for C++ programmers; VB and other scripting languages use
|
|
// get_Addresses instead.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class _CopyBSTR
|
|
{
|
|
public:
|
|
static void copy(BSTR *p1, BSTR *p2)
|
|
{
|
|
(*p1) = SysAllocString(*p2);
|
|
}
|
|
static void init(BSTR* p) {*p = NULL;}
|
|
static void destroy(BSTR* p) { SysFreeString(*p);}
|
|
};
|
|
|
|
STDMETHODIMP CMDhcpLeaseInfo::EnumerateAddresses(
|
|
IEnumBstr ** ppEnumAddresses
|
|
)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::EnumerateAddresses: enter"));
|
|
|
|
if (IsBadWritePtr(ppEnumAddresses, sizeof(IEnumBstr *)))
|
|
{
|
|
LOG((MSP_ERROR, "EnumerateAddresses: "
|
|
"invalid ppEnumAddresses pointer "
|
|
"(ptr = %08x)", ppEnumAddresses));
|
|
return E_POINTER;
|
|
}
|
|
|
|
BSTR * pbszArray = NULL;
|
|
|
|
// This performs a new and as many SysAllocStrings as there are addresses.
|
|
HRESULT hr = MakeBstrArray(&pbszArray);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "EnumerateAddresses: MakeBstrArray failed"));
|
|
return hr;
|
|
}
|
|
|
|
typedef CSafeComEnum<IEnumBstr, &IID_IEnumBstr,
|
|
BSTR, _CopyBSTR> CEnumerator;
|
|
CComObject<CEnumerator> *pEnum = NULL;
|
|
|
|
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
|
|
if (FAILED(hr) || (pEnum == NULL))
|
|
{
|
|
LOG((MSP_ERROR, "EnumerateAddresses: "
|
|
"Couldn't create enumerator object: %08x", hr));
|
|
|
|
for (DWORD i = 0 ; i < m_pLease->AddrCount; i++)
|
|
{
|
|
SysFreeString(pbszArray[i]);
|
|
}
|
|
delete pbszArray;
|
|
return hr;
|
|
}
|
|
|
|
|
|
// Hand the BSTRs to the enumerator. The enumerator takes ownership of the
|
|
// array of BSTRs, so no need to delete them if this succeeds.
|
|
hr = pEnum->Init(&(pbszArray[0]),
|
|
&(pbszArray[m_pLease->AddrCount]),
|
|
NULL, AtlFlagTakeOwnership);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
LOG((MSP_ERROR, "EnumerateAddresses: "
|
|
"Init enumerator object failed: %08x", hr));
|
|
|
|
for (DWORD i = 0 ; i < m_pLease->AddrCount; i++)
|
|
{
|
|
SysFreeString(pbszArray[i]);
|
|
}
|
|
delete pbszArray;
|
|
|
|
// p has not yet been addreffed so release makes no sense
|
|
delete pEnum;
|
|
|
|
return hr;
|
|
}
|
|
|
|
// The enumerator took ownership, so don't delete the array.
|
|
|
|
// Now get the interface we wanted...
|
|
|
|
hr = pEnum->_InternalQueryInterface(IID_IEnumBstr,
|
|
(void **) ppEnumAddresses);
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
LOG((MSP_ERROR, "EnumerateAddresses: "
|
|
"internal QI failed: %08x", hr));
|
|
|
|
// we don't know if p has been addreffed
|
|
delete pEnum;
|
|
|
|
return hr;
|
|
}
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::EnumerateAddresses: exit"));
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CMDhcpLeaseInfo::GetLocal(BOOL * pfLocal)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetLocal: enter"));
|
|
|
|
_ASSERTE( ! IsBadWritePtr( pfLocal, sizeof(BOOL) ) );
|
|
|
|
*pfLocal = m_fLocal;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::GetLocal: exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CMDhcpLeaseInfo::SetLocal(BOOL fLocal)
|
|
{
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::SetLocal: enter"));
|
|
|
|
m_fLocal = fLocal;
|
|
|
|
LOG((MSP_TRACE, "CMDhcpLeaseInfo::SetLocal: exit S_OK"));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// eof
|