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-​2018·​Christopher·​M.​·​Kohlhoff·​(chris·​at·​kohlhoff·​dot·​com)​5 /​/​·​Copyright·​(c)​·​2003-​2018·​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:​:​steady_timer;​23 using·​asio:​:​steady_timer;​
22 namespace·​chrono·​=·​asio:​:​chrono;​
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_·​=·​steady_timer:​:​clock_type:​:​now()​;​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_​·​+·​chrono:​:​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_​·​+·​chrono:​:​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 ·​·​·​·​·​·​chrono:​:​steady_clock:​:​time_point·​now·​=·​chrono:​:​steady_clock:​:​now()​;​111 ·​·​·​·​·​·​auto·​now·​=·​steady_timer:​:​clock_type:​:​now()​;​
110 ·​·​·​·​·​·​chrono:​:​steady_clock:​:​duration·​elapsed·​=·​now·​-​·​time_sent_;​
111 ·​·​·​·​·​·​std:​:​cout·​<<·​length·​-​·​ipv4_hdr.​header_length()​112 ·​·​·​·​·​·​std:​:​cout·​<<·​length·​-​·​ipv4_hdr.​header_length()​
112 ·​·​·​·​·​·​·​·​<<·​"·​bytes·​from·​"·​<<·​ipv4_hdr.​source_address()​113 ·​·​·​·​·​·​·​·​<<·​"·​bytes·​from·​"·​<<·​ipv4_hdr.​source_address()​
113 ·​·​·​·​·​·​·​·​<<·​":​·​icmp_seq="·​<<·​icmp_hdr.​sequence_number()​114 ·​·​·​·​·​·​·​·​<<·​":​·​icmp_seq="·​<<·​icmp_hdr.​sequence_number()​
114 ·​·​·​·​·​·​·​·​<<·​",​·​ttl="·​<<·​ipv4_hdr.​time_to_live()​115 ·​·​·​·​·​·​·​·​<<·​",​·​ttl="·​<<·​ipv4_hdr.​time_to_live()​
115 ·​·​·​·​·​·​·​·​<<·​",​·​time="116 ·​·​·​·​·​·​·​·​<<·​",​·​time="·​<<·​(now·​-​·​time_sent_)​.​total_milliseconds()​·​<<·​"·​ms"
116 ·​·​·​·​·​·​·​·​<<·​chrono:​:​duration_cast<chrono:​:​milliseconds>(elapsed​)​.​count()​
117 ·​·​·​·​·​·​·​·​<<·​std:​:​endl;​117 ·​·​·​·​·​·​·​·​<<·​std:​:​endl;​
118 ·​·​·​·​}118 ·​·​·​·​}
119 119
120 ·​·​·​·​start_receive()​;​120 ·​·​·​·​start_receive()​;​
121 ·​·​}121 ·​·​}
122 122
123 ·​·​static·​unsigned·​short·​get_identifier()​123 ·​·​static·​unsigned·​short·​get_identifier()​
124 ·​·​{124 ·​·​{
125 #if·​defined(ASIO_WINDOWS)​125 #if·​defined(ASIO_WINDOWS)​
126 ·​·​·​·​return·​static_cast<unsigned·​short>(:​:​GetCurrentProcessId()​)​;​126 ·​·​·​·​return·​static_cast<unsigned·​short>(:​:​GetCurrentProcessId()​)​;​
127 #else127 #else
128 ·​·​·​·​return·​static_cast<unsigned·​short>(:​:​getpid()​)​;​128 ·​·​·​·​return·​static_cast<unsigned·​short>(:​:​getpid()​)​;​
129 #endif129 #endif
130 ·​·​}130 ·​·​}
131 131
132 ·​·​icmp:​:​resolver·​resolver_;​132 ·​·​icmp:​:​resolver·​resolver_;​
133 ·​·​icmp:​:​endpoint·​destination_;​133 ·​·​icmp:​:​endpoint·​destination_;​
134 ·​·​icmp:​:​socket·​socket_;​134 ·​·​icmp:​:​socket·​socket_;​
135 ·​·​steady_timer·​timer_;​135 ·​·​steady_timer·​timer_;​
136 ·​·​unsigned·​short·​sequence_number_;​136 ·​·​unsigned·​short·​sequence_number_;​
137 ·​·​chrono:​:​steady_clock:​:​time_point·​time_sent_;​137 ·​·​steady_timer:​:​clock_type:​:​time_point·​time_sent_;​
138 ·​·​asio:​:​streambuf·​reply_buffer_;​138 ·​·​std:​:​string·​reply_buffer_;​
139 ·​·​std:​:​size_t·​num_replies_;​139 ·​·​std:​:​size_t·​num_replies_;​
140 };​140 };​
141 141
142 int·​main(int·​argc,​·​char*·​argv[])​142 int·​main(int·​argc,​·​char*·​argv[])​
143 {143 {
144 ·​·​try144 ·​·​try
145 ·​·​{145 ·​·​{
146 ·​·​·​·​if·​(argc·​!=·​2)​146 ·​·​·​·​if·​(argc·​!=·​2)​
147 ·​·​·​·​{147 ·​·​·​·​{
148 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​ping·​<host>"·​<<·​std:​:​endl;​148 ·​·​·​·​·​·​std:​:​cerr·​<<·​"Usage:​·​ping·​<host>"·​<<·​std:​:​endl;​
149 #if·​!defined(ASIO_WINDOWS​)​149 #if·​!defined(ASIO_WINDOWS​)​
150 ·​·​·​·​·​·​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;​
151 #endif151 #endif
152 ·​·​·​·​·​·​return·​1;​152 ·​·​·​·​·​·​return·​1;​
153 ·​·​·​·​}153 ·​·​·​·​}
154 154
155 ·​·​·​·​asio:​:​io_context·​io_context;​155 ·​·​·​·​asio:​:​io_context·​io_context;​
156 ·​·​·​·​pinger·​p(io_context,​·​argv[1])​;​156 ·​·​·​·​pinger·​p(io_context,​·​argv[1])​;​
157 ·​·​·​·​io_context.​run()​;​157 ·​·​·​·​io_context.​run()​;​
158 ·​·​}158 ·​·​}
159 ·​·​catch·​(std:​:​exception&·​e)​159 ·​·​catch·​(std:​:​exception&·​e)​
160 ·​·​{160 ·​·​{
161 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​161 ·​·​·​·​std:​:​cerr·​<<·​"Exception:​·​"·​<<·​e.​what()​·​<<·​std:​:​endl;​
162 ·​·​}162 ·​·​}
163 }163 }