netsukuku/src/libping.c

387 lines
8.3 KiB
C
Raw Normal View History

2013-09-16 09:53:25 +00:00
/**
* 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.
*
* --
*
* This code has been lightly modified to adapt it in the Netsukuku source
* code.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <pthread.h>
#include <stdlib.h>
#include "libping.h"
#include "xmalloc.h"
#include "log.h"
#define MAXPACKET 65535
#define PKTSIZE 64
2013-09-16 09:53:25 +00:00
#define HDRLEN ICMP_MINLEN
#define DATALEN (PKTSIZE-HDRLEN)
#define MAXDATA (MAXPKT-HDRLEN-TIMLEN)
#define DEF_TIMEOUT 5
struct ping_priv
ping_priv_default(void)
2013-09-16 09:53:25 +00:00
{
struct ping_priv datum;
datum.ident = IDENT_DEFAULT;
datum.timo = TIMO_DEFAULT;
return datum;
2013-09-16 09:53:25 +00:00
}
/**
* elapsed_time
* returns an int value for the difference
* between now and starttime in milliseconds.
*/
int
elapsed_time(struct timeval *starttime)
{
struct timeval *newtime;
int elapsed;
newtime = (struct timeval *) xmalloc(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);
}
if (elapsed < 1)
elapsed = 1;
xfree(newtime);
return (elapsed);
2013-09-16 09:53:25 +00:00
}
void
JOEfreeprotoent(struct protoent *p)
2013-09-16 09:53:25 +00:00
{
char **a;
xfree(p->p_name);
if (p->p_aliases != NULL) {
for (a = p->p_aliases; *a != NULL; a++) {
xfree(*a);
}
}
xfree(p);
2013-09-16 09:53:25 +00:00
}
void
JOEfreehostent(struct hostent *h)
2013-09-16 09:53:25 +00:00
{
char **p;
2013-09-16 09:53:25 +00:00
xfree(h->h_name);
if (h->h_aliases != NULL) {
for (p = h->h_aliases; *p != NULL; ++p)
xfree(*p);
xfree(h->h_aliases);
}
if (h->h_addr_list != NULL) {
for (p = h->h_addr_list; *p != NULL; ++p)
xfree(*p);
xfree(h->h_addr_list);
}
xfree(h);
2013-09-16 09:53:25 +00:00
}
static int
in_checksum(u_short * buf, int len)
2013-09-16 09:53:25 +00:00
{
register long sum = 0;
u_short answer = 0;
2013-09-16 09:53:25 +00:00
while (len > 1) {
sum += *buf++;
len -= 2;
}
2013-09-16 09:53:25 +00:00
if (len == 1) {
*(u_char *) (&answer) = *(u_char *) buf;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
2013-09-16 09:53:25 +00:00
return (answer);
2013-09-16 09:53:25 +00:00
}
2013-09-16 09:53:25 +00:00
static int
send_ping(const char *host, struct sockaddr_in *taddr,
struct ping_priv *datum)
2013-09-16 09:53:25 +00:00
{
int len;
int ss;
unsigned char buf[HDRLEN + DATALEN];
2013-09-16 09:53:25 +00:00
#define 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];
2013-09-16 09:53:25 +00:00
#if defined(_AIX)
char *aixbuf;
char *probuf;
int rc;
2013-09-16 09:53:25 +00:00
#endif/*_AIX*/
struct icmp *icp;
unsigned short last;
2013-09-16 09:53:25 +00:00
len = HDRLEN + DATALEN;
2013-09-16 09:53:25 +00:00
#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;
}
2013-09-16 09:53:25 +00:00
#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);
2013-09-16 09:53:25 +00:00
#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;
2013-09-16 09:53:25 +00:00
#elif ( defined(hpux) || defined(__osf__) )
proto = getprotobyname("icmp");
hp = gethostbyname(host);
herrno = h_errno;
2013-09-16 09:53:25 +00:00
#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;
}
2013-09-16 09:53:25 +00:00
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;
}
2013-09-16 09:53:25 +00:00
last = ntohl(taddr->sin_addr.s_addr) & 0xFF;
if ((last == 0x00) || (last == 0xFF)) {
return -1;
}
2013-09-16 09:53:25 +00:00
if ((datum->sock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
2013-09-16 09:53:25 +00:00
#ifdef DEBUG
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
#endif /*DEBUG*/
return -2;
}
2013-09-16 09:53:25 +00:00
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);
2013-09-16 09:53:25 +00:00
if ((ss = sendto(datum->sock, buf, sizeof(buf), 0,
(struct sockaddr *) taddr, sizeof(*taddr))) < 0) {
2013-09-16 09:53:25 +00:00
#ifdef DEBUG
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
#endif /*DEBUG*/
return -2;
}
if (ss != len) {
2013-09-16 09:53:25 +00:00
#ifdef DEBUG
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
#endif /*DEBUG*/
return -2;
}
2013-09-16 09:53:25 +00:00
#if defined(_AIX)
xfree(aixbuf);
xfree(probuf);
#endif
/* JOEfreeprotoent( proto ); */
/* JOEfreeprotoent( &proto_datum ); */
/* JOEfreehostent( hp ); */
/* JOEfreehostent( &hent ); */
return 0;
2013-09-16 09:53:25 +00:00
}
static int
recv_ping(struct sockaddr_in *taddr, struct ping_priv *datum)
2013-09-16 09:53:25 +00:00
{
int len;
int from;
int nf, cc;
unsigned char buf[HDRLEN + DATALEN];
struct icmp *icp;
2013-09-16 09:53:25 +00:00
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;
2013-09-16 09:53:25 +00:00
FD_ZERO(&readset);
FD_SET(datum->sock, &readset);
2013-09-16 09:53:25 +00:00
/* 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) {
2013-09-16 09:53:25 +00:00
datum->rrt = -4;
#ifdef DEBUG
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
#endif /*DEBUG*/
return 0;
2013-09-16 09:53:25 +00:00
}
if (nf == 0) {
return -1;
2013-09-16 09:53:25 +00:00
}
len = HDRLEN + DATALEN;
from = sizeof(faddr);
2013-09-16 09:53:25 +00:00
cc = recvfrom(datum->sock, buf, len, 0, (struct sockaddr *) &faddr,
(socklen_t *) & from);
if (cc < 0) {
2013-09-16 09:53:25 +00:00
datum->rrt = -4;
#ifdef DEBUG
debug(DBG_NORMAL, ERROR_MSG "sock: %s" ERROR_POS, strerror(errno));
#endif /*DEBUG*/
return 0;
}
2013-09-16 09:53:25 +00:00
icp = (struct icmp *) (buf + HDRLEN + DATALEN);
if (faddr.sin_addr.s_addr != taddr->sin_addr.s_addr) {
return 1;
}
2013-09-16 09:53:25 +00:00
/*****
if( icp->icmp_id != ( getpid() & 0xFFFF )){
printf( "id: %d\n", icp->icmp_id );
return 1;
}
*****/
return 0;
2013-09-16 09:53:25 +00:00
}
int
myping(const char *hostname, int t, struct ping_priv *datum)
2013-09-16 09:53:25 +00:00
{
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;
2013-09-16 09:53:25 +00:00
}
int
pinghost(const char *hostname)
2013-09-16 09:53:25 +00:00
{
struct ping_priv datum = ping_priv_default();
return myping(hostname, 0, &datum);
2013-09-16 09:53:25 +00:00
}
int
pingthost(const char *hostname, int t)
2013-09-16 09:53:25 +00:00
{
struct ping_priv datum = ping_priv_default();
return myping(hostname, t, &datum);
2013-09-16 09:53:25 +00:00
}
int
tpinghost(const char *hostname)
2013-09-16 09:53:25 +00:00
{
int ret;
struct ping_priv datum = ping_priv_default();
2013-09-16 09:53:25 +00:00
ret = myping(hostname, 0, &datum);
if (ret > 0)
ret = datum.rrt;
return ret;
}
2013-09-16 09:53:25 +00:00
int
tpingthost(const char *hostname, int t)
2013-09-16 09:53:25 +00:00
{
int ret;
struct ping_priv datum = ping_priv_default();
2013-09-16 09:53:25 +00:00
ret = myping(hostname, t, &datum);
if (ret > 0)
ret = datum.rrt;
return ret;
2013-09-16 09:53:25 +00:00
}