#include #include #include #include #include #include #include #include "myc_err.h" #include "coc_util.h" #include "coc_client.h" #include "myc_str.h" /* --- non ANSI signal --- */ #ifndef SIGPIPE #define SIGPIPE 13 #endif #define COC_NETTMO 5 #define COC_RESTMO 60 #define ARG_CHAR 1 #define ARG_INT 2 #define ARG_FLT 3 #define ARG_ARR 4 #define ARG_OUT 5 /*-------------------------------------------------------------------------*/ int CocConnect(CocConn *conn) { /* connect, but do not start */ int i; struct sockaddr_in sadr; ERR_I(CocCreateSockAdr(&sadr, conn->host, conn->port)); ERR_SI(conn->fd=socket(AF_INET, SOCK_STREAM, 0)); i = 1; ERR_SI(setsockopt(conn->fd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int))); /* allow quick port reuse */ i=connect(conn->fd, (struct sockaddr *)&sadr, sizeof(sadr)); if (i<0) { close(conn->fd); conn->fd=-1; if (errno==ECONNREFUSED) return(1); ERR_COD(errno); } return(0); OnError: return(-1); } int CocOpen(CocConn *conn) { /* connect and start, if not succsessful */ int i, try, tmo; ERR_I(i=CocConnect(conn)); if (i==0) return(0); /* connection refused */ if (conn->startcmd[0]=='\0') { CocDelay(500); ErrTxt("connect",1); return(1); } printf("Starting TecsServer ...\n\n%s\n", conn->startcmd); ERR_I(system(conn->startcmd)); try=15; tmo=100; /* wait total ca. 10 sec. for max. 15 tries */ while (try>0) { try--; CocDelay(tmo); tmo=tmo*5/4; ERR_I(i=CocConnect(conn)); if (i==0) { printf("\n... connected to TecsServer\n"); return(0); } } ERR_MSG("can not start TECS, too many retries"); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocInitClient(CocConn *conn, char *host, int port, char *magic, int bufsize, char *startcmd) { int iret; assert(conn!=NULL); if (bufsize==0) bufsize=1024; StrLink(&conn->cmdbuf, conn->cmdbuf_); StrLink(&conn->resbuf, conn->resbuf_); conn->port=port; ERR_I(str_copy(conn->host, host)); ERR_I(str_copy(conn->magic, magic)); ERR_I(str_copy(conn->startcmd, startcmd)); conn->fd=-1; ERR_I(iret=CocOpen(conn)); if (iret==0) { iret=CocSendMagic(conn, conn->magic); if (iret<0) { CocCloseClient(conn); iret=1; } } return(iret); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocSendMagic(CocConn *conn, char *magic) { char *err; if (magic != conn->magic) { str_copy(conn->magic, magic); } StrClear(&conn->resbuf); /* use return buffer for command in order to preserve command buffer */ ERR_I(StrPut(&conn->resbuf, "", COC_MAGIC)); ERR_I(StrPut(&conn->resbuf, magic, COC_SEP)); ERR_I(CocSend(conn->fd, conn->resbuf.buf, conn->resbuf.wrpos)); ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); ERR_P(err=StrGet(&conn->resbuf, NULL, COC_SEP)); if (err[0]!=COC_MAGIC) ERR_MSG("magic synch error"); if (err[1]!='\0') { ErrMsg(err+1); ErrTxt(": (response from server)",0); goto OnError; } ERR_I(StrGetEnd(&conn->resbuf)); return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocCheck(CocConn *conn) { if (conn->fd<0) return(1); ERR_I(CocSend(conn->fd, "_quit", 6)); ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); return(0); OnError: if (ErrCode==ECONNRESET || ErrCode==EPIPE) return(1); return(-1); } /*-------------------------------------------------------------------------*/ int CocTryCmd(CocConn *conn) { int iret=-1; signal(SIGPIPE, SIG_IGN); if (conn->fd<0) { ERR_I(iret=CocConnect(conn)); /* was CocOpen earlier */ if (iret == 1) { CocDelay(500); ErrTxt("connect",1); return (-1); } iret=-1; ERR_I(CocSendMagic(conn, conn->magic)); } ERR_I(CocSend(conn->fd, conn->cmdbuf.buf, conn->cmdbuf.wrpos)); ERR_I(CocRecv(conn->fd, &conn->resbuf, COC_NETTMO, NULL)); return(0); OnError: if (ErrCode==ECONNRESET || ErrCode==EPIPE) return(-2); return(iret); } /*-------------------------------------------------------------------------*/ int CocCmdWithRetry(CocConn *conn) { int cnt, iret; if (conn==NULL) ERR_MSG("not connected"); cnt=3; while (1) { cnt--; if (cnt<=0) { ERR_I(CocTryCmd(conn)); break; } iret=CocTryCmd(conn); if (iret>=0) break; close(conn->fd); conn->fd=-1; if (iret==-1) goto OnError; /* severe error */ ErrShort(ErrMessage); ErrShort("try to reconnect"); } return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ void CocReset(CocConn *conn) { assert(conn!=NULL); StrClear(&conn->cmdbuf); if (conn->synch!=COC_SYN0) { conn->synch=COC_SYN0; } else { conn->synch=COC_SYN1; } StrPut(&conn->cmdbuf, "", conn->synch); conn->nargs=0; } /*-------------------------------------------------------------------------*/ int CocPushArg(CocConn *conn, const char *name, void *value, int type, int size) { StrBuf *buf; int n; assert(conn!=NULL); assert(NULL==strchr(name, ' ')); buf=&conn->cmdbuf; n=conn->nargs; if (n>=sizeof(conn->args)/sizeof(conn->args[0])) ERR_MSG("too many return arguments"); conn->args[n].adr=value; conn->args[n].type=type; conn->args[n].size=size; conn->args[n].cmd=buf->buf + buf->wrpos; conn->nargs=n+1; if (value==NULL) { ERR_I(StrPut(buf, name, ' ')); } else { ERR_I(StrPut(buf, name, COC_SEP)); } return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocPutStr(CocConn *conn, const char *name, const char *value) { ERR_I(CocPushArg(conn, name, NULL, ARG_CHAR, 0)); ERR_I(StrPut(&conn->cmdbuf, value, COC_SEP)); return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocPutFloat(CocConn *conn, const char *name, float value) { ERR_I(CocPushArg(conn, name, NULL, ARG_FLT, 0)); ERR_I(StrPutFloat(&conn->cmdbuf, value, COC_SEP)); return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocPutArray(CocConn *conn, const char *name, float *value, int value_size) { ERR_I(CocPushArg(conn, name, NULL, ARG_ARR, 0)); ERR_I(StrPutArray(&conn->cmdbuf, value, value_size)); return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocPutInt(CocConn *conn, const char *name, int value) { ERR_I(CocPushArg(conn, name, NULL, ARG_INT, 0)); ERR_I(StrPutInt(&conn->cmdbuf, value, COC_SEP)); return(0); OnError: return(-1); } /*-------------------------------------------------------------------------*/ int CocGetStr(CocConn *conn, const char *name, char *value, int value_len) { return(CocPushArg(conn, name, value, ARG_CHAR, value_len)); } /*-------------------------------------------------------------------------*/ int CocGetFloat(CocConn *conn, const char *name, float *value) { return(CocPushArg(conn, name, value, ARG_FLT, 0)); } /*-------------------------------------------------------------------------*/ int CocGetInt(CocConn *conn, const char *name, int *value) { return(CocPushArg(conn, name, value, ARG_INT, 0)); } /*-------------------------------------------------------------------------*/ int CocGetArray(CocConn *conn, const char *name, float *value, int value_size) { return(CocPushArg(conn, name, value, ARG_ARR, value_size)); } /*-------------------------------------------------------------------------*/ int CocGetOut(CocConn *conn, const char *name, OutFunc *func) { return(CocPushArg(conn, name, func, ARG_OUT, 0)); } /*-------------------------------------------------------------------------*/ int CocDoIt(CocConn *conn, char *res, int res_len) { StrBuf *buf; int i, pending; float *arr; CocArg *a; char *resp, *t, tag, *str; int iret=0; int siz; OutFunc *f; assert(conn!=NULL); ERR_I(CocCmdWithRetry(conn)); buf=&conn->resbuf; while (buf->buf[0] != conn->synch) { /* throw away unsynchronized answers */ ERR_I(CocRecv(conn->fd, buf, COC_NETTMO, NULL)); } pending=conn->nargs; *res='\0'; while (1) { if (buf->buf[0] != conn->synch) ERR_MSG("synch error"); ERR_P(StrGet(buf, NULL, conn->synch)); i=0; a=conn->args; while (pending>0 && inargs) { if (a->type!=0) { resp=buf->buf + buf->rdpos; tag=*resp; if (tag==COC_DELAYED) { /* delayed response */ resp++; ERR_P(StrGet(buf, NULL, COC_SEP)); } else { pending--; if (tag==COC_ERR || tag==COC_TRM) { /* error response */ str_ncat(res, a->cmd, res_len); resp++; ERR_P(StrGet(buf, NULL, COC_SEP)); str_ncat(res, ": ", res_len); iret=1; if (tag==COC_TRM) return(1); } else { if (a->adr==NULL) { t=strchr(res, COC_SEP); str_ncat(res, a->cmd, res_len); t=strchr(t, ' '); assert(t!=NULL); /* truncate argument */ *t=COC_SEP; str_ncat(res, "=", res_len); ERR_P(StrGet(buf, NULL, COC_SEP)); } else { str_ncat(res, a->cmd, res_len); str_ncat(res, "=", res_len); if (a->type==ARG_INT) { ERR_I(StrGetInt(buf, (int *)a->adr, COC_SEP)); } else if (a->type==ARG_FLT) { ERR_I(StrGetFloat(buf, (float *)a->adr, COC_SEP)); } else if (a->type==ARG_ARR) { arr=(float *)a->adr; ERR_I(siz=StrGetArray(buf, arr, a->size)); while (siz < a->size) { /* fill with zeroes */ arr[siz++]=0.0; } resp=""; } else if (a->type==ARG_CHAR) { ERR_P(StrNGet(buf, (char *)a->adr, a->size, COC_SEP)); } else if (a->type==ARG_OUT) { ERR_P(str=StrNGet(buf, NULL, 0, COC_SEP)); f=(OutFunc *)a->adr; f->func(str, f->arg); } else { ERR_MSG("unknown type"); } a->type=0; /* done */ } } str_ncat(res, resp, res_len); str_ncat(res, "\n", res_len); } } i++; a++; } ERR_I(StrGetEnd(buf)); if (pending==0) return(iret); /* no more delayed response awaiting */ ERR_I(CocRecv(conn->fd, buf, COC_RESTMO, NULL)); } return(iret); OnError: return(-1); } static int interrupt, logFd=0; void CocIntSignal(int sig) { char buf[4]; if (logFd) { interrupt=2; buf[0]=COC_CLRLOG; buf[1]=COC_SEP; /* send "clear log" message */ printf("\nCLRLOG\n"); CocSend(logFd, buf, 2); } else { printf("\ninterrupt\n"); interrupt=1; } } int CocWatchLog(CocConn *conn, char *loglist) { char cbuf[1024]; StrBuf *buf; int fd, iret; #if __VMS static int init=1; if (init) { init=0; DECC$CRTL_INIT(); } #endif fd=conn->fd; CocReset(conn); ERR_I(CocPutStr(conn, "loglist", loglist)); ERR_I(CocDoIt(conn, cbuf, sizeof(cbuf))); buf=&conn->resbuf; interrupt=0; logFd=fd; signal(SIGINT, CocIntSignal); while (!interrupt) { logFd=fd; ERR_I(iret=CocRecv(fd, buf, 60, &logFd)); if (iret>0) { if (buf->buf[0]==COC_CLRLOG) { /* confirmed "clear log" message */ interrupt=3; } else { /* it's a log message */ StrReset(buf); while (!StrEnd(buf)) { ERR_P(StrGet(buf, cbuf, COC_SEP)); printf("%s", cbuf); } } } } signal(SIGINT, SIG_DFL); logFd=0; if (interrupt==1) { /* send "clear log" message */ cbuf[0]=COC_CLRLOG; cbuf[1]=COC_SEP; /* send "clear log" message */ printf("\nclrlog\n"); CocSend(fd, cbuf, 2); do { ERR_I(CocRecv(fd, buf, 10, NULL)); } while (buf->buf[0]!=COC_CLRLOG); } return(0); OnError: signal(SIGINT, SIG_DFL); return(-1); } int CocShowLog(CocConn *conn, char *loglist, int start, int lines) { char cbuf[1024]; StrBuf *buf; int fd, iret; fd=conn->fd; CocReset(conn); if (start>0) { ERR_I(CocPutInt(conn, "logstart", start)); } ERR_I(CocPutInt(conn, "loglines", lines)); ERR_I(CocPutStr(conn, "logshow", loglist)); ERR_I(CocDoIt(conn, cbuf, sizeof(cbuf))); buf=&conn->resbuf; while (1) { ERR_I(iret=CocRecv(fd, buf, 10, NULL)); if (iret<=0) break; if (buf->buf[0]==COC_CLRLOG) { /* end of log message */ break; } else { /* it's a log message */ StrReset(buf); while (!StrEnd(buf)) { ERR_P(StrGet(buf, cbuf, COC_SEP)); printf("%s", cbuf); } } } return(0); OnError: signal(SIGINT, SIG_DFL); return(-1); } void CocCloseClient(CocConn *conn) { assert(conn!=NULL); if (conn->fd >= 0) close(conn->fd); conn->fd=-1; } /*-------------------------------------------------------------------------*/ static char rbuf[256]; int CocSet(CocConn *conn, const char *name, const char *value) { int iret; assert(conn!=NULL); CocReset(conn); ERR_I(CocPutStr(conn, name, value)); ERR_I(iret=CocDoIt(conn, rbuf, sizeof(rbuf))); if (iret) ERR_MSG(rbuf); return(0); OnError: return(-1); } int CocGetN(CocConn *conn, const char *name, char *value, int reslen) { int iret; assert(conn!=NULL); CocReset(conn); ERR_I(CocGetStr(conn, name, value, reslen)); ERR_I(iret=CocDoIt(conn, rbuf, sizeof(rbuf))); if (iret) ERR_MSG(rbuf); return(0); OnError: return(-1); } int CocSetGetN(CocConn *conn, const char *name, const char *cmd, char *value, int reslen) { assert(conn!=NULL); CocReset(conn); ERR_I(CocPutStr(conn, name, cmd)); ERR_I(CocDoIt(conn, value, reslen)); return(0); OnError: return(-1); }