1//
2// ICMPSocket.cpp
3//
4// Library: Net
5// Package: ICMP
6// Module: ICMPSocket
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/ICMPSocket.h"
16#include "Poco/Net/ICMPSocketImpl.h"
17#include "Poco/Exception.h"
18#include "Poco/Net/NetException.h"
19
20
21using Poco::InvalidArgumentException;
22
23
24namespace Poco {
25namespace Net {
26
27
28ICMPSocket::ICMPSocket(IPAddress::Family family, int dataSize, int ttl, int timeout):
29 Socket(new ICMPSocketImpl(family, dataSize, ttl, timeout))
30{
31}
32
33
34ICMPSocket::ICMPSocket(const Socket& socket):
35 Socket(socket)
36{
37 if (!dynamic_cast<ICMPSocketImpl*>(impl()))
38 throw InvalidArgumentException("Cannot assign incompatible socket");
39}
40
41
42ICMPSocket::ICMPSocket(SocketImpl* pImpl):
43 Socket(pImpl)
44{
45 if (!dynamic_cast<ICMPSocketImpl*>(impl()))
46 throw InvalidArgumentException("Cannot assign incompatible socket");
47}
48
49
50ICMPSocket::~ICMPSocket()
51{
52}
53
54
55ICMPSocket& ICMPSocket::operator = (const Socket& socket)
56{
57 if (dynamic_cast<ICMPSocketImpl*>(socket.impl()))
58 Socket::operator = (socket);
59 else
60 throw InvalidArgumentException("Cannot assign incompatible socket");
61 return *this;
62}
63
64
65int ICMPSocket::sendTo(const SocketAddress& address, int flags)
66{
67 return impl()->sendTo(0, 0, address, flags);
68}
69
70
71int ICMPSocket::receiveFrom(SocketAddress& address, int flags)
72{
73 return impl()->receiveFrom(0, 0, address, flags);
74}
75
76
77int ICMPSocket::dataSize() const
78{
79 return static_cast<ICMPSocketImpl*>(impl())->dataSize();
80}
81
82
83int ICMPSocket::packetSize() const
84{
85 return static_cast<ICMPSocketImpl*>(impl())->packetSize();
86}
87
88
89int ICMPSocket::ttl() const
90{
91 return static_cast<ICMPSocketImpl*>(impl())->ttl();
92}
93
94
95int ICMPSocket::timeout() const
96{
97 return static_cast<ICMPSocketImpl*>(impl())->timeout();
98}
99
100
101Poco::UInt16 ICMPSocket::mtu(const SocketAddress& address, Poco::UInt16 sz)
102{
103 if (address.family() != IPAddress::IPv4) return 0;
104
105 SocketAddress returnAddress(address);
106 for (; sz >= 68 /*RFC791*/; --sz)
107 {
108 ICMPSocket icmpSocket(address.family(), sz);
109
110#ifdef IP_DONTFRAGMENT
111 icmpSocket.setOption(IPPROTO_IP, IP_DONTFRAGMENT, 1);
112#elif defined(IP_MTU_DISCOVER)
113 icmpSocket.setOption(IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DO);
114#elif defined(IP_DONTFRAG)
115 icmpSocket.setOption(IPPROTO_IP, IP_DONTFRAG, 1);
116#else
117 throw NotImplementedException("ICMPSocket::mtu()");
118#endif
119
120 try
121 {
122 icmpSocket.sendTo(address);
123 icmpSocket.receiveFrom(returnAddress);
124 poco_assert_dbg (returnAddress == address);
125 return sz;
126 }
127 catch (ICMPFragmentationException&)
128 {
129 // PMTU fragmentation, continue discovery
130 continue;
131 }
132 catch (NetException& ex)
133 {
134 // local MTU limit, continue discovery
135 if (ex.code() == POCO_EMSGSIZE)
136 continue;
137 }
138 catch (Exception&)
139 {
140 return 0;
141 }
142 }
143 return 0;
144}
145
146
147} } // namespace Poco::Net
148