/** * PING module * * Copyright (C) 2001 Jeffrey Fulmer * This file is part of LIBPING * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "ping.h" #ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif /*EXIT_SUCCESS*/ #ifndef EXIT_FAILURE # define EXIT_FAILURE 1 #endif /*EXIT_FAILURE*/ #define MAXPACKET 65535 #define PKTSIZE 64 #define HDRLEN ICMP_MINLEN #define DATALEN (PKTSIZE-HDRLEN) #define MAXDATA (MAXPKT-HDRLEN-TIMLEN) #define DEF_TIMEOUT 5 static int ident = 0; static int timo = 2; static int rrt; static int sock = -1; static int in_checksum( u_short *buf, int len ) { register long sum = 0; u_short answer = 0; while( len > 1 ){ sum += *buf++; len -= 2; } if( len == 1 ){ *( u_char* )( &answer ) = *( u_char* )buf; sum += answer; } sum = ( sum >> 16 ) + ( sum & 0xffff ); sum += ( sum >> 16 ); answer = ~sum; return ( answer ); } int send_ping( const char *host, struct sockaddr_in *taddr ) { int len; int ss; unsigned char buf[ HDRLEN + DATALEN ]; struct protoent *proto; struct hostent *hp; struct icmp *icp; unsigned short last; len = HDRLEN + DATALEN; if(( proto = getprotobyname( "icmp" )) == NULL ){ return -1; } if(( hp = gethostbyname( host )) != NULL ){ memmove( &taddr->sin_addr, hp->h_addr_list[0], sizeof( taddr->sin_addr )); taddr->sin_port = 0; taddr->sin_family = AF_INET; } else if( inet_aton( host, &taddr->sin_addr ) == 0 ){ return -1; } last = ntohl( taddr->sin_addr.s_addr ) & 0xFF; if(( last == 0x00 ) || ( last == 0xFF )){ return -1; } if((sock < 0) && ( sock = socket( AF_INET, SOCK_RAW, proto->p_proto )) < 0 ){ #ifdef DEBUG perror( "sock" ); #endif/*DEBUG*/ return -2; } icp = (struct icmp *)buf; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_id = getpid() & 0xFFFF; icp->icmp_cksum = in_checksum((u_short *)icp, len ); if(( ss = sendto( sock, buf, sizeof( buf ), 0, (struct sockaddr*)taddr, sizeof( *taddr ))) < 0 ){ #ifdef DEBUG perror( "sock" ); #endif/*DEBUG*/ close( sock ); sock = -1; return -2; } if( ss != len ){ #ifdef DEBUG perror( "malformed packet" ); #endif/*DEBUG*/ close( sock ); sock = -1; return -2; } return 0; } static int recv_ping( struct sockaddr_in *taddr ) { int len; socklen_t from; int nf, cc; unsigned char buf[ HDRLEN + DATALEN ]; //struct icmp *icp; struct sockaddr_in faddr; struct timeval to; fd_set readset, writeset; to.tv_sec = timo / 100000; to.tv_usec = ( timo - ( to.tv_sec * 100000 ) ) * 10; FD_ZERO( &readset ); FD_ZERO( &writeset ); FD_SET( sock, &readset ); /* we use select to see if there is any activity on the socket. If not, then we've requested an unreachable network and we'll time out here. */ if(( nf = select( sock + 1, &readset, &writeset, NULL, &to )) < 0 ){ #ifdef DEBUG perror( "select" ); #endif/*DEBUG*/ exit( EXIT_FAILURE ); } if( nf == 0 ){ return -1; } len = HDRLEN + DATALEN; from = sizeof( faddr ); cc = recvfrom( sock, buf, len, 0, (struct sockaddr*)&faddr, &from ); if( cc < 0 ){ exit( EXIT_FAILURE ); } //icp = (struct icmp *)(buf + HDRLEN + DATALEN ); if( faddr.sin_addr.s_addr != taddr->sin_addr.s_addr ){ return 1; } /***** if( icp->icmp_id != ( getpid() & 0xFFFF )){ printf( "id: %d\n", icp->icmp_id ); return 1; } *****/ return 0; } /** * elapsed_time * returns an int value for the difference * between now and starttime in milliseconds. */ static int elapsed_time( struct timeval *starttime ){ struct timeval *newtime; int elapsed; newtime = (struct timeval*)malloc( sizeof(struct timeval)); gettimeofday(newtime,NULL); elapsed = 0; if(( newtime->tv_usec - starttime->tv_usec) > 0 ){ elapsed += (newtime->tv_usec - starttime->tv_usec)/1000 ; } else{ elapsed += ( 1000000 + newtime->tv_usec - starttime->tv_usec ) /1000; newtime->tv_sec--; } if(( newtime->tv_sec - starttime->tv_sec ) > 0 ){ elapsed += 1000 * ( newtime->tv_sec - starttime->tv_sec ); } free(newtime); return( elapsed ); } static int myping(const std::string &hostname, int t, struct sockaddr_in *sa = NULL) { int err; struct sockaddr_in _sa; struct timeval mytime; if (!sa) sa = &_sa; ident = getpid() & 0xFFFF; if( t == 0 ) timo = 2; else timo = t; (void) gettimeofday( &mytime, (struct timezone *)NULL); if(( err = send_ping( hostname.c_str(), sa )) < 0 ){ return err; } do{ if(( rrt = elapsed_time( &mytime )) > timo * 1000 ){ close( sock ); sock = -1; return 0; } } while( recv_ping(sa)); close( sock ); sock = -1; return 1; } int pinghost(const std::string &hostname, std::string *ip) { struct sockaddr_in sa; int res = myping( hostname, 0, &sa); if (ip) { char *p = inet_ntoa(sa.sin_addr); *ip = p ? std::string(p) : ""; } return res; } int pingthost(const std::string &hostname, int t) { return myping( hostname, t ); } int tpinghost(const std::string &hostname) { int ret; if(( ret = myping( hostname, 0 )) > 0 ) return rrt; else return ret; } int tpingthost(const std::string &hostname, int t ) { int ret; if(( ret = myping( hostname, t )) > 0 ) return rrt; else return ret; }