User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

    Creating a Multi-Threaded Trace Route



    .

    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 - 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.


    IT Offers


    Top Authors