Cover V02, I05
Article
Listing 1
Listing 2

sep93.tar


Listing 1: Eric Horne's corrected newping

/*  newping v1.0f

Replaces ping(1) for simple host status
information. Uses TCP/IP to check the
target machine, connects to a well-known
port, and waits for a response. Does not
use ICMP, like ping(1).

Exit Codes:

0 -- host is up
1 -- Problem with connecting
2 -- host would connect, but wouldn't respond
3 -- Connection was forcably refused
4 -- Problem with the network
5 -- Host is unreachable
255 -- Unknown or unexpected error occured.

REVISIONS:
Version 1.0  -- Nov 07, 1991
Version 1.0a -- Nov 18, 1991
Version 1.0c -- Jul 10, 1992
Version 1.0f -- Aug 23, 1992
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>

#define DEFAULTTIMEOUT 20    /* in seconds */
#define SERVICEPORT "time"   /* name of port */
#define DEFAULTPORT  37      /* TIME/TCP port # */

#define DEBUG 0x1
#define VERBOSE 0x2

int totsecs=1;       /* Time elapsed so far */
int timeout;         /* Time allowed to elapse */
int sckt;
char *hostname;      /* name of the remote host */
char opts;

extern int errno;    /*  */

void noconnect();
void noresponse();

main(argc,argv)
char *argv[];
int argc;
{
struct hostent *host;
struct servent *service;
struct protoent *protocol;
struct sockaddr_in pinghost,frompinghost;
struct sockaddr_in localhost;
int fromlen,res;
long ipaddress;
char buf[25];

if((argc>1)&&(*argv[1]=='-'))
{
int offset=1;

while(*(argv[1]+offset))
switch(*(argv[1]+offset))
{
case 'd':        /* debug mode */
opts|=DEBUG; offset++;
break;
case 'v':        /* verbose mode */
opts|=VERBOSE; offset++;
break;
case NULL:       /* end of options list */
break;
default:         /* unknown option */
offset++; break;
}
}

if(argc>1)
{
if(isdigit(*(argv[argc-1])))
{
if(strchr(argv[argc-1],'.'))
hostname=argv[argc-1];
else
hostname=(argc-2) ? argv[argc-2] :
argv[argc-1];
}
else
hostname=argv[argc-1];
}
else
{
hostname=(char *)strrchr(argv[0],'/');
if(hostname)
{
hostname++; *hostname=NULL;
}
else
hostname = argv[0];
fprintf(stderr,
"Usage: %s -[dv] host [timeout]\n",
hostname);
exit(0);
}

if(isdigit(*(argv[argc-1])))
timeout=atoi(argv[argc-1]); /* Define timeout */
else
timeout=DEFAULTTIMEOUT;     /*  or default */

/* Assume an IP address was given */

if((ipaddress=inet_addr(hostname))==-1)
{
if(host=gethostbyname(hostname))
{
/* Found host, initialize the address */
pinghost.sin_family=host->h_addrtype;
bcopy(host->h_addr,
(char *)&pinghost.sin_addr,
host->h_length);
}
else           /* UNKNOWN HOST */
{
/* Host unknown -- assume it is down */
printf("%s: unknown host %s\n",
argv[0],hostname);
exit(1);
}
}
else
{
pinghost.sin_addr.s_addr=ipaddress;
pinghost.sin_family=AF_INET;
}

if(opts&DEBUG)
printf("The IP Address for %s is: %0lX\n",
hostname,pinghost.sin_addr.s_addr);

/* Define the activity port */
/* I tried using getservbyname(), but it seemed to
crash the program. I don't know why. */

pinghost.sin_port=DEFAULTPORT;

if(opts&DEBUG)
printf("Service %s recognized as port # %d.\n",
SERVICEPORT,pinghost.sin_port);

/* Find the protocol by name (TCP/IP) */
if(!(protocol=getprotobyname("tcp")))
{
printf("Unrecognized protocol: tcp\n");
exit(255);
}

/* Make the socket on the local machine */
if((sckt=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket"); exit(255);
}

if(opts&DEBUG)
printf("Socket open. Descriptor Number %d\n",
sckt);

/* Set the alarm clock to go off in a second */

signal(SIGALRM,noconnect); alarm(1);

/* Attempt the connection with remote machine.
The EINTR is added so that when the alarm goes
off and interrupts the system call, the call
will recover. */

while(res=connect(sckt,
(struct sockaddr *)&pinghost,
sizeof(pinghost)))
{
if(res==-1)                       /* error occured! */
{
if((opts&DEBUG)&&(errno!=EINTR))
perror("connect");

switch(errno)
{
case ECONNRESET:    /* reset connection */
case ECONNREFUSED:  /* Connection refused */
perror("connect");
mypingexit(3);
break;            /*  Exit CODE 3 */

case EHOSTUNREACH:  /* Host is unreachable */
perror("connect");
mypingexit(5);
break;            /*  Exit CODE 5 */

case EINTR:         /* call interrupted */
case EISCONN:       /* Connection exists */
/* The connection was interrupted by alarm
clock going off. The only way I know to
reset the situation is to open a socket,
and reattempt a connect() call */
close(sckt);
if((sckt=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket"); mypingexit(255);
}

break;
case ENETRESET:     /* Dropped connection */
case ENETDOWN:      /* Network down */
case ENETUNREACH:   /* Network unreachable */
perror("connect");
mypingexit(4);
break;            /*  Exit CODE 4 */

case EADDRINUSE:    /* Address in use */
case EADDRNOTAVAIL: /* Address not available */
break;            /*  Ignore these. */

default:            /* Unknown or unexpected */
perror("connect");
mypingexit(255);
break;            /*  Exit CODE 255 */
}
}

if((opts&DEBUG)||(opts&VERBOSE))
printf("Connect made (returned with %d)\n",res);

/* Reset the alarm to call noresponse() when it
expires */
signal(SIGALRM,noresponse); alarm(1);

/* Just because the connect() succeeded, the
machine may still be down. This portion
tests the down-ness of the machine by
waiting for a response from the connection. */


while((res=recv(sckt,buf,sizeof(buf),0))<=0)
if(res==-1)
{
if(opts&DEBUG)
{
perror("recv"); continue;
}

switch(errno)
{
case ECONNABORTED:  /* connection aborted */
case ENOTCONN:      /* no connection */
perror("recv");   /*  Exit CODE 1 */
mypingexit(1);
break;

case ECONNRESET:    /* reset connection */
case ENETRESET:     /* network reset */
perror("recv");   /*  Exit CODE 4 */
mypingexit(4);
break;

default:            /* Unknown or unexpected */
perror("recv");   /*  Exit CODE 255 */
mypingexit(255);
break;
}
}

if((opts&DEBUG)||(opts&VERBOSE))
{
printf("Received something. ");
printf("Len=%d. Total Elapsed Time: %d\n",
res,totsecs);
}

/* Ignore any signals, they are meaningless now! */
signal(SIGALRM,SIG_IGN);

/* It's alive!! Let the user know */
printf("%s is alive (%d)\n",
hostname,totsecs);
close(sckt);

/* Pack it up, and take it home! */
mypingexit(0);
}
}
mypingexit(retcode)
int retcode;
{
close(sckt);
exit(retcode);
}
/* end of file */