From: octo Date: Sat, 4 Feb 2006 09:40:33 +0000 (+0000) Subject: Patch for libping (icmp identifier) by Tommie Gannert X-Git-Tag: collectd-3.8.0~20 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=a940d23ef82034df739be0addce0466660027425;p=collectd.git Patch for libping (icmp identifier) by Tommie Gannert --- diff --git a/src/libping/ping.c b/src/libping/ping.c new file mode 100644 index 00000000..c6a0096d --- /dev/null +++ b/src/libping/ping.c @@ -0,0 +1,337 @@ +/** + * 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 +#include +#include +#include +#include +#include +#include + +#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; +} +