IP Helper API: Retrieving Basic Information

Friday Sep 10th 2004 by Alex Gusev
Share:

Discover how to obtain detailed information about various Network Configuration parameters, adapters, and interfaces on a Pocket PC

This article starts a set of postings discussing different aspects of mobile networking insides. This is a pretty wide area, so one article is too small to cover it all. Thus, we will divide this topic into several logical pieces and overview them one by one. A recent article told about starting part of IP Helper API : general network configuration information, adapters, and interfaces.

General Info is really simple stuff

As I said above, we will start with obtaining info about the general network configuration. IP Helper API has one function for this purpose: GetNetworkParams. This function returns general information that is not specific to a particular network adapter or interface such as DNS, proxy, DHCP parameters, and so forth. This data is the same for all available network adapters or interfaces. The function signature is listed below:

DWORD GetNetworkParams(PFIXED_INFO pFixedInfo,PULONG pOutBufLen);

The function takes the pointer to the FIXED_INFO struct and fills it in. pOutBufLen tells the size of the supplying buffer. If no errors occured, GetNetworkParams returns NO_ERROR and corresponding data in pFixedInfo. Otherwise, you will get ERROR_BUFFER_OVERFLOW and actually the required size into pOutBufLen parameter if the initial buffer is insufficient to hold all data. That is a common behavior of most IP Helper API (and Windows' ones in general) functions. FIXED_INFO struct is presented below:

typedef struct {
char HostName [MAX_HOSTNAME_LEN + 4];
char DomainName [MAX_DOMAIN_NAME_LEN + 4];
PIP_ADDR_STRING CurrentDnsServer;
IP_ADDR_STRING DnsServerList;
UINT NodeType;
char ScopeId [MAX_SCOPE_ID_LEN + 4];
UINT EnableRouting;
UINT EnableProxy;
UINT EnableDns;
} FIXED_INFO, *PFIXED_INFO;

All its fields are self-documented and intuitive enough, so we will just cover them briefly here, mainly for reference purposes:

Field Description
HostName Name of your PDA, which you may change on the Settings\System\About\DeviceID page
DomainName This field will be empty in many cases because mobile devices usually do not belong to any domain
CurrentDnsServer Not used under Windows CE
DnsServerList Linked list of IP_ADDR_STRING structures holding info about defined DSN servers
NodeType Specifies whether the local computer a uses dynamic host configuration protocol (DHCP) Usually has a HYBRID_NODETYPE value
ScopeId Specifies the DHCP scope name
EnableRouting Specifies whether routing is enabled on the local computer. Usually equals 0 on Windows CE
EnableProxy Specifies whether the local computer is acting as an ARP proxy. Usually equals 0 on Windows CE
EnableDns Specifies whether DNS is enabled on the local computer

To complete this topic, let's consider a simple code sample that retrieves info from the system:

void CNWParamsDlg::OnButtonQuery()
{
   FIXED_INFO FixedInfo;
   ULONG OutBufLen = sizeof(FixedInfo);
   DWORD dwRet = GetNetworkParams(&FixedInfo, &OutBufLen);
   if ( dwRet == NO_ERROR )
   {
      TRACE(L"OK\n");
      ShowDSN(&FixedInfo);
   }
   else if ( dwRet == ERROR_BUFFER_OVERFLOW )
   {
      TRACE(L"Error: size = %lu\n",OutBufLen);
      BYTE *pBuffer = new BYTE[OutBufLen];
      PFIXED_INFO pInfo = (PFIXED_INFO)pBuffer;
      dwRet = GetNetworkParams(pInfo, &OutBufLen);
      if ( dwRet == NO_ERROR )
      {
         TRACE(L"OK\n");
         ShowDSN(pInfo);
      }
      delete [] pBuffer;
   }
}

void CNWParamsDlg::ShowDSN(PFIXED_INFO pInfo)
{
   m_ListBox.ResetContent();
   m_ListBox.AddString(CString(pInfo->
                       DnsServerList.IpAddress.String));
   IP_ADDR_STRING * pIPAddr = pInfo->DnsServerList.Next;
   while ( pIPAddr )
   {
      m_ListBox.AddString(CString(pIPAddr->IpAddress.String));
      pIPAddr = pIPAddr->Next;
   }
   ((CStatic*)GetDlgItem(IDC_STATIC_INFO))->SetWindowText(L"DNS:");
}

Getting the Adapter's Info

With the IP Helper API, you can manage network adapters. An adapter is a datalink-level abstraction for network stuff. Later in this article, you will find one more similar term—an interface, which is an IP-level abstraction.

There are several functions that provide all necessary information about adapters:

  • GetAdaptersInfo: Returns an array of IP_ADAPTER_INFO structures, one for each adapter
  • GetPerAdapterInfo: Returns additional information about a specific adapter in the IP_PER_ADAPTER_INFO struct
  • GetAdapterIndex: Returns the adapter index from the adapter name

The next code snippet shows how to obtain info about all available adapters:

void CNWParamsDlg::ShowAdapters(PIP_ADAPTER_INFO pAdapterInfo)
{
   m_ListBox.ResetContent();
   do
   {
      m_ListBox.AddString(L"Adapter: " +
                          CString(pAdapterInfo->AdapterName));
      m_ListBox.AddString(L"   Desc: " +
                          CString(pAdapterInfo->Description));

      if(pAdapterInfo->AddressLength>0)
      {
         CString strToChar;
         CString strCurrentMac;
         BYTE *pAddress = pAdapterInfo->Address;
         for(int nCount=0; nCount-pAdapterInfo->
             AddressLength;nCount++,pAddress++)
         {
            strToChar.Format(L"%02X",*pAddress);
            strCurrentMac+=strToChar;
            if ( nCount + 1 < pAdapterInfo->AddressLength )
               strCurrentMac += L":";
         }
         m_ListBox.AddString(L"   MAC: " + strCurrentMac);
      }
      pAdapterInfo = pAdapterInfo->Next;
   }
   while(pAdapterInfo);

   ((CStatic*)GetDlgItem(IDC_STATIC_INFO))->
      SetWindowText(L"Adapters:");
}

void CNWParamsDlg::OnButtonAdapters()
{
   IP_ADAPTER_INFO *pAdapterInfo = NULL;
   ULONG ulBufLen = 0;
   int nErr = ERROR_SUCCESS;

   nErr = GetAdaptersInfo(pAdapterInfo,&ulBufLen);

   // If buffer size is smaller - allocate memory and try again
   if ( nErr == ERROR_BUFFER_OVERFLOW )
   {
      pAdapterInfo = (IP_ADAPTER_INFO *)new char[ulBufLen];

      nErr = GetAdaptersInfo(pAdapterInfo,&ulBufLen);

      if( nErr == ERROR_SUCCESS )
      {
         ShowAdapters(pAdapterInfo);
         return;
      }
   }
}

This sample gives you a common example of IP Helper API data structures. Most of them contain a linked list of the same structs, so you should iterate through it to get desired info. The IP_ADAPTER_INFO struct keeps details about various network parameters per specific adapter; for example, WINS, Gateway, DHCP, and so on:

typedef struct _IP_ADAPTER_INFO {
   struct _IP_ADAPTER_INFO* Next;
   DWORD ComboIndex;
   char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
   char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
   UINT AddressLength;
   BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
   DWORD Index;
   UINT Type;
   UINT DhcpEnabled;
   PIP_ADDR_STRING CurrentIpAddress;
   IP_ADDR_STRING IpAddressList;
   IP_ADDR_STRING GatewayList;
   IP_ADDR_STRING DhcpServer;
   BOOL HaveWins;
   IP_ADDR_STRING PrimaryWinsServer;
   IP_ADDR_STRING SecondaryWinsServer;
   time_t LeaseObtained;
   time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;

The sample above displays only a small part of the available information: name, description, and MAC address. The last one may be useful to identify a specific device because a MAC address is a unique number. Let me leave all the rest of this type of API calls for you to play with.

Getting Interfaces Info

The last section of the IP Helper API we will consider in this article is obtaining different info about network interfaces. As noted above, an interface is an IP-level abstraction for network stuff. Similarily to adapters, you can retrieve all required data by calling the following functions:

  • GetInterfaceInfo: To obtain a list of the network interface adapters
  • GetIfTable: To obtain the MIB-II interface table
  • GetIfEntry: To obtain info for specific interface
  • GetBestInterface or GetBestInterfaceEx: To obtain the best interface index for specified host address

The simplest case is the GetInterfaceInfo function:

void CNWParamsDlg::ShowInterfaces(PIP_INTERFACE_INFO pIfTable)
{
   m_ListBox.ResetContent();
   CString sTmp;
   sTmp.Format(L"Num Adapters: %d",pIfTable->NumAdapters);
   m_ListBox.AddString(sTmp);

   PIP_ADAPTER_INDEX_MAP pAdapter = pIfTable->Adapter;
   for (int i = 0; i < pIfTable->NumAdapters; i++)
   {
      sTmp.Format(L"Idx: %lu Name: %s", pIfTable->Adapter[i].Index,
                                        pIfTable->Adapter[i].Name);
      m_ListBox.AddString(sTmp);
   }

   ((CStatic*)GetDlgItem(IDC_STATIC_INFO))->
      SetWindowText(L"Interfaces:");
}

void CNWParamsDlg::OnInterfaces()
{
   ULONG dwOutBufLen = 0;
   DWORD dwRes       = GetInterfaceInfo(NULL,&dwOutBufLen);

   PIP_INTERFACE_INFO pIfTable =
      (PIP_INTERFACE_INFO)new BYTE[dwOutBufLen];
   dwRes = GetInterfaceInfo(pIfTable,&dwOutBufLen);

   TRACE(L"dwRes = %lu\n",dwRes);
   if ( dwRes == 0 )
      ShowInterfaces(pIfTable);
}

It lists all existing interfaces and adapters. There is nothing to discuss anything regarding this function, so let's move to the next ones.

GetIfTable returns interface table content into its pIfTable parameter:

typedef struct _MIB_IFTABLE {
   DWORD dwNumEntries;
   MIB_IFROW table[ANY_SIZE];
} MIB_IFTABLE, *PMIB_IFTABLE;

Each row in this table is presented by a MIB_IFROW struct. In turn, MIB_IFROW contains a lot of useful information:

typedef struct _MIB_IFROW {
   WCHAR wszName[MAX_INTERFACE_NAME_LEN];
   DWORD dwIndex;
   DWORD dwType;
   DWORD dwMtu;
   DWORD dwSpeed;
   DWORD dwPhysAddrLen;
   BYTE bPhysAddr[MAXLEN_PHYSADDR];
   DWORD dwAdminStatus;
   DWORD dwOperStatus;
   DWORD dwLastChange;
   DWORD dwInOctets;
   DWORD dwInUcastPkts;
   DWORD dwInNUcastPkts;
   DWORD dwInDiscards;
   DWORD dwInErrors;
   DWORD dwInUnknownProtos;
   DWORD dwOutOctets;
   DWORD dwOutUcastPkts;
   DWORD dwOutNUcastPkts;
   DWORD dwOutDiscards;
   DWORD dwOutErrors;
   DWORD dwOutQLen;
   DWORD dwDescrLen;
   BYTE bDescr[MAXLEN_IFDESCR];
} MIB_IFROW, *PMIB_IFROW;

As you see, there is a lot of informative data here. I'd like to highlight the following fields:

  • WCHAR wszName[MAX_INTERFACE_NAME_LEN];
  • DWORD dwIndex;
  • DWORD dwType;
  • DWORD dwMtu;
  • DWORD dwSpeed;
  • DWORD dwDescrLen;
  • BYTE bDescr[MAXLEN_IFDESCR];

For example, knowing dwMtu for a specific interface may significantly reduce network traffic if you will use the same block size in transmission. You can be interested in other parameters too for some reasons, depending on the application type you are developing. As a final shot, the snippet below shows how to select the best network interface for a specific IP.

void CNWParamsDlg::OnBestInterface()
{
   IPAddr dwDestAddr = inet_addr("63.236.73.167");
   DWORD dwBestIfIndex = -1;
   DWORD dwRes = GetBestInterface(dwDestAddr, &dwBestIfIndex);

   CString sTmp;
   sTmp.Format(L"Best Index : %lu - ",dwBestIfIndex);

   MIB_IFROW IfRow;
   IfRow.dwIndex = dwBestIfIndex;
   dwRes = GetIfEntry(&IfRow);

   m_ListBox.ResetContent();
   m_ListBox.AddString(sTmp + IfRow.wszName);
   ((CStatic*)GetDlgItem(IDC_STATIC_INFO))->
      SetWindowText(L"Best Interface Index:");
}

And that's all for today! New articles are coming soon.

Download

Download the accompanying code's zip file here

About the Author

Alex Gusev started to play with mainframes at the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers' lives in the mobile jungles a little bit simpler.

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved