00001
00002
00003 #include "ace/Ping_Socket.h"
00004
00005 #if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1)
00006
00007 #include "ace/INET_Addr.h"
00008 #include "ace/Log_Msg.h"
00009 #include "ace/OS_NS_string.h"
00010 #include "ace/OS_NS_sys_time.h"
00011 #include "ace/OS_NS_sys_socket.h"
00012
00013 #if !defined (__ACE_INLINE__)
00014 # include "ace/Ping_Socket.inl"
00015 #endif
00016
00017
00018 ACE_RCSID (ace,
00019 Ping_Socket,
00020 "Ping_Socket.cpp,v 1.11 2006/06/19 12:51:17 schmidt Exp")
00021
00022 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00023
00024 ACE_ALLOC_HOOK_DEFINE (ACE_Ping_Socket)
00025
00026 ACE_END_VERSIONED_NAMESPACE_DECL
00027
00028
00029
00030
00031
00032
00033 #if !defined (ACE_WIN32)
00034
00035
00036
00037
00038 #include <netinet/in_systm.h>
00039 #include <netinet/ip.h>
00040 #include <netinet/ip_icmp.h>
00041
00042 #else
00043
00044
00045
00046
00047
00048
00049
00050 #define ICMP_ECHO 8
00051 #define ICMP_ECHOREPLY 0
00052
00053 #pragma pack(1)
00054
00055 struct ip
00056 {
00057 ACE_UINT8 ip_hl:4;
00058 ACE_UINT8 version:4;
00059 ACE_UINT8 tos;
00060 ACE_UINT16 total_len;
00061 ACE_UINT16 ident;
00062 ACE_UINT16 frag_and_flags;
00063 ACE_UINT8 ip_ttl;
00064 ACE_UINT8 proto;
00065 ACE_UINT16 checksum;
00066 ACE_UINT32 sourceIP;
00067 ACE_UINT32 destIP;
00068 };
00069
00070 struct icmp
00071 {
00072 ACE_UINT8 icmp_type;
00073 ACE_UINT8 icmp_code;
00074 ACE_UINT16 icmp_cksum;
00075 ACE_UINT16 icmp_id;
00076 ACE_UINT16 icmp_seq;
00077 ACE_UINT32 icmp_data;
00078 };
00079
00080 #pragma pack()
00081
00082 #endif
00083
00084
00085 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00086
00087 int const ICMP_MIN = 8;
00088 int const ICMP_DATA_LENGTH = 56;
00089 ACE_Time_Value const ACE_Ping_Socket::time_default_ (0, 500000);
00090
00091
00092 void
00093 ACE_Ping_Socket::dump (void) const
00094 {
00095 ACE_TRACE ("ACE_Ping_Socket::dump");
00096 }
00097
00098 ACE_Ping_Socket::ACE_Ping_Socket (void)
00099 {
00100 ACE_TRACE ("ACE_Ping_Socket::ACE_Ping_Socket");
00101 }
00102
00103 ACE_Ping_Socket::ACE_Ping_Socket (ACE_Addr const & local,
00104 int protocol,
00105 int reuse_addr)
00106 : sequence_number_ (0),
00107 connected_socket_ (0)
00108 {
00109 ACE_TRACE ("ACE_Ping_Socket::ACE_Ping_Socket");
00110
00111 ACE_OS::memset (icmp_send_buff_, 0, sizeof (icmp_send_buff_));
00112 ACE_OS::memset (icmp_recv_buff_, 0, sizeof (icmp_recv_buff_));
00113
00114 if (this->open (local, protocol, reuse_addr) == -1)
00115 {
00116 ACE_DEBUG ((LM_DEBUG,
00117 ACE_LIB_TEXT ("ACE_Ping_Socket::ACE_Ping_Socket: %p\n"),
00118 ACE_LIB_TEXT ("open")));
00119 return;
00120 }
00121
00122
00123
00124
00125 int size = 64 * 1024;
00126 ACE_SOCK::set_option (SOL_SOCKET,
00127 SO_RCVBUF,
00128 (void *) &size,
00129 sizeof (size));
00130 }
00131
00132 ACE_Ping_Socket::~ACE_Ping_Socket (void)
00133 {
00134 ACE_TRACE ("ACE_Ping_Socket::~ACE_Ping_Socket");
00135 }
00136
00137 int
00138 ACE_Ping_Socket::open (ACE_Addr const & local,
00139 int protocol,
00140 int reuse_addr)
00141 {
00142 ACE_TRACE ("ACE_Ping_Socket::open");
00143 return inherited::open (local, protocol, reuse_addr);
00144 }
00145
00146 int
00147 ACE_Ping_Socket::receive_echo_reply (ACE_Time_Value const * timeout)
00148 {
00149 ACE_TRACE ("ACE_Ping_Socket::receive_echo_reply");
00150
00151 ACE_Time_Value before = ACE_OS::gettimeofday ();
00152 ACE_Time_Value after;
00153 ACE_Time_Value time_left;
00154 ACE_Time_Value *wait_time = const_cast<ACE_Time_Value *> (timeout);
00155 const ACE_Time_Value half_millisec (0, 500);
00156
00157 ACE_OS::memset (icmp_recv_buff_, 0, sizeof icmp_recv_buff_);
00158
00159 do
00160 {
00161 int rval_recv = inherited::recv (icmp_recv_buff_,
00162 sizeof icmp_recv_buff_,
00163 0,
00164 wait_time);
00165 if (rval_recv < 0)
00166 {
00167 if (errno == EINTR)
00168 {
00169 after = ACE_OS::gettimeofday ();
00170 time_left = *timeout - after + before;
00171
00172
00173 if (time_left > half_millisec)
00174 {
00175 wait_time = &time_left;
00176 continue;
00177 }
00178 else
00179 {
00180 break;
00181 }
00182 }
00183 return -1;
00184 }
00185 else if (!this->process_incoming_dgram (icmp_recv_buff_, rval_recv))
00186 {
00187 return 0;
00188 }
00189 else
00190 {
00191 after = ACE_OS::gettimeofday ();
00192 if ((after - before) >= *timeout)
00193 {
00194 errno = ETIMEDOUT;
00195 break;
00196 }
00197
00198 *wait_time = *timeout - after + before;
00199 }
00200 } while (*wait_time >= half_millisec);
00201
00202 errno = ETIMEDOUT;
00203 return -1;
00204 }
00205
00206 int
00207 ACE_Ping_Socket::process_incoming_dgram (char * ptr, ssize_t len)
00208 {
00209 unsigned char hlen1;
00210 int icmplen;
00211 struct ip * ip;
00212 struct icmp * icmp;
00213
00214 ip = (struct ip *) ptr;
00215
00216
00217
00218
00219 #if 0
00220 hlen1 = ip->ip_hl;
00221 #else
00222 hlen1 = static_cast<unsigned char>(*ptr);
00223 hlen1 <<= 4;
00224 hlen1 >>= 4;
00225 #endif
00226 hlen1 <<= 2;
00227
00228 icmp = (struct icmp *) (ptr + hlen1);
00229
00230 if ((icmplen = len - hlen1) < ICMP_MIN)
00231 {
00232 ACE_DEBUG
00233 ((LM_DEBUG,
00234 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::process_incoming_dgram")
00235 ACE_LIB_TEXT (" - ICMP length is %d < 8.\n"),
00236 icmplen));
00237 ACE_ERROR_RETURN
00238 ((LM_ERROR,
00239 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::process_incoming_dgram - ")
00240 ACE_LIB_TEXT ("The ICMP header either not received or is corrupted.")),
00241 -1);
00242 }
00243
00244 if (icmp->icmp_type == ICMP_ECHOREPLY)
00245 {
00246 ACE_DEBUG
00247 ((LM_DEBUG,
00248 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::process_incoming_dgram")
00249 ACE_LIB_TEXT (" - ICMP_ECHOREPLY received.\n")));
00250
00251 if (icmp->icmp_id != getpid ())
00252 {
00253 ACE_ERROR_RETURN
00254 ((LM_ERROR,
00255 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::")
00256 ACE_LIB_TEXT ("process_incoming_dgram ")
00257 ACE_LIB_TEXT ("- The ICMP header received is a reply")
00258 ACE_LIB_TEXT (" to request of another process.")),
00259 -1);
00260 }
00261 if (icmplen < 16)
00262 {
00263 ACE_ERROR_RETURN
00264 ((LM_ERROR,
00265 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::")
00266 ACE_LIB_TEXT ("process_incoming_dgram - ICMP length ")
00267 ACE_LIB_TEXT ("is %d < 16."),
00268 icmplen),
00269 -1);
00270 }
00271
00272 ACE_DEBUG
00273 ((LM_DEBUG,
00274 ACE_LIB_TEXT ("(%P|%t) ACE::Ping_Socket::process_incoming_dgram - ")
00275 ACE_LIB_TEXT ("received ")
00276 ACE_LIB_TEXT ("ICMP datagram with length of %d bytes (not counting ")
00277 ACE_LIB_TEXT ("IP-header): seq=%u, ttl=%d.\n"),
00278 icmplen, icmp->icmp_seq, ip->ip_ttl));
00279
00280 return 0;
00281 }
00282
00283 ACE_DEBUG
00284 ((LM_DEBUG,
00285 ACE_LIB_TEXT ("(%P|%t) ACE::Ping_Socket::process_incoming_dgram - ")
00286 ACE_LIB_TEXT ("received datagram that is not ICMP_ECHOREPLY.\n")));
00287
00288 return -1;
00289 }
00290
00291 int
00292 ACE_Ping_Socket::send_echo_check (ACE_INET_Addr &remote_addr,
00293 int to_connect)
00294 {
00295 if (this->get_handle () == ACE_INVALID_HANDLE)
00296 {
00297 errno = EBADF;
00298 return -1;
00299 }
00300
00301 sockaddr_in *addr_connect = 0;
00302 addr_connect = (sockaddr_in *) remote_addr.get_addr ();
00303
00304
00305
00306
00307
00308 ACE_OS::memset ((void*) &addr_connect->sin_port,
00309 0,
00310 sizeof (addr_connect->sin_port));
00311
00312
00313 if (to_connect && !this->connected_socket_)
00314 {
00315 if (ACE_OS::connect (this->get_handle (),
00316 (sockaddr*) addr_connect,
00317 remote_addr.get_size ()) == -1)
00318 {
00319 if (errno != EINTR)
00320 return -1;
00321 }
00322 this->connected_socket_ = 1;
00323 }
00324
00325 ACE_OS::memset (this->icmp_send_buff_, 0, sizeof this->icmp_send_buff_);
00326 int datalen = ICMP_DATA_LENGTH;
00327 struct icmp *_icmp;
00328
00329 _icmp = (struct icmp *) this->icmp_send_buff_;
00330 _icmp->icmp_type = ICMP_ECHO;
00331 _icmp->icmp_code = 0;
00332 _icmp->icmp_id = getpid ();
00333 _icmp->icmp_seq = sequence_number_++;
00334
00335 #if defined (ACE_WIN32)
00336 _icmp->icmp_data = GetTickCount ();
00337 #else
00338 gettimeofday ((struct timeval *) &_icmp->icmp_data, 0);
00339 #endif
00340
00341 int length_icmp = ICMP_MIN + datalen;
00342 _icmp->icmp_cksum = 0;
00343 _icmp->icmp_cksum = inherited::calculate_checksum ((u_short *) _icmp,
00344 length_icmp);
00345 int rval_send = -1;
00346
00347 if ((rval_send = send ((void const *) icmp_send_buff_,
00348 length_icmp,
00349 remote_addr)) != length_icmp)
00350 {
00351 return -1;
00352 }
00353 return 0;
00354 }
00355
00356 int
00357 ACE_Ping_Socket::make_echo_check (ACE_INET_Addr & remote_addr,
00358 int to_connect,
00359 ACE_Time_Value const * timeout)
00360 {
00361 int rval_send = -1;
00362
00363 if ((rval_send = this->send_echo_check (remote_addr,
00364 to_connect)) == -1)
00365 return -1;
00366
00367 ACE_DEBUG
00368 ((LM_DEBUG,
00369 ACE_LIB_TEXT ("(%P|%t) ACE_Ping_Socket::make_echo_check - sent %d.\n"),
00370 rval_send));
00371
00372 return this->receive_echo_reply (timeout);
00373 }
00374
00375 ACE_END_VERSIONED_NAMESPACE_DECL
00376
00377 #endif