--- /dev/null
+/**
+ * PING module
+ *
+ * Copyright (C) 2001 Jeffrey Fulmer <jdfulmer@armstrong.com>
+ * 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>
+#include <util.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+#define MAXPACKET 65535
+#define PKTSIZE 64
+#define HDRLEN ICMP_MINLEN
+#define DATALEN (PKTSIZE-HDRLEN)
+#define MAXDATA (MAXPKT-HDRLEN-TIMLEN)
+#define DEF_TIMEOUT 5
+
+#include "private.h"
+
+void
+JOEfreeprotoent( struct protoent *p )
+{
+ char **a;
+ free( p->p_name );
+ if( p->p_aliases != NULL ){
+ for( a = p->p_aliases; *a != NULL; a++ ){
+ free( *a );
+ }
+ }
+ free( p );
+}
+
+void
+JOEfreehostent( struct hostent *h )
+{
+ char **p;
+
+ free( h->h_name );
+ if( h->h_aliases != NULL ){
+ for( p = h->h_aliases; *p != NULL; ++p )
+ free( *p );
+ free( h->h_aliases );
+ }
+ if( h->h_addr_list != NULL ){
+ for( p = h->h_addr_list; *p != NULL; ++p )
+ free( *p );
+ free (h->h_addr_list);
+ }
+ free( h );
+}
+
+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 );
+
+}
+
+static int
+send_ping( const char *host, struct sockaddr_in *taddr, struct ping_priv * datum )
+{
+ int len;
+ int ss;
+ unsigned char buf[ HDRLEN + DATALEN ];
+
+ const int proto_buf_len = 1024;
+ char proto_buf[proto_buf_len];
+ struct protoent *proto = NULL;
+ struct protoent proto_datum;
+
+ struct hostent *hp = NULL;
+ struct hostent hent;
+ int herrno;
+ char hbf[9000];
+#if defined(_AIX)
+ char *aixbuf;
+ char *probuf;
+ int rc;
+#endif/*_AIX*/
+
+ struct icmp *icp;
+ unsigned short last;
+
+ len = HDRLEN + DATALEN;
+
+#if defined(__GLIBC__)
+ /* for systems using GNU libc */
+ getprotobyname_r("icmp", &proto_datum, proto_buf, proto_buf_len, &proto);
+ if(( gethostbyname_r( host, &hent, hbf, sizeof(hbf), &hp, &herrno ) < 0 )){
+ hp = NULL;
+ }
+#elif defined(sun)
+ /* Solaris 5++ */
+ proto = getprotobyname_r("icmp", &proto_datum, proto_buf, proto_buf_len);
+ hp = gethostbyname_r( host, &hent, hbf, sizeof(hbf), &herrno );
+#elif defined(_AIX)
+ aixbuf = (char*)xmalloc( 9000 );
+ probuf = (char*)xmalloc( 9000 );
+ rc = getprotobyname_r( "icmp", &proto,
+ ( struct protoent_data *)(probuf + sizeof( struct protoent)));
+ rc = gethostbyname_r ( host, (struct hostent *)aixbuf,
+ (struct hostent_data *)(aixbuf + sizeof(struct hostent)));
+ hp = (struct hostent*)aixbuf;
+#elif ( defined(hpux) || defined(__osf__) )
+ proto = getprotobyname( "icmp" );
+ hp = gethostbyname( host );
+ herrno = h_errno;
+#else
+ /* simply hoping that get*byname is thread-safe */
+ proto = getprotobyname( "icmp" );
+ hp = gethostbyname( host );
+ herrno = h_errno;
+#endif/*OS SPECIFICS*/
+
+ if( proto == NULL ) {
+ return -1;
+ }
+
+ if(hp != NULL ){
+ memcpy( &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(( datum->sock = socket( AF_INET, SOCK_RAW, proto->p_proto )) < 0 ){
+#ifdef DEBUG
+ perror( "sock" );
+#endif/*DEBUG*/
+ return -2;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ icp = (struct icmp *)buf;
+ icp->icmp_type = ICMP_ECHO;
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ icp->icmp_id = getpid() & 0xFFFF;
+ icp->icmp_seq = icp->icmp_id;
+ icp->icmp_cksum = in_checksum((u_short *)icp, len );
+
+ if(( ss = sendto( datum->sock, buf, sizeof( buf ), 0,
+ (struct sockaddr*)taddr, sizeof( *taddr ))) < 0 ){
+#ifdef DEBUG
+ perror( "sock" );
+#endif/*DEBUG*/
+ return -2;
+ }
+ if( ss != len ){
+#ifdef DEBUG
+ perror( "malformed packet" );
+#endif/*DEBUG*/
+ return -2;
+ }
+
+#if defined(_AIX)
+ free( aixbuf );
+ free( probuf );
+#endif
+ /* JOEfreeprotoent( proto ); */
+ /* JOEfreeprotoent( &proto_datum ); */
+ /* JOEfreehostent( hp ); */
+ /* JOEfreehostent( &hent ); */
+ return 0;
+}
+
+static int
+recv_ping( struct sockaddr_in *taddr, struct ping_priv * datum )
+{
+ 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;
+
+ to.tv_sec = datum->timo / 100000;
+ to.tv_usec = ( datum->timo - ( to.tv_sec * 100000 ) ) * 10;
+
+ FD_ZERO( &readset );
+ FD_SET( datum->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( datum->sock + 1, &readset, NULL, NULL, &to )) < 0 ){
+ datum->rrt = -4;
+#ifdef DEBUG
+ perror( "select" );
+#endif/*DEBUG*/
+ return 0;
+ }
+ if( nf == 0 ){
+ return -1;
+ }
+
+ len = HDRLEN + DATALEN;
+ from = sizeof( faddr );
+
+ cc = recvfrom( datum->sock, buf, len, 0, (struct sockaddr*)&faddr, &from );
+ if( cc < 0 ){
+ datum->rrt = -4;
+#ifdef DEBUG
+ perror( "recvfrom" );
+#endif/*DEBUG*/
+ return 0;
+ }
+
+ 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;
+}
+
+int
+myping( const char *hostname, int t , struct ping_priv * datum)
+{
+ int err;
+ int rrt;
+ struct sockaddr_in sa;
+ struct timeval mytime;
+
+ datum->ident = getpid() & 0xFFFF;
+
+ if( t == 0 ) datum->timo = 2;
+ else datum->timo = t;
+
+ datum->rrt = 0;
+
+ (void) gettimeofday( &mytime, (struct timezone *)NULL);
+ if(( err = send_ping( hostname, &sa, datum)) < 0 ){
+ close( datum->sock );
+ return err;
+ }
+ do {
+ rrt = elapsed_time( &mytime );
+ if (datum->rrt < 0)
+ return 0;
+ datum->rrt = rrt;
+ if (datum->rrt > datum->timo * 1000 ) {
+ close( datum->sock );
+ return 0;
+ }
+ } while( recv_ping( &sa, datum ));
+ close( datum->sock );
+
+ return 1;
+}
+
+int
+pinghost( const char *hostname )
+{
+ struct ping_priv datum = ping_priv_default();
+ return myping( hostname, 0, &datum );
+}
+
+int
+pingthost( const char *hostname, int t )
+{
+ struct ping_priv datum = ping_priv_default();
+ return myping( hostname, t, &datum );
+}
+
+int
+tpinghost( const char *hostname )
+{
+ int ret;
+ struct ping_priv datum = ping_priv_default();
+
+ ret = myping( hostname, 0, &datum );
+ if(ret > 0 )
+ ret = datum.rrt;
+ return ret;
+}
+
+int
+tpingthost( const char *hostname, int t )
+{
+ int ret;
+ struct ping_priv datum = ping_priv_default();
+
+ ret = myping( hostname, t, &datum );
+ if(ret > 0 )
+ ret = datum.rrt;
+ return ret;
+}
+