| Platform SDK: Quality of Service |
The ENUMERATION_BUFFER structure contains information specific to a given flow, including flow name, the number of filters associated with the flow, and an array of filters associated with the flow.
typedef struct _ENUMERATION_BUFFER {
ULONG Length;
ULONG OwnerProcessId;
USHORT FlowNameLength;
WCHAR FlowName[MAX_STRING_LENGTH];
PTC_GEN_FLOW pFlow;
ULONG NumberOfFilters;
TC_GEN_FILTER GenericFilter[1];
} ENUMERATION_BUFFER, *PENUMERATION_BUFFER;
sizeof(TC_GEN_FILTER) + 2 * [the pattern size of the current TC_GEN_FILTER structure].
The following example shows how to use the ENUMERATION_BUFFER with traffic control. It also provides an example of enumerating through the array of TC_GEN_FILTER structures found in GenericFilter.
#define UNICODE
#include <winsock2.h>
#include <windows.h>
#include <qos.h>
#include <ntddndis.h>
#include <traffic.h>
#include <tcerror.h>
#include <stdlib.h>
#include <stdio.h>
#define INITIAL_IFC_BUFFER_SIZE 4096
#define INITIAL_FLOW_BUFFER_SIZE 1024
#define FLOW_NAME_BUFFER_SIZE 1024
#define QUERY_FLOW_BUFFER_SIZE 2048
#define QUERY_IFC_BUFFER_SIZE 2048
void ExamineFlow(int nFlow, PENUMERATION_BUFFER pEnumBuffer)
{
PTC_GEN_FILTER pCurrentFilter = pEnumBuffer->GenericFilter;
printf(" Flow %d:\n",nFlow);
printf(" Name: %ws\n",pEnumBuffer->FlowName);
printf(" OwnerProcessID: %d\n",pEnumBuffer->OwnerProcessId);
printf(" Number of Filters: %d\n",pEnumBuffer->NumberOfFilters);
for (ULONG i=0; i < pEnumBuffer->NumberOfFilters; i++)
{
printf(" Filter %d: ",i);
if (pCurrentFilter->AddressType == NDIS_PROTOCOL_ID_TCP_IP) printf("TCP/IP Filter\n");
else if (pCurrentFilter->AddressType == NDIS_PROTOCOL_ID_IPX) printf("IPX Filter\n");
else printf("Other Filter Type\n");
pCurrentFilter = (PTC_GEN_FILTER)((PBYTE)pCurrentFilter + sizeof(TC_GEN_FILTER) + (pCurrentFilter->PatternSize * 2));
}
}
void EnumFlows(HANDLE hIfc)
{
PENUMERATION_BUFFER pEnumBuffer, pCurrentEnumBuffer;
ULONG EnumBufferSize = INITIAL_FLOW_BUFFER_SIZE;
ULONG FilledEnumBufferSize;
HANDLE hEnum;
ULONG FlowCount, err, i;
int nFlow = 0;
pEnumBuffer = (PENUMERATION_BUFFER) malloc ( EnumBufferSize );
if (pEnumBuffer == NULL) {
printf("Error: malloc");
return;
}
hEnum = NULL;
do
{
FilledEnumBufferSize = EnumBufferSize;
FlowCount = -1; // Request All Flows
err = TcEnumerateFlows ( hIfc,
&hEnum,
&FlowCount,
&FilledEnumBufferSize,
pEnumBuffer );
if (err == ERROR_INSUFFICIENT_BUFFER)
{
//
// The buffer was not large enough to hold any entries. Make it bigger.
//
EnumBufferSize *= 2;
pEnumBuffer = (PENUMERATION_BUFFER) realloc( pEnumBuffer, EnumBufferSize );
}
else if (err == NO_ERROR)
{
pCurrentEnumBuffer = pEnumBuffer;
for (ULONG i = 0; i < FlowCount; i++)
{
nFlow++;
ExamineFlow(nFlow, pCurrentEnumBuffer);
//
// Advance to the next buffer
//
pCurrentEnumBuffer = (PENUMERATION_BUFFER)((PBYTE)pCurrentEnumBuffer + pCurrentEnumBuffer->Length);
}
}
} while ( (hEnum != NULL && err == NO_ERROR) || (err == ERROR_INSUFFICIENT_BUFFER) );
free(pEnumBuffer);
if (err != NO_ERROR && err != ERROR_INVALID_DATA)
{
printf("Error: TcEnumerateFlow");
return;
}
}
void ExamineInterface(HANDLE hClient, int nIfcs, PTC_IFC_DESCRIPTOR pCurrentIfc)
{
HANDLE hIfc;
ULONG err;
printf("Interface %d:\n Name: %ws\n\n",nIfcs,pCurrentIfc->pInterfaceName);
err = TcOpenInterface(
pCurrentIfc->pInterfaceName,
hClient,
NULL,
&hIfc);
if (err != NO_ERROR)
{
printf("Error: TcOpenInterface");
return;
}
EnumFlows(hIfc);
err = TcCloseInterface(hIfc);
if (err != NO_ERROR)
{
printf("Error: TcCloseInterface");
return;
}
}
void EnumInterfaces(HANDLE hClient)
{
PTC_IFC_DESCRIPTOR pIfcs,pCurrentIfc;
ULONG BufferSize = INITIAL_IFC_BUFFER_SIZE;
ULONG ActualBufferSize, RemainingBufferSize;
int nIfcs = 0;
while (true)
{
pIfcs = (PTC_IFC_DESCRIPTOR) malloc(BufferSize);
if (pIfcs == NULL) {
printf("Error: malloc");
return;
}
ULONG err = TcEnumerateInterfaces(
hClient,
&ActualBufferSize,
pIfcs);
if (err == NO_ERROR)
{
// We've got the data
break;
}
else if (err == ERROR_INSUFFICIENT_BUFFER)
{
free(pIfcs);
BufferSize *= 2;
}
else
{
printf("Error: TcEnumerateInterfaces");
return;
}
}
RemainingBufferSize = ActualBufferSize;
pCurrentIfc = pIfcs;
while (RemainingBufferSize > 0)
{
nIfcs++;
ExamineInterface(hClient, nIfcs, pCurrentIfc);
RemainingBufferSize -= pCurrentIfc->Length;
pCurrentIfc = (PTC_IFC_DESCRIPTOR) ((PBYTE) pCurrentIfc + pCurrentIfc->Length);
}
free(pIfcs);
}
VOID CALLBACK NotifyHandler(
HANDLE ClRegCtx,
HANDLE ClIfcCtx,
ULONG Event,
ULONG SubCode,
ULONG BufSize,
PVOID Buffer)
{
switch (Event) {
case TC_NOTIFY_IFC_UP:
case TC_NOTIFY_IFC_CLOSE:
case TC_NOTIFY_IFC_CHANGE:
case TC_NOTIFY_PARAM_CHANGED:
case TC_NOTIFY_FLOW_CLOSE:
break;
}
}
void main()
{
ULONG err;
TCI_CLIENT_FUNC_LIST Handlers;
HANDLE hClient;
Handlers.ClNotifyHandler = NotifyHandler;
Handlers.ClAddFlowCompleteHandler = NULL;
Handlers.ClModifyFlowCompleteHandler = NULL;
Handlers.ClDeleteFlowCompleteHandler = NULL;
err = TcRegisterClient(CURRENT_TCI_VERSION, (HANDLE) NULL, &Handlers, &hClient);
if (err != NO_ERROR)
{
printf("Error: TcRegisterClient");
exit(1);
}
EnumInterfaces(hClient);
err = TcDeregisterClient(hClient);
if (err != NO_ERROR)
{
printf("Error: TcDeregisterClient");
exit(1);
}
}
Windows NT/2000: Requires Windows 2000.
Windows 95/98: Unsupported.
Header: Declared in Traffic.h.