/************************************************************************\ |* MIS 5599 Vahid Moghaddasi *| |* (Socket Programming) *| |* >> A Simple PING Clone << *| +------------------------------------------------------------------------+ | | | NAME: pingclient.c | | SYNOPSIS: pingclient host portnum [tcp|udp] | | PLATFORMS: tested on Linux Redhat 5.x, 6.x , Solaris 2.51, | | Solaris 2.6, HP-UX 10.20, AIX 4.1.2 | | DESCRIPTION: | | A simple ping clone. This client program connects to a server | | using either UDP or TCP (default UDP) to get the number of times | | the server has been 'pinged' (i.e. a client connected to the | | server) since it was started the last time. The client program | | prints out this number. | | | | NOTES: | | Setting DEBUG=1 turns on a more verbose output mode. | | The number (nn) of pings reported is in the range of 1...INT_MAX.| | After reporting INT_MAX pings, the numbers displayed by this | | program are no longer valid. | | When using the UDP protocol, the client sends a message "PING" | | to the server and waits for an answer. In TCP mode, the client | | just tries to connect to the server and attempts to read from | | the server. | | Since the timeout values for the different socket operations are | | highly system specific, an alarm() is used to stop the program | | after C_WAIT seconds. | | | | gcc -lsocket -lnsl pingclient.c | | | \************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define DEBUG 0 /* set to '1' for diagnostic messages */ #define C_WAIT 2 /* timeout in seconds for communication with server */ #define TCP 1 /* internal names for TCP & UDP */ #define UDP 2 #define INADDR_NONE 0xffffffff /* could cause a compiler warning, */ /* because it might already be defined in . */ static int s; /* socket on client side */ typedef void (*sighandler_t)(int); extern void handler(); void status (int return_value, char *description) /* display error/diagnostic messages, handle errors */ { /* This also saves me from writing too many comments :-) */ if (return_value) /* function call successful, output only if DEBUG=1 */ { if (DEBUG) printf("%s ... OK (%d)\n", description, return_value); } else /* function call returned with error */ { fprintf(stderr,"ERROR: could not %s!\n", description); if (close(s)) perror("ERROR: Failed to close socket"); exit(-1); } } void handler(int sig) /* signal handler for SIGALRM */ { /* Communication with server took longer than */ signal(sig, SIG_IGN); /* C_WAIT seconds -> terminate program */ fprintf(stderr,"ERROR: Timeout (%d seconds)\n",C_WAIT); fprintf(stderr,"Failed connect to server or did not get an answer!\n"); fprintf(stderr,"Check hostname & portnum, ensure that server is up.\n"); status(close(s)==0, "close socket"); signal(SIGALRM, (sighandler_t)handler); exit(-2); } void main (int argc, char *argv[]) { char *host; /* server to connect to */ struct hostent *hp; struct protoent *pp; struct sockaddr_in sin; int s; /* socket on client side */ int port; /* port number on server side */ short prtcl=UDP; /* default: use UDP to ping server */ char *ping="PING"; /* UDP message that is sent to server */ int rcount=-1,rcnt=1; char buf[20]; /* buffer to hold sent/received data */ signal(SIGALRM,(sighandler_t)handler); /* install handler for SIGALRM */ /* check if command line arguments are correct */ if (((argc==4)&&strcmp(argv[3],"tcp")&&strcmp(argv[3],"udp"))||(argc<3)) {printf("usage: %s hostname portnum [tcp|udp]\n default: udp\n",argv[0]); exit(1);} host=argv[1]; /* server name - a name or dotted notation */ memset(&sin, 0, sizeof(sin)); status(((port=atoi(argv[2]))), "read port number from command line"); sin.sin_port=htons(port); /* store port number in network format */ sin.sin_family=AF_INET; /* use the Internet protocol family */ if (argc==4) if (strcmp(argv[3],"udp")) prtcl=TCP; /* use TCP, not UDP */ if ((hp=gethostbyname(host))) /* convert host to an IP NUMBER */ memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); else status(((sin.sin_addr.s_addr=inet_addr(host))!=INADDR_NONE), "resolve host name from command line"); alarm(C_WAIT); /* start the alarm clock, */ /* covers all communication with the server */ if (prtcl==UDP){ /* using the UDP protocol to ping (default) */ status((pp=getprotobyname("udp"))!=NULL, "get protocol by name"); status((s=socket(PF_INET,SOCK_DGRAM,pp->p_proto))>=0, "create socket"); status(connect(s, (struct sockaddr *)&sin, sizeof(sin))>=0, "connect to server"); status(write(s, ping, strlen(ping)), "write to server"); status(read(s, buf, sizeof(buf))==sizeof(buf), "read from server"); if (DEBUG) printf("[udp]: "); }else{ /* using the TCP protocol to ping */ status((pp=getprotobyname("tcp"))!=NULL, "get protocol by name (tcp)"); status((s=socket(PF_INET,SOCK_STREAM,pp->p_proto))>=0, "create socket"); status(connect(s, (struct sockaddr *)&sin, sizeof(sin))>=0, "connect to server"); /* If the 1st attempt to read is successful, read as long as data comes*/ status((rcount=read(s, buf, sizeof(buf)))!=-1, "read from server"); while (((rcnt=read(s, buf, sizeof(buf)))>0)) rcount+=rcnt; /* Now we have all bytes or an error... */ status(rcnt>-1,"read from server (tried multiple)"); if (DEBUG) printf("[tcp]: "); } alarm(0); /* reset the alarm timer */ printf("Server running on port %d was ping %s times.\n", port, buf); status(close(s)==0, "close socket"); exit(0); } /* END OF pingclient.c */