Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
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
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
00054 boost::asio::streambuf request_buffer;
00055 std::ostream os(&request_buffer);
00056 os << echo_request << body;
00057
00058
00059 time_sent_ = posix_time::microsec_clock::universal_time();
00060 socket_.send_to(request_buffer.data(), destination_);
00061
00062
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
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
00084 reply_buffer_.consume(reply_buffer_.size());
00085
00086
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
00094
00095 reply_buffer_.commit(length);
00096
00097
00098 std::istream is(&reply_buffer_);
00099 ipv4_header ipv4_hdr;
00100 icmp_header icmp_hdr;
00101 is >> ipv4_hdr >> icmp_hdr;
00102
00103
00104
00105
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
00111 if (num_replies_++ == 0)
00112 timer_.cancel();
00113
00114
00115 posix_time::ptime now = posix_time::microsec_clock::universal_time();
00116 delay = (now - time_sent_).total_nanoseconds()/(1000.0*1000);
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
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