4 * ICMP socket class implementation.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.15 2002/10/10 04:43:44 robertj
31 * VxWorks port, thanks Martijn Roest
33 * Revision 1.14 2001/09/10 03:03:36 robertj
34 * Major change to fix problem with error codes being corrupted in a
35 * PChannel when have simultaneous reads and writes in threads.
37 * Revision 1.13 2001/06/30 06:59:07 yurik
38 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
40 * Revision 1.12 2001/03/07 07:00:17 yurik
41 * #ifdef'd setsockopt IPPROTO_IP for BeOS
43 * Revision 1.11 2001/03/06 22:20:21 craigs
44 * Fixed TTL and other stuff so that traceroute is almost possible!
46 * Revision 1.10 1999/08/09 04:06:39 robertj
47 * Change to avoid name space problem with X windows library
49 * Revision 1.9 1999/02/22 13:26:54 robertj
52 * Revision 1.8 1998/11/30 21:52:06 robertj
53 * New directory structure.
55 * Revision 1.7 1998/09/24 04:12:29 robertj
56 * Added open software license.
58 * Revision 1.6 1998/08/26 01:45:56 craigs
59 * Fixed error in IPHdr
61 * Revision 1.5 1998/01/26 07:27:09 robertj
62 * Added part support for extra ping info. Still needs TTL for traceroute.
64 * Revision 1.4 1996/11/16 11:12:56 craigs
65 * Fixed problem with work misaligns under SOlaris
67 * Revision 1.3 1996/10/31 10:20:07 craigs
68 * Moved ICMP implementation into here, as it is now platform dependent
70 * Revision 1.6 1996/09/14 13:09:34 robertj
72 * rearranged sockets to help support IPX.
73 * added indirect channel class and moved all protocols to descend from it,
74 * separating the protocol from the low level byte transport.
76 * Revision 1.5 1996/08/11 06:52:14 robertj
79 * Revision 1.4 1996/08/07 13:40:57 robertj
80 * Fixed sparc memory alignment problem from int 64
82 * Revision 1.3 1996/06/03 10:03:10 robertj
83 * Changed ping to return more parameters.
85 * Revision 1.2 1996/05/30 10:08:51 robertj
86 * Fixed bug in ping (checksum incorrect).
88 * Revision 1.1 1996/05/15 21:11:35 robertj
93 #pragma implementation "icmpsock.h"
96 #include <ptlib/sockets.h>
99 #define MAX_ICMP_LEN 76
100 #define ICMP_DATA_LEN (64-8)
101 #define RX_BUFFER_SIZE (MAX_IP_LEN+MAX_ICMP_LEN+ICMP_DATA_LEN)
103 #define ICMP_ECHO_REPLY 0
106 #define ICMP_TIMXCEED 11
118 BYTE data
[ICMP_DATA_LEN
-sizeof(PInt64
)];
136 static WORD
CalcChecksum(void * p
, PINDEX len
)
138 WORD
* ptr
= (WORD
*)p
;
146 WORD t
= *(BYTE
*)ptr
;
150 sum
= (sum
>> 16) + (sum
& 0xffff);
156 PICMPSocket::PICMPSocket()
162 BOOL
PICMPSocket::Ping(const PString
& host
)
165 return Ping(host
, info
);
169 BOOL
PICMPSocket::Ping(const PString
& host
, PingInfo
& info
)
171 if (!WritePing(host
, info
))
174 return ReadPing(info
);
178 BOOL
PICMPSocket::WritePing(const PString
& host
, PingInfo
& info
)
180 // find address of the host
181 PIPSocket::Address addr
;
182 if (!GetHostAddress(host
, addr
))
183 return SetErrorValues(BadParameter
, EINVAL
);
185 // create the ICMP packet
188 // clear the packet including data area
189 memset(&packet
, 0, sizeof(packet
));
191 packet
.type
= ICMP_ECHO
;
192 packet
.sequence
= info
.sequenceNum
;
193 packet
.id
= info
.identifier
;
197 char ttl
= (char)info
.ttl
;
198 if (::setsockopt(os_handle
, IPPROTO_IP
, IP_TTL
, &ttl
, sizeof(ttl
)) != 0)
204 packet
.sendtime
= PTimer::Tick().GetMilliSeconds();
206 // calculate the checksum
207 packet
.checksum
= CalcChecksum(&packet
, sizeof(packet
));
210 return WriteTo(&packet
, sizeof(packet
), addr
, 0);
214 BOOL
PICMPSocket::ReadPing(PingInfo
& info
)
217 BYTE packet
[RX_BUFFER_SIZE
];
219 ICMPPacket
* icmpPacket
;
222 PTimer
timeout(GetReadTimeout());
225 memset(&packet
, 0, sizeof(packet
));
227 if (!ReadFrom(packet
, sizeof(packet
), info
.remoteAddr
, port
))
230 now
= PTimer::Tick().GetMilliSeconds();
231 ipHdr
= (IPHdr
*)packet
;
232 icmpPacket
= (ICMPPacket
*)(packet
+ ((ipHdr
->verIhl
& 0xf) << 2));
234 if (( icmpPacket
->type
== ICMP_ECHO_REPLY
) &&
235 ((WORD
)icmpPacket
->id
== info
.identifier
)) {
236 info
.status
= PingSuccess
;
240 if (icmpPacket
->type
== ICMP_TIMXCEED
) {
241 info
.status
= TtlExpiredTransmit
;
245 if (!timeout
.IsRunning())
249 info
.remoteAddr
= Address(ipHdr
->sourceAddr
[0], ipHdr
->sourceAddr
[1],
250 ipHdr
->sourceAddr
[2], ipHdr
->sourceAddr
[3]);
251 info
.localAddr
= Address(ipHdr
->destAddr
[0], ipHdr
->destAddr
[1],
252 ipHdr
->destAddr
[2], ipHdr
->destAddr
[3]);
254 // calc round trip time. Be careful, as unaligned "long long" ints
255 // can cause problems on some platforms
256 #if defined(P_SUN4) || defined(P_SOLARIS)
258 BYTE
* pthen
= (BYTE
*)&then
;
259 BYTE
* psendtime
= (BYTE
*)&icmpPacket
->sendtime
;
260 memcpy(pthen
, psendtime
, sizeof(PInt64
));
261 info
.delay
.SetInterval(now
- then
);
263 info
.delay
.SetInterval(now
- icmpPacket
->sendtime
);
266 info
.sequenceNum
= icmpPacket
->sequence
;
272 BOOL
PICMPSocket::OpenSocket()
274 #if !defined BE_BONELESS && !defined(P_VXWORKS)
275 struct protoent
* p
= ::getprotobyname(GetProtocolName());
277 return ConvertOSError(-1);
278 return ConvertOSError(os_handle
= os_socket(AF_INET
, SOCK_RAW
, p
->p_proto
));
279 #else // Raw sockets not supported in BeOS R4 or VxWorks.
280 return ConvertOSError(os_handle
= os_socket(AF_INET
, SOCK_DGRAM
, IPPROTO_ICMP
));
281 #endif //!defined BE_BONELESS && !defined(P_VXWORKS)
285 const char * PICMPSocket::GetProtocolName() const
291 PICMPSocket::PingInfo::PingInfo(WORD id
)
297 status
= PingSuccess
;
301 // End Of File ///////////////////////////////////////////////////////////////