Patch for libping (icmp identifier) by Tommie Gannert
authorocto <octo>
Sat, 4 Feb 2006 09:40:33 +0000 (09:40 +0000)
committerocto <octo>
Sat, 4 Feb 2006 09:40:33 +0000 (09:40 +0000)
src/libping/ping.c [new file with mode: 0644]

diff --git a/src/libping/ping.c b/src/libping/ping.c
new file mode 100644 (file)
index 0000000..c6a0096
--- /dev/null
@@ -0,0 +1,337 @@
+/**
+ * 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;
+}
+