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
21using Poco::TimeoutException;
22using Poco::Timespan;
23using Poco::Exception;
24
25
26namespace Poco {
27namespace Net {
28
29
30ICMPSocketImpl::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
42ICMPSocketImpl::~ICMPSocketImpl()
43{
44}
45
46
47int 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
54int 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