]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/asio/example/cpp03/icmp/ping.cpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / boost / libs / asio / example / cpp03 / icmp / ping.cpp
CommitLineData
7c673cae
FG
1//
2// ping.cpp
3// ~~~~~~~~
4//
1e59de90 5// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7c673cae
FG
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#include <boost/asio.hpp>
f67539c2 12#include <boost/bind/bind.hpp>
7c673cae
FG
13#include <istream>
14#include <iostream>
15#include <ostream>
16
17#include "icmp_header.hpp"
18#include "ipv4_header.hpp"
19
20using boost::asio::ip::icmp;
11fdf7f2
TL
21using boost::asio::steady_timer;
22namespace chrono = boost::asio::chrono;
7c673cae
FG
23
24class pinger
25{
26public:
b32b8144
FG
27 pinger(boost::asio::io_context& io_context, const char* destination)
28 : resolver_(io_context), socket_(io_context, icmp::v4()),
29 timer_(io_context), sequence_number_(0), num_replies_(0)
7c673cae 30 {
b32b8144 31 destination_ = *resolver_.resolve(icmp::v4(), destination, "").begin();
7c673cae
FG
32
33 start_send();
34 start_receive();
35 }
36
37private:
38 void start_send()
39 {
40 std::string body("\"Hello!\" from Asio ping.");
41
42 // Create an ICMP header for an echo request.
43 icmp_header echo_request;
44 echo_request.type(icmp_header::echo_request);
45 echo_request.code(0);
46 echo_request.identifier(get_identifier());
47 echo_request.sequence_number(++sequence_number_);
48 compute_checksum(echo_request, body.begin(), body.end());
49
50 // Encode the request packet.
51 boost::asio::streambuf request_buffer;
52 std::ostream os(&request_buffer);
53 os << echo_request << body;
54
55 // Send the request.
11fdf7f2 56 time_sent_ = steady_timer::clock_type::now();
7c673cae
FG
57 socket_.send_to(request_buffer.data(), destination_);
58
59 // Wait up to five seconds for a reply.
60 num_replies_ = 0;
11fdf7f2 61 timer_.expires_at(time_sent_ + chrono::seconds(5));
7c673cae
FG
62 timer_.async_wait(boost::bind(&pinger::handle_timeout, this));
63 }
64
65 void handle_timeout()
66 {
67 if (num_replies_ == 0)
68 std::cout << "Request timed out" << std::endl;
69
70 // Requests must be sent no less than one second apart.
11fdf7f2 71 timer_.expires_at(time_sent_ + chrono::seconds(1));
7c673cae
FG
72 timer_.async_wait(boost::bind(&pinger::start_send, this));
73 }
74
75 void start_receive()
76 {
77 // Discard any data already in the buffer.
78 reply_buffer_.consume(reply_buffer_.size());
79
80 // Wait for a reply. We prepare the buffer to receive up to 64KB.
81 socket_.async_receive(reply_buffer_.prepare(65536),
f67539c2 82 boost::bind(&pinger::handle_receive, this, boost::placeholders::_2));
7c673cae
FG
83 }
84
85 void handle_receive(std::size_t length)
86 {
87 // The actual number of bytes received is committed to the buffer so that we
88 // can extract it using a std::istream object.
89 reply_buffer_.commit(length);
90
91 // Decode the reply packet.
92 std::istream is(&reply_buffer_);
93 ipv4_header ipv4_hdr;
94 icmp_header icmp_hdr;
95 is >> ipv4_hdr >> icmp_hdr;
96
97 // We can receive all ICMP packets received by the host, so we need to
98 // filter out only the echo replies that match the our identifier and
99 // expected sequence number.
100 if (is && icmp_hdr.type() == icmp_header::echo_reply
101 && icmp_hdr.identifier() == get_identifier()
102 && icmp_hdr.sequence_number() == sequence_number_)
103 {
104 // If this is the first reply, interrupt the five second timeout.
105 if (num_replies_++ == 0)
106 timer_.cancel();
107
108 // Print out some information about the reply packet.
11fdf7f2
TL
109 chrono::steady_clock::time_point now = chrono::steady_clock::now();
110 chrono::steady_clock::duration elapsed = now - time_sent_;
7c673cae
FG
111 std::cout << length - ipv4_hdr.header_length()
112 << " bytes from " << ipv4_hdr.source_address()
113 << ": icmp_seq=" << icmp_hdr.sequence_number()
114 << ", ttl=" << ipv4_hdr.time_to_live()
11fdf7f2
TL
115 << ", time="
116 << chrono::duration_cast<chrono::milliseconds>(elapsed).count()
7c673cae
FG
117 << std::endl;
118 }
119
120 start_receive();
121 }
122
123 static unsigned short get_identifier()
124 {
125#if defined(BOOST_ASIO_WINDOWS)
126 return static_cast<unsigned short>(::GetCurrentProcessId());
127#else
128 return static_cast<unsigned short>(::getpid());
129#endif
130 }
131
132 icmp::resolver resolver_;
133 icmp::endpoint destination_;
134 icmp::socket socket_;
11fdf7f2 135 steady_timer timer_;
7c673cae 136 unsigned short sequence_number_;
11fdf7f2 137 chrono::steady_clock::time_point time_sent_;
7c673cae
FG
138 boost::asio::streambuf reply_buffer_;
139 std::size_t num_replies_;
140};
141
142int main(int argc, char* argv[])
143{
144 try
145 {
146 if (argc != 2)
147 {
148 std::cerr << "Usage: ping <host>" << std::endl;
149#if !defined(BOOST_ASIO_WINDOWS)
150 std::cerr << "(You may need to run this program as root.)" << std::endl;
151#endif
152 return 1;
153 }
154
b32b8144
FG
155 boost::asio::io_context io_context;
156 pinger p(io_context, argv[1]);
157 io_context.run();
7c673cae
FG
158 }
159 catch (std::exception& e)
160 {
161 std::cerr << "Exception: " << e.what() << std::endl;
162 }
163}