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