// $Id$ #include "ace/ICMP_Socket.h" #if defined (ACE_HAS_ICMP_SUPPORT) && (ACE_HAS_ICMP_SUPPORT == 1) #include "ace/ACE.h" #include "ace/Log_Category.h" #include "ace/OS_NS_netdb.h" #include "ace/OS_NS_sys_socket.h" ACE_BEGIN_VERSIONED_NAMESPACE_DECL ACE_ALLOC_HOOK_DEFINE (ACE_ICMP_Socket) void ACE_ICMP_Socket::dump (void) const { ACE_TRACE ("ACE_ICMP_Socket::dump"); } ACE_ICMP_Socket::ACE_ICMP_Socket (void) { ACE_TRACE ("ACE_ICMP_Socket::ACE_ICMP_Socket"); } ssize_t ACE_ICMP_Socket::send (void const * buf, size_t n, ACE_Addr const & addr, int flags) const { ACE_TRACE ("ACE_ICMP_Socket::send"); return ACE_OS::sendto (this->get_handle (), (char const *) buf, n, flags, (sockaddr const *) addr.get_addr (), addr.get_size ()); } ssize_t ACE_ICMP_Socket::recv (void * buf, size_t n, ACE_Addr & addr, int flags) const { ACE_TRACE ("ACE_ICMP_Socket::recv"); int addr_len = addr.get_size (); ssize_t status = ACE_OS::recvfrom (this->get_handle (), (char *) buf, n, flags, (sockaddr *) addr.get_addr (), (int*) &addr_len); addr.set_size (addr_len); return status; } ssize_t ACE_ICMP_Socket::recv (void * buf, size_t n, int flags, ACE_Time_Value const * timeout) const { ACE_TRACE ("ACE_ICMP_Socket::recv"); return ACE::recv (this->get_handle (), buf, n, flags, timeout); } int ACE_ICMP_Socket::open (ACE_Addr const & local, int protocol, int reuse_addr) { ACE_TRACE ("ACE_ICMP_Socket::open"); // Check if icmp protocol is supported on this host int proto_number = -1; protoent *proto = 0; if (! (proto = ACE_OS::getprotobyname ("icmp"))) { ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) ACE_ICMP_Socket::open: %p; %s\n"), ACE_TEXT ("getprotobyname"), ACE_TEXT ("ICMP protocol is not properly configured ") ACE_TEXT ("or not supported.")), -1); } proto_number = proto->p_proto; if (proto_number != IPPROTO_ICMP || proto_number != protocol) { ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("(%P|%t) ACE::ICMP_Socket::open - ") ACE_TEXT ("only IPPROTO_ICMP protocol is ") ACE_TEXT ("currently supported.\n")), -1); } if (ACE_SOCK::open (SOCK_RAW, AF_INET, protocol, reuse_addr) == -1) { return -1; } return this->shared_open (local); } int ACE_ICMP_Socket::shared_open (ACE_Addr const & local) { ACE_TRACE ("ACE_ICMP_Socket::shared_open"); int error = 0; if (local == ACE_Addr::sap_any) { if (ACE::bind_port (this->get_handle ()) == -1) { error = 1; } } else if (ACE_OS::bind (this->get_handle (), reinterpret_cast (local.get_addr ()), local.get_size ()) == -1) { error = 1; } if (error != 0) { this->close (); } return error ? -1 : 0; } unsigned short ACE_ICMP_Socket::calculate_checksum (unsigned short * paddress, int len) { int nleft = len; int sum = 0; unsigned short * w = paddress; unsigned short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *((unsigned char *) &answer) = *((unsigned char *) w); sum += answer; } // add back carry outs from top 16 bits to low 16 bits sum = (sum >> 16) + (sum & 0xffff); // add hi 16 to low 16 sum += (sum >> 16); // add carry answer = ~sum; // truncate to 16 bits return (answer); } ACE_END_VERSIONED_NAMESPACE_DECL #endif /* ACE_HAS_ICMP_SUPPORT == 1 */