Platform SDK: Quality of Service

ENUMERATION_BUFFER

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;

Members

Length
Number of bytes from the beginning of the ENUMERATION_BUFFER to the next ENUMERATION_BUFFER.
OwnerProcessId
Identifies the owner of the process.
FlowNameLength
Specifies the length of the FlowName member.
FlowName
Array of WCHAR characters, of length MAX_STRING_LENGTH, that specifies the flow name.
pFlow
Pointer to the corresponding TC_GEN_FLOW structure. This structure is placed immediately after the array of TC_GEN_FILTERS and is included in Length.
NumberOfFilters
Specifies the number of filters associated with the flow.
GenericFilter
Array of TC_GEN_FILTER structures. The number of elements in the array corresponds to the number of filters attached to the specified flow. Note that in order to enumerate through the array of TC_GEN_FILTER structures, you need to increment the pointer to the current TC_GEN_FILTER by using the following:

sizeof(TC_GEN_FILTER) + 2 * [the pattern size of the current TC_GEN_FILTER structure].

Example

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);
    }
}

Requirements

  Windows NT/2000: Requires Windows 2000.
  Windows 95/98: Unsupported.
  Header: Declared in Traffic.h.

See Also

TC_GEN_FLOW, TC_GEN_FILTER