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

894 lines
20 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
confaddr.cpp
Abstract:
This module contains implementation of CIPConfMSP.
Author:
Mu Han (muhan) 5-September-1997
--*/
#include "stdafx.h"
#include "common.h"
#ifdef USEIPADDRTABLE
#include <iprtrmib.h>
typedef DWORD (WINAPI * PFNGETIPADDRTABLE)(
OUT PMIB_IPADDRTABLE pIPAddrTable,
IN OUT PDWORD pdwSize,
IN BOOL bOrder
);
#define IPHLPAPI_DLL L"IPHLPAPI.DLL"
#define GETIPADDRTABLE "GetIpAddrTable"
#define IsValidInterface(_dwAddr_) \
(((_dwAddr_) != 0) && \
((_dwAddr_) != htonl(INADDR_LOOPBACK)))
#endif
#define IPCONF_WINSOCKVERSION MAKEWORD(2,0)
HRESULT CIPConfMSP::FinalConstruct()
{
// initialize winsock stack
WSADATA wsaData;
if (WSAStartup(IPCONF_WINSOCKVERSION, &wsaData) != 0)
{
LOG((MSP_ERROR, "WSAStartup failed with:%x", WSAGetLastError()));
return E_FAIL;
}
// allocate control socket
m_hSocket = WSASocket(
AF_INET, // af
SOCK_DGRAM, // type
IPPROTO_IP, // protocol
NULL, // lpProtocolInfo
0, // g
0 // dwFlags
);
// validate handle
if (m_hSocket == INVALID_SOCKET) {
LOG((
MSP_ERROR,
"error %d creating control socket.\n",
WSAGetLastError()
));
// failure
WSACleanup();
return E_FAIL;
}
HRESULT hr = CMSPAddress::FinalConstruct();
if (hr != S_OK)
{
// close socket
closesocket(m_hSocket);
// shutdown
WSACleanup();
}
return hr;
}
void CIPConfMSP::FinalRelease()
{
CMSPAddress::FinalRelease();
if (m_hSocket != INVALID_SOCKET)
{
// close socket
closesocket(m_hSocket);
}
// shutdown
WSACleanup();
}
DWORD CIPConfMSP::FindLocalInterface(DWORD dwIP)
{
SOCKADDR_IN DestAddr;
DestAddr.sin_family = AF_INET;
DestAddr.sin_port = 0;
DestAddr.sin_addr.s_addr = htonl(dwIP);
SOCKADDR_IN LocAddr;
// query for default address based on destination
DWORD dwStatus;
DWORD dwLocAddrSize = sizeof(SOCKADDR_IN);
DWORD dwNumBytesReturned = 0;
if ((dwStatus = WSAIoctl(
m_hSocket, // SOCKET s
SIO_ROUTING_INTERFACE_QUERY, // DWORD dwIoControlCode
&DestAddr, // LPVOID lpvInBuffer
sizeof(SOCKADDR_IN), // DWORD cbInBuffer
&LocAddr, // LPVOID lpvOUTBuffer
dwLocAddrSize, // DWORD cbOUTBuffer
&dwNumBytesReturned, // LPDWORD lpcbBytesReturned
NULL, // LPWSAOVERLAPPED lpOverlapped
NULL // LPWSAOVERLAPPED_COMPLETION_ROUTINE lpComplROUTINE
)) == SOCKET_ERROR)
{
dwStatus = WSAGetLastError();
LOG((MSP_ERROR, "WSAIoctl failed: %d (0x%X)", dwStatus, dwStatus));
return INADDR_NONE;
}
DWORD dwAddr = ntohl(LocAddr.sin_addr.s_addr);
if (dwAddr == 0x7f000001)
{
// it is loopback address, just return none.
return INADDR_NONE;
}
return dwAddr;
}
STDMETHODIMP CIPConfMSP::CreateTerminal(
IN BSTR pTerminalClass,
IN long lMediaType,
IN TERMINAL_DIRECTION Direction,
OUT ITTerminal ** ppTerminal
)
/*++
Routine Description:
This method is called by TAPI3 to create a dynamic terminal. It asks the
terminal manager to create a dynamic terminal.
Arguments:
iidTerminalClass
IID of the terminal class to be created.
dwMediaType
TAPI media type of the terminal to be created.
Direction
Terminal direction of the terminal to be created.
ppTerminal
Returned created terminal object
Return Value:
S_OK
E_OUTOFMEMORY
TAPI_E_INVALIDMEDIATYPE
TAPI_E_INVALIDTERMINALDIRECTION
TAPI_E_INVALIDTERMINALCLASS
--*/
{
LOG((MSP_TRACE,
"CIPConfMSP::CreateTerminal - enter"));
//
// Check if initialized.
//
// lock the event related data
m_EventDataLock.Lock();
if ( m_htEvent == NULL )
{
// unlock the event related data
m_EventDataLock.Unlock();
LOG((MSP_ERROR,
"CIPConfMSP::CreateTerminal - "
"not initialized - returning E_UNEXPECTED"));
return E_UNEXPECTED;
}
// unlock the event related data
m_EventDataLock.Unlock();
//
// Get the IID from the BSTR representation.
//
HRESULT hr;
IID iidTerminalClass;
hr = CLSIDFromString(pTerminalClass, &iidTerminalClass);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
"bad CLSID string - returning E_INVALIDARG"));
return E_INVALIDARG;
}
//
// Make sure we support the requested media type.
// The terminal manager checks the terminal class, terminal direction,
// and return pointer.
//
if ( ! IsValidSingleMediaType( (DWORD) lMediaType, GetCallMediaTypes() ) )
{
LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
"non-audio terminal requested - returning E_INVALIDARG"));
return E_INVALIDARG;
}
//
// Use the terminal manager to create the dynamic terminal.
//
_ASSERTE( m_pITTerminalManager != NULL );
hr = m_pITTerminalManager->CreateDynamicTerminal(NULL,
iidTerminalClass,
(DWORD) lMediaType,
Direction,
(MSP_HANDLE) this,
ppTerminal);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "CIPConfMSP::CreateTerminal - "
"create dynamic terminal failed - returning 0x%08x", hr));
return hr;
}
if ((iidTerminalClass == CLSID_MediaStreamTerminal)
&& (lMediaType == TAPIMEDIATYPE_AUDIO))
{
// Set the format of the audio to 8KHZ, 16Bit/Sample, MONO.
hr = ::SetAudioFormat(
*ppTerminal,
g_wAudioCaptureBitPerSample,
g_dwG711AudioSampleRate
);
if (FAILED(hr))
{
LOG((MSP_WARN, "can't set audio format, %x", hr));
}
}
LOG((MSP_TRACE, "CIPConfMSP::CreateTerminal - exit S_OK"));
return S_OK;
}
STDMETHODIMP CIPConfMSP::CreateMSPCall(
IN MSP_HANDLE htCall,
IN DWORD dwReserved,
IN DWORD dwMediaType,
IN IUnknown * pOuterUnknown,
OUT IUnknown ** ppMSPCall
)
/*++
Routine Description:
This method is called by TAPI3 before a call is made or answered. It creates
a aggregated MSPCall object and returns the IUnknown pointer. It calls the
helper template function defined in mspaddress.h to handle the real creation.
Arguments:
htCall
TAPI 3.0's identifier for this call. Returned in events passed back
to TAPI.
dwReserved
Reserved parameter. Not currently used.
dwMediaType
Media type of the call being created. These are TAPIMEDIATYPES and more
than one mediatype can be selected (bitwise).
pOuterUnknown
pointer to the IUnknown interface of the containing object.
ppMSPCall
Returned MSP call that the MSP fills on on success.
Return Value:
S_OK
E_OUTOFMEMORY
E_POINTER
TAPI_E_INVALIDMEDIATYPE
--*/
{
LOG((MSP_TRACE,
"CreateMSPCall entered. htCall:%x, dwMediaType:%x, ppMSPCall:%x",
htCall, dwMediaType, ppMSPCall
));
CIPConfMSPCall * pMSPCall = NULL;
HRESULT hr = ::CreateMSPCallHelper(
this,
htCall,
dwReserved,
dwMediaType,
pOuterUnknown,
ppMSPCall,
&pMSPCall
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "CreateMSPCallHelper failed:%x", hr));
return hr;
}
// this function doesn't return anything.
pMSPCall->SetIPInterface(m_dwIPInterface);
return hr;
}
STDMETHODIMP CIPConfMSP::ShutdownMSPCall(
IN IUnknown * pUnknown
)
/*++
Routine Description:
This method is called by TAPI3 to shutdown a MSPCall. It calls the helper
function defined in MSPAddress to to the real job.
Arguments:
pUnknown
pointer to the IUnknown interface of the contained object. It is a
CComAggObject that contains our call object.
Return Value:
S_OK
E_POINTER
TAPI_E_INVALIDMEDIATYPE
--*/
{
LOG((MSP_TRACE, "ShutDownMSPCall entered. pUnknown:%x", pUnknown));
if (IsBadReadPtr(pUnknown, sizeof(VOID *) * 3))
{
LOG((MSP_ERROR, "ERROR:pUnknow is a bad pointer"));
return E_POINTER;
}
CIPConfMSPCall * pMSPCall = NULL;
HRESULT hr = ::ShutdownMSPCallHelper(pUnknown, &pMSPCall);
if (FAILED(hr))
{
LOG((MSP_ERROR, "ShutDownMSPCallhelper failed:: %x", hr));
return hr;
}
return hr;
}
DWORD CIPConfMSP::GetCallMediaTypes(void)
{
return IPCONFCALLMEDIATYPES;
}
ULONG CIPConfMSP::MSPAddressAddRef(void)
{
return MSPAddRefHelper(this);
}
ULONG CIPConfMSP::MSPAddressRelease(void)
{
return MSPReleaseHelper(this);
}
#ifdef USEIPADDRTABLE
PMIB_IPADDRTABLE GetIPTable()
/*++
Routine Description:
This method is used to get the table of local IP interfaces.
Arguments:
Return Value:
NULL - failed.
Pointer - a memory buffer that contains the IP interface table.
--*/
{
// dynamically load iphlpapi.dll
HMODULE hIPHLPAPI = LoadLibraryW(IPHLPAPI_DLL);
// validate handle
if (hIPHLPAPI == NULL)
{
LOG((MSP_ERROR, "could not load %s.\n", IPHLPAPI_DLL));
// failure
return NULL;
}
PFNGETIPADDRTABLE pfnGetIpAddrTable = NULL;
// retrieve function pointer to retrieve addresses
pfnGetIpAddrTable = (PFNGETIPADDRTABLE)GetProcAddress(
hIPHLPAPI,
GETIPADDRTABLE
);
// validate function pointer
if (pfnGetIpAddrTable == NULL)
{
LOG((MSP_ERROR, "could not resolve GetIpAddrTable.\n"));
// release
FreeLibrary(hIPHLPAPI);
// failure
return NULL;
}
PMIB_IPADDRTABLE pIPAddrTable = NULL;
DWORD dwBytesRequired = 0;
DWORD dwStatus;
// determine amount of memory needed for table
dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
// validate status is what we expect
if (dwStatus != ERROR_INSUFFICIENT_BUFFER)
{
LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
// release
FreeLibrary(hIPHLPAPI);
// failure, but we need to return true to load.
return NULL;
}
// attempt to allocate memory for table
pIPAddrTable = (PMIB_IPADDRTABLE)malloc(dwBytesRequired);
// validate pointer
if (pIPAddrTable == NULL)
{
LOG((MSP_ERROR, "could not allocate address table.\n"));
// release
FreeLibrary(hIPHLPAPI);
// failure, but we need to return true to load.
return NULL;
}
// retrieve ip address table from tcp/ip stack via utitity library
dwStatus = (*pfnGetIpAddrTable)(pIPAddrTable, &dwBytesRequired, FALSE);
// validate status
if (dwStatus != NOERROR)
{
LOG((MSP_ERROR, "error 0x%08lx calling GetIpAddrTable.\n", dwStatus));
// release table
free(pIPAddrTable);
// release
FreeLibrary(hIPHLPAPI);
// failure, but we need to return true to load.
return NULL;
}
// release library
FreeLibrary(hIPHLPAPI);
return pIPAddrTable;
}
BSTR IPToBstr(
DWORD dwIP
)
{
struct in_addr Addr;
Addr.s_addr = dwIP;
// convert the interface to a string.
CHAR *pChar = inet_ntoa(Addr);
if (pChar == NULL)
{
LOG((MSP_ERROR, "bad IP address:%x", dwIP));
return NULL;
}
// convert the ascii string to WCHAR.
WCHAR szAddressName[MAXIPADDRLEN + 1];
wsprintfW(szAddressName, L"%hs", pChar);
// create a BSTR.
BSTR bAddress = SysAllocString(szAddressName);
if (bAddress == NULL)
{
LOG((MSP_ERROR, "out of mem in allocation address name"));
return NULL;
}
return bAddress;
}
STDMETHODIMP CIPConfMSP::get_DefaultIPInterface(
OUT BSTR * ppIPAddress
)
{
LOG((MSP_TRACE, "get_DefaultIPInterface, ppIPAddress:%p", ppIPAddress));
if (IsBadWritePtr(ppIPAddress, sizeof(BSTR)))
{
LOG((MSP_ERROR,
"get_DefaultIPInterface, ppIPAddress is bad:%p", ppIPAddress));
return E_POINTER;
}
// get the current local interface.
m_Lock.Lock();
DWORD dwIP= m_dwIPInterface;
m_Lock.Unlock();
BSTR bAddress = IPToBstr(dwIP);
if (bAddress == NULL)
{
return E_OUTOFMEMORY;
}
*ppIPAddress = bAddress;
LOG((MSP_TRACE, "get_DefaultIPInterface, returning %ws", bAddress));
return S_OK;
}
STDMETHODIMP CIPConfMSP::put_DefaultIPInterface(
IN BSTR pIPAddress
)
{
LOG((MSP_TRACE, "put_DefaultIPInterface, pIPAddress:%p", pIPAddress));
if (IsBadStringPtrW(pIPAddress, MAXIPADDRLEN))
{
LOG((MSP_ERROR,
"put_DefaultIPInterface, invalid pointer:%p", pIPAddress));
return E_POINTER;
}
char buffer[MAXIPADDRLEN + 1];
if (WideCharToMultiByte(
GetACP(),
0,
pIPAddress,
-1,
buffer,
MAXIPADDRLEN,
NULL,
NULL
) == 0)
{
LOG((MSP_ERROR, "put_DefaultIPInterface, can't covert:%ws", pIPAddress));
return E_INVALIDARG;
}
DWORD dwAddr;
if ((dwAddr = inet_addr(buffer)) == INADDR_NONE)
{
LOG((MSP_ERROR, "put_DefaultIPInterface, bad address:%s", buffer));
return E_INVALIDARG;
}
// set the current local interface.
m_Lock.Lock();
m_dwIPInterface = dwAddr;
m_Lock.Unlock();
LOG((MSP_TRACE, "put_DefaultIPInterface, set to %s", buffer));
return S_OK;
}
HRESULT CreateBstrCollection(
IN BSTR * pBstr,
IN DWORD dwCount,
OUT VARIANT * pVariant
)
{
//
// create the collection object - see mspcoll.h
//
CComObject<CTapiBstrCollection> * pCollection;
HRESULT hr = CComObject<CTapiBstrCollection>::CreateInstance( &pCollection );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "get_IPInterfaces - "
"can't create collection - exit 0x%08x", hr));
return hr;
}
//
// get the Collection's IDispatch interface
//
IDispatch * pDispatch;
hr = pCollection->_InternalQueryInterface(IID_IDispatch,
(void **) &pDispatch );
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "get_IPInterfaces - "
"QI for IDispatch on collection failed - exit 0x%08x", hr));
delete pCollection;
return hr;
}
//
// Init the collection using an iterator -- pointers to the beginning and
// the ending element plus one.
//
hr = pCollection->Initialize( dwCount,
pBstr,
pBstr + dwCount);
if ( FAILED(hr) )
{
LOG((MSP_ERROR, "get_IPInterfaces - "
"Initialize on collection failed - exit 0x%08x", hr));
pDispatch->Release();
return hr;
}
//
// put the IDispatch interface pointer into the variant
//
LOG((MSP_ERROR, "get_IPInterfaces - "
"placing IDispatch value %08x in variant", pDispatch));
VariantInit(pVariant);
pVariant->vt = VT_DISPATCH;
pVariant->pdispVal = pDispatch;
LOG((MSP_TRACE, "get_IPInterfaces - exit S_OK"));
return S_OK;
}
STDMETHODIMP CIPConfMSP::get_IPInterfaces(
OUT VARIANT * pVariant
)
{
PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
if (pIPAddrTable == NULL)
{
return E_FAIL;
}
BSTR *Addresses =
(BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
if (Addresses == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = S_OK;
DWORD dwCount = 0;
// loop through the interfaces and find the valid ones.
for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
{
if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
{
DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
Addresses[i] = IPToBstr(dwIPAddr);
if (Addresses[i] == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
}
}
// release table memory
free(pIPAddrTable);
if (FAILED(hr))
{
// release all the BSTRs and the array.
for (i = 0; i < dwCount; i ++)
{
SysFreeString(Addresses[i]);
}
free(Addresses);
return hr;
}
hr = CreateBstrCollection(Addresses, dwCount, pVariant);
// if the collection is not created, release all the BSTRs.
if (FAILED(hr))
{
for (i = 0; i < dwCount; i ++)
{
SysFreeString(Addresses[i]);
}
}
// delete the pointer array.
free(Addresses);
return hr;
}
HRESULT CreateBstrEnumerator(
IN BSTR * begin,
IN BSTR * end,
OUT IEnumBstr ** ppIEnum
)
{
typedef CSafeComEnum<IEnumBstr, &IID_IEnumBstr, BSTR, _CopyBSTR>> CEnumerator;
HRESULT hr;
CComObject<CEnumerator> *pEnum = NULL;
hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
if (pEnum == NULL)
{
LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
return hr;
}
IEnumBstr * pIEnum;
// query for the IID_IEnumDirectory i/f
hr = pEnum->_InternalQueryInterface(
IID_IEnumBstr,
(void**)&pIEnum
);
if (FAILED(hr))
{
LOG((MSP_ERROR, "query enum interface failed, %x", hr));
delete pEnum;
return hr;
}
hr = pEnum->Init(begin, end, NULL, AtlFlagTakeOwnership);
if (FAILED(hr))
{
LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
pIEnum->Release();
return hr;
}
*ppIEnum = pIEnum;
return hr;
}
STDMETHODIMP CIPConfMSP::EnumerateIPInterfaces(
OUT IEnumBstr ** ppIEnumBstr
)
{
PMIB_IPADDRTABLE pIPAddrTable = GetIPTable();
if (pIPAddrTable == NULL)
{
return E_FAIL;
}
BSTR *Addresses =
(BSTR *)malloc(sizeof(BSTR *) * pIPAddrTable->dwNumEntries);
if (Addresses == NULL)
{
return E_OUTOFMEMORY;
}
HRESULT hr = S_OK;
DWORD dwCount = 0;
// loop through the interfaces and find the valid ones.
for (DWORD i = 0; i < pIPAddrTable->dwNumEntries; i++)
{
if (IsValidInterface(pIPAddrTable->table[i].dwAddr))
{
DWORD dwIPAddr = ntohl(pIPAddrTable->table[i].dwAddr);
Addresses[i] = IPToBstr(dwIPAddr);
if (Addresses[i] == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
}
}
// release table memory
free(pIPAddrTable);
if (FAILED(hr))
{
// release all the BSTRs and the array.
for (i = 0; i < dwCount; i ++)
{
SysFreeString(Addresses[i]);
}
free(Addresses);
return hr;
}
hr = CreateBstrEnumerator(Addresses, Addresses + dwCount, ppIEnumBstr);
// if the collection is not created, release all the BSTRs.
if (FAILED(hr))
{
for (i = 0; i < dwCount; i ++)
{
SysFreeString(Addresses[i]);
}
free(Addresses);
return hr;
}
// the enumerator will destroy the bstr array eventually,
// so no need to free anything here. Even if we tell it to hand
// out zero objects, it will delete the array on destruction.
return hr;
}
#endif