1 | // |
2 | // ICMPSocketImpl.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: ICMP |
6 | // Module: ICMPSocketImpl |
7 | // |
8 | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Net/ICMPSocketImpl.h" |
16 | #include "Poco/Net/NetException.h" |
17 | #include "Poco/Format.h" |
18 | #include "Poco/Buffer.h" |
19 | |
20 | |
21 | using Poco::TimeoutException; |
22 | using Poco::Timespan; |
23 | using Poco::Exception; |
24 | |
25 | |
26 | namespace Poco { |
27 | namespace Net { |
28 | |
29 | |
30 | ICMPSocketImpl::ICMPSocketImpl(IPAddress::Family family, int dataSize, int ttl, int timeout): |
31 | RawSocketImpl(family, IPPROTO_ICMP), |
32 | _icmpPacket(family, dataSize), |
33 | _ttl(ttl), |
34 | _timeout(timeout) |
35 | { |
36 | setOption(IPPROTO_IP, IP_TTL, ttl); |
37 | setBlocking(true); |
38 | setReceiveTimeout(Timespan(timeout)); |
39 | } |
40 | |
41 | |
42 | ICMPSocketImpl::~ICMPSocketImpl() |
43 | { |
44 | } |
45 | |
46 | |
47 | int ICMPSocketImpl::sendTo(const void*, int, const SocketAddress& address, int flags) |
48 | { |
49 | int n = SocketImpl::sendTo(_icmpPacket.packet(), _icmpPacket.packetSize(), address, flags); |
50 | return n; |
51 | } |
52 | |
53 | |
54 | int ICMPSocketImpl::receiveFrom(void*, int, SocketAddress& address, int flags) |
55 | { |
56 | int maxPacketSize = _icmpPacket.maxPacketSize(); |
57 | Poco::Buffer<unsigned char> buffer(maxPacketSize); |
58 | |
59 | try |
60 | { |
61 | Poco::Timestamp ts; |
62 | int rc; |
63 | int expected = _icmpPacket.packetSize(); |
64 | do |
65 | { |
66 | // guard against a DoS attack |
67 | if (ts.isElapsed(_timeout)) throw TimeoutException(); |
68 | buffer.clear(); |
69 | SocketAddress respAddr; |
70 | rc = SocketImpl::receiveFrom(buffer.begin(), expected, respAddr, flags); |
71 | if (rc == 0) break; |
72 | if (respAddr == address) |
73 | { |
74 | expected -= rc; |
75 | if (expected == 0) |
76 | { |
77 | if (_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)) break; |
78 | std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize); |
79 | if (!err.empty()) throw ICMPException(err); |
80 | throw ICMPException("Invalid ICMP reply" ); |
81 | } |
82 | } |
83 | else |
84 | { |
85 | throw ICMPException(Poco::format("Reply from an unknown IP address " |
86 | "(requested %s, received %s)." , |
87 | address.host().toString(), respAddr.host().toString())); |
88 | } |
89 | } |
90 | while (expected && !_icmpPacket.validReplyID(buffer.begin(), maxPacketSize)); |
91 | } |
92 | catch (ICMPException&) |
93 | { |
94 | throw; |
95 | } |
96 | catch (Exception&) |
97 | { |
98 | std::string err = _icmpPacket.errorDescription(buffer.begin(), maxPacketSize); |
99 | if (!err.empty()) |
100 | throw ICMPException(err); |
101 | else |
102 | throw; |
103 | } |
104 | |
105 | struct timeval then = _icmpPacket.time(buffer.begin(), maxPacketSize); |
106 | struct timeval now = _icmpPacket.time(); |
107 | |
108 | int elapsed = (((now.tv_sec * 1000000) + now.tv_usec) - ((then.tv_sec * 1000000) + then.tv_usec))/1000; |
109 | |
110 | return elapsed; |
111 | } |
112 | |
113 | |
114 | } } // namespace Poco::Net |
115 | |