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