412 lines
10 KiB
C
412 lines
10 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
stackex.c
|
|
|
|
Abstract:
|
|
|
|
Ex versions of GetTcpTableFromStack and GetUdpTableFromStack.
|
|
These are used to get the owning process id associated with connections
|
|
from the stack.
|
|
|
|
Author:
|
|
|
|
Shaun Cox (shaunco) 19-Feb-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "inc.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
int
|
|
TCPQueryInformationEx(
|
|
DWORD Family,
|
|
void *InBuf,
|
|
ulong *InBufLen,
|
|
void *OutBuf,
|
|
ulong *OutBufLen
|
|
);
|
|
|
|
DWORD
|
|
GetTcpExTableFromStack(
|
|
OUT TCP_EX_TABLE *pTcpTable,
|
|
IN DWORD dwSize,
|
|
IN BOOL bOrder,
|
|
IN DWORD dwFamily
|
|
)
|
|
{
|
|
DWORD dwInBufLen, dwOutBufLen, dwResult, dwEntryLen;
|
|
TDIObjectID *ID;
|
|
BYTE *Context;
|
|
int (_cdecl *pfnCompare)(CONST VOID *pvElem1, CONST VOID *pvElem2);
|
|
|
|
TCP_REQUEST_QUERY_INFORMATION_EX trqiInBuf;
|
|
|
|
CheckTcpipState();
|
|
if (dwFamily == AF_INET)
|
|
{
|
|
if (!g_bIpConfigured)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
dwEntryLen = sizeof(TCPConnTableEntryEx);
|
|
pfnCompare = CompareTcpRow;
|
|
dwOutBufLen = dwSize - FIELD_OFFSET(TCP_EX_TABLE, table[0]);
|
|
}
|
|
else if (dwFamily == AF_INET6)
|
|
{
|
|
if (!g_bIp6Configured)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
dwEntryLen = sizeof(TCP6ConnTableEntry);
|
|
pfnCompare = CompareTcp6Row;
|
|
dwOutBufLen = dwSize - FIELD_OFFSET(TCP6_EX_TABLE, table[0]);
|
|
}
|
|
else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ID = &(trqiInBuf.ID);
|
|
|
|
ID->toi_entity.tei_entity = CO_TL_ENTITY;
|
|
ID->toi_entity.tei_instance = 0;
|
|
ID->toi_class = INFO_CLASS_PROTOCOL;
|
|
ID->toi_type = INFO_TYPE_PROVIDER;
|
|
ID->toi_id = TCP_EX_TABLE_ID;
|
|
|
|
Context = (BYTE *) &(trqiInBuf.Context[0]);
|
|
ZeroMemory( Context, CONTEXT_SIZE );
|
|
|
|
dwInBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
|
|
|
|
dwResult = TCPQueryInformationEx(dwFamily,
|
|
&trqiInBuf,
|
|
&dwInBufLen,
|
|
(PVOID)(pTcpTable->table),
|
|
&dwOutBufLen);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"GetTcpExTableFromStack: Couldnt query stack. Error %x",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
pTcpTable->dwNumEntries = (dwOutBufLen / dwEntryLen);
|
|
|
|
if((pTcpTable->dwNumEntries > 0) and bOrder)
|
|
{
|
|
|
|
qsort(pTcpTable->table,
|
|
pTcpTable->dwNumEntries,
|
|
dwEntryLen,
|
|
pfnCompare);
|
|
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
AllocateAndGetTcpExTableFromStack(
|
|
OUT TCP_EX_TABLE **ppTcpTable,
|
|
IN BOOL bOrder,
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN DWORD dwFamily
|
|
)
|
|
{
|
|
DWORD dwResult, dwCount, dwOutBufLen;
|
|
MIB_TCPSTATS TcpInfo;
|
|
DWORD dwEntryLen;
|
|
|
|
*ppTcpTable = NULL;
|
|
|
|
//
|
|
// Find out the number of entries the stack has. It returns this as part of
|
|
// the Tcp Stats. Also validate the dwFamily parameter.
|
|
//
|
|
|
|
dwResult = GetTcpStatsFromStackEx(&TcpInfo, dwFamily);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AllocateAndGetTcpExTableFromStack: Couldnt get Tcp Stats From stack. Error %d",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
dwCount = TcpInfo.dwNumConns + OVERFLOW_COUNT;
|
|
|
|
if (dwFamily == AF_INET)
|
|
{
|
|
dwEntryLen = sizeof(TCPConnTableEntryEx);
|
|
dwOutBufLen = FIELD_OFFSET(TCP_EX_TABLE, table[0])
|
|
+ (dwCount * dwEntryLen)
|
|
+ ALIGN_SIZE;
|
|
}
|
|
else
|
|
{
|
|
dwEntryLen = sizeof(TCP6ConnTableEntry);
|
|
dwOutBufLen = FIELD_OFFSET(TCP6_EX_TABLE, table[0])
|
|
+ (dwCount * dwEntryLen)
|
|
+ ALIGN_SIZE;
|
|
}
|
|
|
|
*ppTcpTable = HeapAlloc(hHeap, dwFlags, dwOutBufLen);
|
|
if(*ppTcpTable is NULL)
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
Trace1(ERR,
|
|
"AllocateAndGetTcpExTableFromStack: Couldnt allocate memory. Error %d",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
if(TcpInfo.dwNumConns is 0)
|
|
{
|
|
(*ppTcpTable)->dwNumEntries = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
dwResult = GetTcpExTableFromStack(*ppTcpTable, dwOutBufLen, bOrder,
|
|
dwFamily);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AllocateAndGetTcpExTableFromStack: Error %d GetTcpExTableFromStack",
|
|
dwResult);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
GetUdpExTableFromStack(
|
|
OUT UDP_EX_TABLE *pUdpTable,
|
|
IN DWORD dwSize,
|
|
IN BOOL bOrder,
|
|
IN DWORD dwFamily
|
|
)
|
|
{
|
|
DWORD dwInBufLen, dwOutBufLen, dwResult;
|
|
BYTE *Context;
|
|
DWORD dwEntryLen;
|
|
int (__cdecl *pfnCompare)(CONST VOID *pvElem1, CONST VOID *pvElem2);
|
|
|
|
TCP_REQUEST_QUERY_INFORMATION_EX trqiInBuf;
|
|
TDIObjectID *ID;
|
|
|
|
CheckTcpipState();
|
|
|
|
if (dwFamily == AF_INET)
|
|
{
|
|
if (!g_bIpConfigured)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
dwEntryLen = sizeof(UDPEntryEx);
|
|
pfnCompare = CompareUdpRow;
|
|
}
|
|
else if (dwFamily == AF_INET6)
|
|
{
|
|
if (!g_bIp6Configured)
|
|
{
|
|
return ERROR_NOT_SUPPORTED;
|
|
}
|
|
dwEntryLen = sizeof(UDP6ListenerEntry);
|
|
pfnCompare = CompareUdp6Row;
|
|
}
|
|
else
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ID = &(trqiInBuf.ID);
|
|
|
|
ID->toi_entity.tei_entity = CL_TL_ENTITY;
|
|
ID->toi_entity.tei_instance = 0;
|
|
ID->toi_class = INFO_CLASS_PROTOCOL;
|
|
ID->toi_type = INFO_TYPE_PROVIDER;
|
|
ID->toi_id = UDP_EX_TABLE_ID;
|
|
|
|
Context = (BYTE *) &(trqiInBuf.Context[0]);
|
|
ZeroMemory( Context, CONTEXT_SIZE );
|
|
|
|
dwInBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
|
|
dwOutBufLen = dwSize - FIELD_OFFSET(UDP6_LISTENER_TABLE, table[0]);
|
|
|
|
dwResult = TCPQueryInformationEx(dwFamily,
|
|
&trqiInBuf,
|
|
&dwInBufLen,
|
|
(PVOID)(pUdpTable->table),
|
|
&dwOutBufLen);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"GetUdpExTableFromStack: Couldnt query TCP information. Error %d",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
pUdpTable->dwNumEntries = (dwOutBufLen / dwEntryLen);
|
|
|
|
//
|
|
// Now sort the UDP connection table. Keys are: local address, and local
|
|
// port.
|
|
//
|
|
|
|
if((pUdpTable->dwNumEntries > 0) and bOrder)
|
|
{
|
|
qsort(pUdpTable->table,
|
|
pUdpTable->dwNumEntries,
|
|
dwEntryLen,
|
|
pfnCompare);
|
|
}
|
|
|
|
TraceLeave("GetUdpExTableFromStack");
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
DWORD
|
|
AllocateAndGetUdpExTableFromStack(
|
|
OUT UDP_EX_TABLE **ppUdpTable,
|
|
IN BOOL bOrder,
|
|
IN HANDLE hHeap,
|
|
IN DWORD dwFlags,
|
|
IN DWORD dwFamily
|
|
)
|
|
{
|
|
DWORD dwResult, dwCount, dwOutBufLen;
|
|
MIB_UDPSTATS UdpInfo;
|
|
UDP6_LISTENER_TABLE **ppUdp6Table;
|
|
|
|
*ppUdpTable = NULL;
|
|
|
|
//
|
|
// Find out the number of entries the stack has. It returns this as part of
|
|
// the Tcp Stats. Also validate the dwFamily parameter.
|
|
//
|
|
|
|
dwResult = GetUdpStatsFromStackEx(&UdpInfo, dwFamily);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AllocateAndGetUdpExTableFromStack: Couldnt get Udp Stats From stack. Error %d",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
dwCount = UdpInfo.dwNumAddrs + OVERFLOW_COUNT;
|
|
if (dwFamily == AF_INET)
|
|
{
|
|
dwOutBufLen = FIELD_OFFSET(UDP_EX_TABLE, table[0])
|
|
+ (dwCount * sizeof(UDPEntryEx))
|
|
+ ALIGN_SIZE;
|
|
}
|
|
else
|
|
{
|
|
dwOutBufLen = FIELD_OFFSET(UDP6_LISTENER_TABLE, table[0])
|
|
+ (dwCount * sizeof(UDP6ListenerEntry))
|
|
+ ALIGN_SIZE;
|
|
}
|
|
|
|
*ppUdpTable = HeapAlloc(hHeap, dwFlags, dwOutBufLen);
|
|
if(*ppUdpTable is NULL)
|
|
{
|
|
dwResult = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
Trace1(ERR,
|
|
"AllocateAndGetUdpExTableFromStack: Couldnt allocate memory. Error %d",
|
|
dwResult);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
if(UdpInfo.dwNumAddrs is 0)
|
|
{
|
|
(*ppUdpTable)->dwNumEntries = 0;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
dwResult = GetUdpExTableFromStack(*ppUdpTable, dwOutBufLen, bOrder,
|
|
dwFamily);
|
|
|
|
if(dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,
|
|
"AllocateAndGetUdpExTableFromStack: Error %d GetUdpExTableFromStack",
|
|
dwResult);
|
|
}
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD
|
|
GetBestInterfaceFromIpv6Stack(
|
|
IN LPSOCKADDR_IN6 pSockAddr,
|
|
OUT PDWORD pdwBestIfIndex
|
|
)
|
|
{
|
|
DWORD dwOutBufLen, dwInBufLen, dwResult;
|
|
CHAR byBuffer[FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context) +
|
|
sizeof(TDI_ADDRESS_IP6)];
|
|
TCP_REQUEST_QUERY_INFORMATION_EX *ptrqiInBuf = (TCP_REQUEST_QUERY_INFORMATION_EX *)byBuffer;
|
|
IP6RouteEntry Ire;
|
|
TDIObjectID *ID;
|
|
BYTE *Context;
|
|
|
|
ID = &(ptrqiInBuf->ID);
|
|
ID->toi_entity.tei_entity = CL_NL_ENTITY;
|
|
ID->toi_entity.tei_instance = 0;
|
|
ID->toi_class = INFO_CLASS_PROTOCOL;
|
|
ID->toi_type = INFO_TYPE_PROVIDER;
|
|
ID->toi_id = IP6_GET_BEST_ROUTE_ID;
|
|
|
|
RtlCopyMemory((PVOID)ptrqiInBuf->Context, &pSockAddr->sin6_port,
|
|
TDI_ADDRESS_LENGTH_IP6);
|
|
|
|
dwInBufLen = sizeof(byBuffer);
|
|
dwOutBufLen = sizeof(Ire);
|
|
|
|
dwResult = TCPQueryInformationEx(AF_INET6,
|
|
ptrqiInBuf,
|
|
&dwInBufLen,
|
|
(PVOID)&Ire,
|
|
&dwOutBufLen);
|
|
|
|
if (dwResult isnot NO_ERROR)
|
|
{
|
|
Trace1(ERR,"Couldn't query IPv6 stack. Error %d", dwResult);
|
|
TraceLeave("GetBestInterfaceEx");
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
*pdwBestIfIndex = Ire.ire_IfIndex;
|
|
|
|
return dwResult;
|
|
}
|