Listing 1
/* 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);
}
/* A simple function to handle exiting
from newping, in case this is
required in the future */
mypingexit(retcode)
int retcode;
{
close(sckt);
exit(retcode);
}
|