dcsimg

Creating a Multi-Threaded Trace Route

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


.

Environment: VC6, NT4/Win2K—should work on any 32-bit Windows operating system that has Winsock2 libraries.

Overview

Sample code for a network "ping" is relatively easy to find. CodeGuru has several good examples and the SDK sample code has another good example. So what about trace route? With a little research I discovered that doing a trace route is really no more difficult than a ping. With a few minor modifications to the ping sample, it is possible to do a multi-threaded trace route. Trace route is really just a ping with the "time-to-live" option set to any number from 1 to the number of hops it takes to get to the destination. So, if it takes 10 hops to get to the destination and the "time-to-live" option is set to 5, the IP address that gets returned is the address of the fifth router along the way. The logical question is: "How many hops does it take?" Well, you don't really know until you get there. Basically, you just increment the time-to-live option until the returned IP address matches the destination IP address. The router names can be obtained by a simple call to "gethostbyaddr".

To call this code "multi-threaded" is a bit of a misnomer. The execution of the pings and ultimately the trace route happens in a single thread; the user interface is in a separate thread. All that is accomplished by this approach is that the user may stop the processing and view updates asynchronously.

This code also relies heavily on the Winsock-2 library (ws2_32.lib).

An Outline of the Approach

  1. This process depends on three variables: destination address, returned address (coming back from ping), and ttl (time-to-live).
  2. Get the destination address by calling "gethostbyname". Set the returned address to 0 and ttl to 1.
  3. While the returned address is not equal to the destination address, do the following: call ping, increment the ttl, and get the name of the returned address.

The Sample Code, Implementing the Approach

int TRThread::RunThread(void)
{
  int result = 0; 

  ClearAllItems();
  InitSockLibrary();

  struct hostent *hHost;
  struct sockaddr_in sin;
 
  // get the IP address of the destination
  HOSTENT * ent = gethostbyname(m_address);
  if (CheckKillFlag())
  {
    return result;
  }

  if (ent && ent->h_addrtype == AF_INET)
  {
    in_addr * final_ptr = (struct in_addr*)ent->h_addr_list[0];
    unsigned long ipfinal = final_ptr->S_un.S_addr;

    // initialize returned IP address and time-to-live (ttl)
    int ttl = 1;
    unsigned long ipback = 0;
    unsigned long ms = 0;

    while (ipback != ipfinal){
      hHost = 0; TRDeviceItem * item = new TRDeviceItem;

      // By checking the "kill flag" often, we are trying to
      // provide a responsive and well behaved worker thread.
        if (CheckKillFlag())
        {
          break;
        }

      // send a ping to the destination address, knowing that it
      // will only make it thru (ttl) routers before getting sent
      // back.
        if (Ping(m_address,ttl,ipback,ms))
        {
          sin.sin_family = AF_INET;
          sin.sin_addr.S_un.S_addr = ipback;

        // get the name of the router that bounced the ping back
        // (ipback)
        hHost = gethostbyaddr((char*)&sin.sin_addr, 4, PF_INET);

        // set up an item for the linked list
        item->SetIPAddress((unsigned long)ipback);
        item->SetResponseTime(ms);

        // if the router information is not null, extract the
        // router name
        if (hHost)
        {
          item->SetName(hHost->h_name);
        }
      }
      ttl++;
      if (CheckKillFlag())
      {
        break;
      }

      // synchronize block, locking access to linked list before
      // changing anything
      Wait();
      {
        // add the item to the linked list
        if (m_first_item == 0)
        {
          m_first_item = m_current_item = item;
        }
        else
        {
          m_current_item->SetNextItem(item);
          m_current_item = item;
        }

        m_total_items++;
        result++;
      }
      Release();

      // The base class (WorkerThread) stores a synchronized
      // variable usually used to calculate the percentage of
      // work done. This time we are using that variable to
      // store the number of hops so far.
      SetTotal(m_total_items); // If we're over the maximum number
                               // of hops, let's break outta here.
      if (ttl > MAX_HOPS)
      {
        break;
      }
    }
  }

  return result;
}

Some Information about the Sample Project

The sample project is basically an SDI application with a ListView. The trace route executes in a thread class derived from WorkerThread and the view class uses a timer to check the thread for updates. To execute the program, simply type in a Web site or Internet address and click Trace.

Downloads

Download demo project - 31 Kb



About the Author

Andy McGovern

Andy McGovern - Software Developer/Engineer. Special interests: astronomy, image processing, orbital mechanics, mathematics. Currently work at the Johns Hopkins University Applied Physics Laboratory on the science operations team for the CRISM instrument on the Mars Reconnaissance Orbiter.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date