252 lines
6.3 KiB
C
252 lines
6.3 KiB
C
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/socket.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include "err_handling.h"
|
|
#include "coc_client.h"
|
|
#include "str_util.h"
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocConnect(CocConn *conn) {
|
|
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) {
|
|
if (errno==ECONNREFUSED) return(1);
|
|
ERR_COD(errno);
|
|
}
|
|
return(0);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
int CocOpen(CocConn *conn)
|
|
{
|
|
int i, try, tmo;
|
|
|
|
ERR_I(i=CocConnect(conn));
|
|
if (i==0) return(0);
|
|
if (conn->startcmd[0]=='\0') ERR_MSG("TECS is down, can not restart from here");
|
|
|
|
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) {
|
|
assert(conn!=NULL);
|
|
if (bufsize==0) bufsize=1024;
|
|
ERR_P(conn->cmdbuf=str_create_buf(bufsize, '\0'));
|
|
ERR_P(conn->resbuf=str_create_buf(bufsize, '\0'));
|
|
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;
|
|
conn->varList=NULL;
|
|
CocVarList(&conn->varList);
|
|
ERR_I(CocOpen(conn));
|
|
ERR_I(CocSendMagic(conn, conn->magic));
|
|
return(0);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocSendMagic(CocConn *conn, char *magic) {
|
|
char *err;
|
|
|
|
if (magic[0]!='#') ERR_MSG("magic must start with '#'");
|
|
str_put_start(conn->resbuf); /* use return buffer for command in order to preserve command buffer */
|
|
ERR_I(str_put_str(conn->resbuf, magic));
|
|
ERR_SI(send(conn->fd, conn->resbuf->buf, conn->resbuf->wrpos, 0));
|
|
ERR_I(CocRecv(conn->fd, conn->resbuf));
|
|
ERR_P(err=str_get_str(conn->resbuf, NULL));
|
|
if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0); goto OnError; }
|
|
ERR_I(str_get_end(conn->resbuf));
|
|
return(0);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocCheck(CocConn *conn) {
|
|
if (conn->fd<0) return(1);
|
|
ERR_SI(send(conn->fd, "quit", 5, 0));
|
|
ERR_I(CocRecv(conn->fd, conn->resbuf));
|
|
return(0);
|
|
OnError:
|
|
if (ErrCode==ECONNRESET || ErrCode==EPIPE) return(1);
|
|
return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocTryCmd(CocConn *conn)
|
|
{ if (conn->fd<0) {
|
|
ERR_I(CocOpen(conn));
|
|
ERR_I(CocSendMagic(conn, conn->magic));
|
|
}
|
|
ERR_SI(send(conn->fd, conn->cmdbuf->buf, conn->cmdbuf->wrpos, 0));
|
|
ERR_I(CocRecv(conn->fd, conn->resbuf));
|
|
return(0);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocCmdWithRetry(CocConn *conn) {
|
|
int cnt, iret;
|
|
char *err;
|
|
|
|
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 (ErrCode!=ECONNRESET && ErrCode!=EPIPE) goto OnError;
|
|
ErrShow("try again, error was");
|
|
}
|
|
ERR_P(err=str_get_str(conn->resbuf, NULL));
|
|
if (*err!='\0') { ErrMsg(err); ErrTxt(": (response from server)",0 ); goto OnError; }
|
|
return(0);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocSet(CocConn *conn, const char *name, const char *value) {
|
|
|
|
assert(conn!=NULL);
|
|
str_put_start(conn->cmdbuf);
|
|
ERR_I(str_put_str(conn->cmdbuf, "["));
|
|
ERR_I(str_put_str(conn->cmdbuf, name));
|
|
ERR_I(str_put_str(conn->cmdbuf, value));
|
|
ERR_I(str_put_str(conn->cmdbuf, "]"));
|
|
|
|
ERR_I(CocCmdWithRetry(conn));
|
|
|
|
ERR_I(str_get_end(conn->resbuf));
|
|
return(0);
|
|
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocGetN(CocConn *conn, const char *name, char *value, int reslen) {
|
|
|
|
assert(conn!=NULL);
|
|
str_put_start(conn->cmdbuf);
|
|
ERR_I(str_put_str(conn->cmdbuf, name));
|
|
|
|
ERR_I(CocCmdWithRetry(conn));
|
|
|
|
ERR_P(str_nget_str(conn->resbuf, value, reslen));
|
|
ERR_I(str_get_end(conn->resbuf));
|
|
return(0);
|
|
|
|
OnError: return(-1);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
int CocCmd(CocConn *conn, const char *rwList)
|
|
{ int setmode, i;
|
|
const char *t, *s;
|
|
char nam[32];
|
|
CocVar *var;
|
|
void *adr;
|
|
|
|
assert(conn!=NULL);
|
|
str_put_start(conn->cmdbuf);
|
|
s=rwList;
|
|
setmode=0;
|
|
do {
|
|
t=strchr(s, ',');
|
|
if (t==NULL) t=s+strlen(s);
|
|
if (*s=='[') {
|
|
if (!setmode) ERR_I(str_put_str(conn->cmdbuf, "["));
|
|
s++;
|
|
setmode=1;
|
|
}
|
|
i=t-s;
|
|
assert(i<32);
|
|
str_ncpy(nam, s, i+1);
|
|
if (setmode) {
|
|
if (nam[i-1]==']') { i--; nam[i]='\0'; setmode=0; }
|
|
ERR_I(str_put_str(conn->cmdbuf, nam));
|
|
ERR_I(CocPutVar(conn->varList, conn->cmdbuf, nam, 0));
|
|
if (!setmode) ERR_I(str_put_str(conn->cmdbuf, "]"));
|
|
} else {
|
|
var=CocFindVar(conn->varList, nam, NULL);
|
|
if (var==NULL) ERR_MSG("variable not found");
|
|
ERR_I(str_put_str(conn->cmdbuf, nam));
|
|
}
|
|
s=t+1;
|
|
} while (*t!='\0');
|
|
|
|
ERR_I(CocCmdWithRetry(conn));
|
|
|
|
/* read values */
|
|
s=rwList;
|
|
setmode=0;
|
|
do {
|
|
t=strchr(s, ',');
|
|
if (t==NULL) t=s+strlen(s);
|
|
if (*s=='[') {
|
|
s++;
|
|
setmode=1;
|
|
}
|
|
i=t-s;
|
|
if (setmode) {
|
|
if (*(t-1)==']') setmode=0;
|
|
} else {
|
|
str_ncpy(nam, s, i+1);
|
|
ERR_I(CocGetVar(conn->varList, conn->resbuf, nam, 0));
|
|
}
|
|
s=t+1;
|
|
} while (*t!='\0');
|
|
ERR_I(str_get_end(conn->resbuf));
|
|
return(0);
|
|
|
|
OnError: return(-1);
|
|
}
|
|
|
|
void CocCloseClient(CocConn *conn) {
|
|
assert(conn!=NULL);
|
|
close(conn->fd);
|
|
str_free_buf(conn->cmdbuf);
|
|
str_free_buf(conn->resbuf);
|
|
CocFreeVarList(&conn->varList);
|
|
}
|