322 lines
8.1 KiB
C
322 lines
8.1 KiB
C
/* $Id$
|
|
* Author: Roger A. Cole
|
|
* Date: 11-26-90
|
|
*
|
|
* Experimental Physics and Industrial Control System (EPICS)
|
|
*
|
|
* Copyright 1991, the Regents of the University of California,
|
|
* and the University of Chicago Board of Governors.
|
|
*
|
|
* This software was produced under U.S. Government contracts:
|
|
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
|
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
|
*
|
|
* Initial development by:
|
|
* The Controls and Automation Group (AT-8)
|
|
* Ground Test Accelerator
|
|
* Accelerator Technology Division
|
|
* Los Alamos National Laboratory
|
|
*
|
|
* Co-developed with
|
|
* The Controls and Computing Group
|
|
* Accelerator Systems Division
|
|
* Advanced Photon Source
|
|
* Argonne National Laboratory
|
|
*
|
|
* Modification Log:
|
|
* -----------------
|
|
* .01 11-26-90 rac initial version
|
|
* .02 07-30-91 rac installed in SCCS
|
|
* .03 09-11-91 joh updated for v5 vxWorks
|
|
* .03 11-07-91 rac be more forgiving of unexpected interactions
|
|
* .04 12-06-91 rac total rewrite, Unix-only, no LWP
|
|
*
|
|
* make options
|
|
* -DNDEBUG don't compile assert() checking
|
|
* -DDEBUG compile various debug code, including checks on
|
|
* malloc'd memory
|
|
*/
|
|
/*+/mod***********************************************************************
|
|
* TITLE cmdClient.c - general purpose client for command-based servers
|
|
*
|
|
* DESCRIPTION
|
|
* Connects to a text-command-based server.
|
|
*
|
|
* Usage on SunOS:
|
|
* % cmdClient hostName portNum
|
|
* or
|
|
* execl("cmdClient", "cmdClient", "hostName", "portNum",
|
|
* (char *)0);
|
|
*
|
|
* Usage on VxWorks:
|
|
* > cmdClient "hostName",portNum
|
|
*
|
|
* BUGS
|
|
* o the stdout stream from this program contains, intermixed, the
|
|
* server's stdout and stderr streams
|
|
* o not all signals are caught
|
|
*-***************************************************************************/
|
|
#include <genDefs.h>
|
|
#include <tsDefs.h>
|
|
#include <ezsSockSubr.h>
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <strings.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <sys/types.h>
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* prototypes
|
|
*----------------------------------------------------------------------------*/
|
|
int cmdcl();
|
|
void cmdclCmdProcess();
|
|
char *cmdclInTask();
|
|
long cmdclTask();
|
|
void cmdclTaskSigHandler();
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* global definitions
|
|
*----------------------------------------------------------------------------*/
|
|
|
|
jmp_buf sigEnv; /* environment for longjmp at signal time */
|
|
|
|
main(argc, argv)
|
|
int argc; /* number of command line args */
|
|
char *argv[]; /* command line args */
|
|
{
|
|
char *hostName; /* host name for server */
|
|
int portNum; /* port number for server */
|
|
|
|
if (argc != 3) /* must be command and 2 args */
|
|
goto mainUsage;
|
|
hostName = argv[1];
|
|
if (sscanf(argv[2], "%d", &portNum) != 1) {
|
|
printf("error scanning port number\n");
|
|
goto mainUsage;
|
|
}
|
|
|
|
return cmdClient(hostName, portNum);
|
|
|
|
mainUsage:
|
|
printf("Usage: %s serverHostName serverPortNumber\n", argv[0]);
|
|
return -1;
|
|
}
|
|
|
|
/*+/subr**********************************************************************
|
|
* NAME cmdClient - shell callable interface for cmdClient
|
|
*
|
|
*-*/
|
|
int
|
|
cmdClient(hostName, portNum)
|
|
char *hostName; /* I host name for server */
|
|
int portNum; /* I port number for server */
|
|
{
|
|
long stat; /* status return from calls */
|
|
int serverSock=-1; /* socket connected to server */
|
|
char serverBuf[80];
|
|
char *pBuf;
|
|
FILE *myIn=NULL;
|
|
FILE *myOut=NULL;
|
|
char *findNl;
|
|
char message[80];
|
|
int i;
|
|
char keyboard[80]; /* line from keyboard */
|
|
int eofFlag=0;
|
|
int discardNL=0;
|
|
|
|
genSigInit(cmdclTaskSigHandler);
|
|
|
|
if (setjmp(sigEnv) != 0)
|
|
goto cmdclTaskWrapup;
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
* attempt to connect to the server. If the connection is successful,
|
|
* print the message returned by the server. Then open two streams to
|
|
* the socket, one for characters from keyboard to server, the other
|
|
* for characters from server to stdout.
|
|
*----------------------------------------------------------------------------*/
|
|
if ((i=ezsConnectToServer(&serverSock, portNum, hostName, serverBuf)) < 0) {
|
|
if (i == -1) {
|
|
(void)sprintf(message, "connect to %s port:%d", hostName, portNum);
|
|
perror(message);
|
|
}
|
|
else
|
|
printf("%s\n", serverBuf);
|
|
serverSock = -1;
|
|
goto cmdclTaskWrapup;
|
|
}
|
|
printf("%s\n", serverBuf);
|
|
if (ezsFopenToFd(&myIn, &serverSock) < 0) {
|
|
perror("myIn");
|
|
myIn = NULL;
|
|
goto cmdclTaskWrapup;
|
|
}
|
|
setbuf(myIn, NULL);
|
|
if (ezsFopenToFd(&myOut, &serverSock) < 0) {
|
|
perror("myOut");
|
|
myOut = NULL;
|
|
goto cmdclTaskWrapup;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* "processing loop"
|
|
* do the interactions with the server, attempting as much as possible
|
|
* to show the messages as they come in from the server.
|
|
*---------------------------------------------------------------------------*/
|
|
while (!eofFlag) {
|
|
if (cmdclInTask(keyboard) != NULL) {
|
|
fputs(keyboard, myOut);
|
|
fflush(myOut);
|
|
}
|
|
|
|
if (ezsCheckFpRead(myIn)) {
|
|
int i, c;
|
|
|
|
i = 0;
|
|
while (ezsCheckFpRead(myIn)) {
|
|
if ((c = fgetc(myIn)) == EOF) {
|
|
eofFlag++;
|
|
break;
|
|
}
|
|
serverBuf[i++] = c;
|
|
if (i >= 79 || c == '\n')
|
|
break;
|
|
}
|
|
pBuf = serverBuf;
|
|
serverBuf[i] = '\0';
|
|
if (i > 0) {
|
|
char *findChr;
|
|
if ((findChr = index(pBuf, '#')) != NULL) {
|
|
while (pBuf != findChr) {
|
|
putchar(*pBuf);
|
|
pBuf++;
|
|
}
|
|
if (strncmp(pBuf, "#p#r#", 5) == 0) {
|
|
pBuf += 5;
|
|
discardNL = 1;
|
|
}
|
|
}
|
|
else
|
|
pBuf = serverBuf;
|
|
if (discardNL) {
|
|
if ((findNl = index(pBuf, '\n')) != NULL) {
|
|
*findNl = '\0';
|
|
discardNL = 0;
|
|
}
|
|
}
|
|
fputs(pBuf, stdout);
|
|
fflush(stdout);
|
|
}
|
|
else {
|
|
if (strncmp(keyboard, "quit", 4) == 0)
|
|
break;
|
|
else if (strncmp(keyboard, "close", 5) == 0)
|
|
break;
|
|
else if (strncmp(keyboard, "disconnect", 10) == 0)
|
|
break;
|
|
else
|
|
printf("null message from server\n");
|
|
}
|
|
}
|
|
sleep(1);
|
|
}
|
|
|
|
cmdclTaskWrapup:
|
|
if (myIn != NULL)
|
|
fclose(myIn);
|
|
if (myOut != NULL)
|
|
fclose(myOut);
|
|
if (serverSock >= 0)
|
|
close(serverSock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*+/subr**********************************************************************
|
|
* NAME cmdclTaskSig - signal handling and initialization
|
|
*
|
|
* DESCRIPTION
|
|
* These routines set up for the signals to be caught for cmdclTask
|
|
* and handle the signals when they occur.
|
|
*
|
|
* RETURNS
|
|
* void
|
|
*
|
|
* BUGS
|
|
* o not all signals are caught
|
|
* o it's not clear how useful it is to catch the signals which originate
|
|
* from the keyboard
|
|
*
|
|
*-*/
|
|
void
|
|
cmdclTaskSigHandler(signo)
|
|
int signo;
|
|
{
|
|
printf("entered cmdclTaskSigHandler for signal:%d\n", signo);
|
|
signal(signo, SIG_DFL);
|
|
longjmp(sigEnv, 1);
|
|
}
|
|
|
|
/*+/subr**********************************************************************
|
|
* NAME cmdclInTask - handle keyboard input
|
|
*
|
|
* DESCRIPTION
|
|
* Checks to see if input is available and reads it, if so. If
|
|
* there is EOF, then question is asked whether to shut down the
|
|
* server.
|
|
*
|
|
* RETURNS
|
|
* char *, or
|
|
* NULL
|
|
*
|
|
*-*/
|
|
char *
|
|
cmdclInTask(buf)
|
|
char *buf;
|
|
{
|
|
char *input;
|
|
char message[80];
|
|
fd_set fdSet; /* set of fd's to watch with select */
|
|
int fdSetWidth; /* width of select bit mask */
|
|
struct timeval fdSetTimeout;/* timeout interval for select */
|
|
|
|
struct rlimit rlp;
|
|
|
|
/* MDA - replace obsolete system call
|
|
fdSetWidth = getdtablesize();
|
|
*/
|
|
getrlimit(RLIMIT_NOFILE,&rlp);
|
|
fdSetWidth = rlp.rlim_cur;
|
|
|
|
fdSetTimeout.tv_sec = 0;
|
|
fdSetTimeout.tv_usec = 0;
|
|
FD_ZERO(&fdSet);
|
|
FD_SET(fileno(stdin), &fdSet);
|
|
|
|
if (select(fdSetWidth, &fdSet, NULL, NULL, &fdSetTimeout) == 0)
|
|
return NULL;
|
|
if (fgets(buf, 80, stdin) == NULL) {
|
|
strcpy(buf, "quit\n");
|
|
clearerr(stdin);
|
|
}
|
|
if (strncmp(buf, "quit", 4) == 0) {
|
|
(void)printf("stop the server (y/n) ? ");
|
|
if (fgets(message, 80, stdin) == NULL) {
|
|
strcpy(message, "y");
|
|
}
|
|
if (message[0] == 'y' || message[0] == 'Y')
|
|
strcpy(buf, "quit\n");
|
|
else
|
|
strcpy(buf, "\n");
|
|
}
|
|
|
|
return buf;
|
|
}
|