ping.cpp
Go to the documentation of this file.
00001 //
00002 // ping.cpp
00003 // ~~~~~~~~
00004 //
00005 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
00006 //
00007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
00008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
00009 //
00010 
00011 #include <boost/asio.hpp>
00012 #include <boost/bind.hpp>
00013 #include <istream>
00014 #include <iostream>
00015 #include <ostream>
00016 
00017 #include "icmp_header.hpp"
00018 #include "ipv4_header.hpp"
00019 
00020 using boost::asio::ip::icmp;
00021 using boost::asio::deadline_timer;
00022 namespace posix_time = boost::posix_time;
00023 
00024 class pinger
00025 {
00026 public:
00027     pinger(boost::asio::io_service& io_service, const char* destination)
00028         : resolver_(io_service), socket_(io_service, icmp::v4()),
00029           timer_(io_service), sequence_number_(0), num_replies_(0)
00030     {
00031         icmp::resolver::query query(icmp::v4(), destination, "");
00032         destination_ = *resolver_.resolve(query);
00033 
00034         start_send();
00035         start_receive();
00036     }
00037 
00038     double delay;
00039 
00040 private:
00041     void start_send()
00042     {
00043         std::string body("\"Hello!\" from Asio ping.");
00044 
00045         // Create an ICMP header for an echo request.
00046         icmp_header echo_request;
00047         echo_request.type(icmp_header::echo_request);
00048         echo_request.code(0);
00049         echo_request.identifier(get_identifier());
00050         echo_request.sequence_number(++sequence_number_);
00051         compute_checksum(echo_request, body.begin(), body.end());
00052 
00053         // Encode the request packet.
00054         boost::asio::streambuf request_buffer;
00055         std::ostream os(&request_buffer);
00056         os << echo_request << body;
00057 
00058         // Send the request.
00059         time_sent_ = posix_time::microsec_clock::universal_time();
00060         socket_.send_to(request_buffer.data(), destination_);
00061 
00062         // Wait up to five seconds for a reply.
00063         num_replies_ = 0;
00064         timer_.expires_at(time_sent_ + posix_time::seconds(5));
00065         timer_.async_wait(boost::bind(&pinger::handle_timeout, this));
00066     }
00067 
00068     void handle_timeout()
00069     {
00070         if (num_replies_ == 0) {
00071           std::cout << "Request timed out" << std::endl;
00072           delay = -1;
00073         }
00074 
00075         // Requests must be sent no less than one second apart.
00076         timer_.expires_at(time_sent_ + posix_time::seconds(1));
00077         timer_.async_wait(boost::bind(&pinger::start_send, this));
00078 
00079     }
00080 
00081     void start_receive()
00082     {
00083         // Discard any data already in the buffer.
00084         reply_buffer_.consume(reply_buffer_.size());
00085 
00086         // Wait for a reply. We prepare the buffer to receive up to 64KB.
00087         socket_.async_receive(reply_buffer_.prepare(65536),
00088                               boost::bind(&pinger::handle_receive, this, _2));
00089     }
00090 
00091     void handle_receive(std::size_t length)
00092     {
00093         // The actual number of bytes received is committed to the buffer so that we
00094         // can extract it using a std::istream object.
00095         reply_buffer_.commit(length);
00096 
00097         // Decode the reply packet.
00098         std::istream is(&reply_buffer_);
00099         ipv4_header ipv4_hdr;
00100         icmp_header icmp_hdr;
00101         is >> ipv4_hdr >> icmp_hdr;
00102 
00103         // We can receive all ICMP packets received by the host, so we need to
00104         // filter out only the echo replies that match the our identifier and
00105         // expected sequence number.
00106         if (is && icmp_hdr.type() == icmp_header::echo_reply
00107             && icmp_hdr.identifier() == get_identifier()
00108             && icmp_hdr.sequence_number() == sequence_number_)
00109             {
00110                 // If this is the first reply, interrupt the five second timeout.
00111                 if (num_replies_++ == 0)
00112                     timer_.cancel();
00113 
00114                 // Print out some information about the reply packet.
00115                 posix_time::ptime now = posix_time::microsec_clock::universal_time();
00116                 delay = (now - time_sent_).total_nanoseconds()/(1000.0*1000); // added
00117                 std::cout << length - ipv4_hdr.header_length()
00118                           << " bytes from " << ipv4_hdr.source_address()
00119                           << ": icmp_seq=" << icmp_hdr.sequence_number()
00120                           << ", ttl=" << ipv4_hdr.time_to_live()
00121                           //<< ", time=" << (now - time_sent_).total_milliseconds() << " ms"
00122                           << ", time=" << delay << " ms"
00123                           << std::endl;
00124             }
00125 
00126         start_receive();
00127     }
00128 
00129     static unsigned short get_identifier()
00130     {
00131 #if defined(BOOST_WINDOWS)
00132         return static_cast<unsigned short>(::GetCurrentProcessId());
00133 #else
00134         return static_cast<unsigned short>(::getpid());
00135 #endif
00136     }
00137 
00138     icmp::resolver resolver_;
00139     icmp::endpoint destination_;
00140     icmp::socket socket_;
00141     deadline_timer timer_;
00142     unsigned short sequence_number_;
00143     posix_time::ptime time_sent_;
00144     boost::asio::streambuf reply_buffer_;
00145     std::size_t num_replies_;
00146 };
00147 
00148 #if 0
00149 int main(int argc, char* argv[])
00150 {
00151   try
00152       {
00153           if (argc != 2)
00154               {
00155                   std::cerr << "Usage: ping <host>" << std::endl;
00156 #if !defined(BOOST_WINDOWS)
00157                   std::cerr << "(You may need to run this program as root.)" << std::endl;
00158 #endif
00159                   return 1;
00160               }
00161 
00162           boost::asio::io_service io_service;
00163           pinger p(io_service, argv[1]);
00164           io_service.run();
00165       }
00166   catch (std::exception& e)
00167       {
00168           std::cerr << "Exception: " << e.what() << std::endl;
00169       }
00170 }
00171 #endif


rosping
Author(s): Kei Okada
autogenerated on Mon Oct 6 2014 11:00:33