How to PING

Wrapping Up

I wrapped the ICMP code in a class named appropriately enough Icmp. I also created an IcmpException class that I use to capture and send exceptions down the call stack.

//////////////////////////////////////////////////////////////////////
//
// icmp.h: implementation of the Icmp class.
// Copyright 2001 by KBCafe
//
//////////////////////////////////////////////////////////////////////

#ifndef KBCAFE_ICMP_H
#define KBCAFE_ICMP_H

#include
#include
#include
#include
#include
#include

namespace
{

    class WSAInit
    {
        public:
        WSAInit()
        {
            WORD w = MAKEWORD(1,1);
            WSADATA wsadata;
            ::WSAStartup(w, &wsadata);
        };

        ~WSAInit()
        {
            ::WSACleanup();
        };

    } instance;
};
namespace kbcafe
{

    class IcmpException : public std:: exception
    {
        std:: string m_str;
        public:
        IcmpException()
        {
            m_str = "ICMP exception.\ tWSAGetLastError = "
            +::WSAGetLastError();
        }

        IcmpException(const std:: string &str)
        {
            std::stringstream ss;
            ss << "ICMP exception:"
            << str
            << "\ tWSAGetLastError = "
            << ::WSAGetLastError();
            m_str = ss.str();
        }

        virtual const char * what() const throw()
        {
            return m_str.c_str();
        }
    };

    class Icmp
    {
        static void SendEmptyEcho(const std:: string &strAddress);
    };

    inline void Icmp:: SendEmptyEcho(const std:: string &strAddress)
    {
        hostent * host;
        in_addr inaddr;
        inaddr.s_addr = ::inet_addr(strAddress.c_str());
        if (inaddr.s_addr == INADDR_NONE)
        {
            host = ::gethostbyname(strAddress.c_str());
        }
        else
        {
            host = ::gethostbyaddr((const char *)&inaddr,
            sizeof(inaddr), AF_INET);
        }

        if (host == NULL)
        {
            throw IcmpException("invalid SMTP server");
        }

        HANDLE icmphandle = IcmpCreateFile();
        char reply[sizeof(icmp_echo_reply)+8];
        icmp_echo_reply* iep = (icmp_echo_reply*)&reply;
        iep->RoundTripTime = 0xffffffff;

        DWORD dw = IcmpSendEcho(icmphandle,
            *((u_long*) host->h_addr_list[0]),
            0,0, NULL,
            reply, sizeof(icmp_echo_reply)+8,5000);

        if (dw == 0)
        {
            throw IcmpException("send echo failed");
        }

        IcmpCloseHandle(icmphandle);
        return;
    }

};
#endif

When initially testing the class, I found that it would not work for me. It was Friday, so I knew it had to be one of the Friday reasons, like my brain was fried. True enough it was.

I forgot to initialize the socket library. So, I cut and paste my trusty WSAInit class and I was back off to the races. The WSAInit class has a performance consequence in that it causes the socket initialization code to be called each time the header file is included in a source listing. This performance inhibiter should only occur at startup, but if you need a quicker startup, then moving the WSAInit class to a source listing might help a bit. Finally, I wrote a little script to test my new ICMP code. I conveniently named the code PING.

// ping.cpp : Defines the entry point for the console application.
//

#include
#include "kbcafe/icmp.h"

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage:\t ping [address]";
        return 1;
    }

    try
    {
        kbcafe::Icmp::SendEmptyEcho(argv[1]);
        std::cout << "Success" << std::endl;
    }
    catch(kbcafe::IcmpException &e)
    {
        std::cerr << e.what();
    }

    return 0;
}

This PING utility is not nearly as useful as the one shipped with most OSes, but at least you know how this utility was coded. Try it out, it's not bad.

You can read more about the ICMP protocol in RFC 792.

You might also like...

Comments

About the author

Randy Charles Morin

Randy Charles Morin Canada

Randy's article are Copyright 1998-2003 Randy Charles Morin

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“There's no test like production” - Anon