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