259 lines
6.3 KiB
C
259 lines
6.3 KiB
C
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <sys/socket.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include "rs232c_def.h"
|
|
#include "asynsrv_def.h"
|
|
#include "sinq_prototypes.h"
|
|
#include "myc_err.h"
|
|
#include "tecs_serial.h"
|
|
#include "coc_logfile.h"
|
|
#include "coc_util.h"
|
|
#include "myc_str.h"
|
|
#include "myc_mem.h"
|
|
|
|
#define ASYNSRV_TYPE 1
|
|
#define TERMSRV_TYPE 2
|
|
#define EOT '\r'
|
|
|
|
typedef struct {
|
|
char host[64];
|
|
int type; /* = ASYNSRV_TYPE */
|
|
struct AsynSrv__info asyn_info; /* Contains skt, host, port & chan */
|
|
struct RS__MsgStruct to_host;
|
|
struct RS__RespStruct from_host;
|
|
} AsynSrvChan;
|
|
|
|
typedef struct {
|
|
char host[64];
|
|
int type; /* = TERMSRV_TYPE */
|
|
char res[SER_BUF_LEN];
|
|
int fd, tmo;
|
|
int (*idleHdl)(int,int);
|
|
} TermSrvChan;
|
|
|
|
void SerA_error(void) {
|
|
char *a_txt;
|
|
int a_cod, a_my, a_vms;
|
|
|
|
AsynSrv_ErrInfo(&a_txt, &a_cod, &a_my, &a_vms);
|
|
ErrMsg("asynsrv error"); ErrTxt(a_txt,0);
|
|
}
|
|
|
|
int SerWait(int tmo_msec, int fd) {
|
|
struct timeval tmo;
|
|
fd_set mask;
|
|
int i;
|
|
|
|
FD_ZERO(&mask);
|
|
FD_SET(fd, &mask);
|
|
tmo.tv_sec=tmo_msec / 1000;
|
|
tmo.tv_usec=(tmo_msec % 1000) % 1000 +1;
|
|
ERR_SI(i=select(fd+1,&mask,NULL,NULL,&tmo));
|
|
if (i==0) return(0); /* timeout */
|
|
return(1);
|
|
OnError: return(-1);
|
|
}
|
|
|
|
SerChannel *SerOpen(const char *hostPort, int msecTmo, int (*idleHdl)(int,int)) {
|
|
AsynSrvChan *aser;
|
|
TermSrvChan *tser;
|
|
char hbuf[64], cport[16], host[32];
|
|
char *p, *c;
|
|
struct sockaddr_in sadr;
|
|
int iret;
|
|
time_t t1, t2;
|
|
static int ecnt;
|
|
|
|
time(&t1);
|
|
str_copy(hbuf, hostPort);
|
|
p=str_split(host, hbuf, ':');
|
|
assert(p!=NULL);
|
|
c=str_split(cport, p, '/');
|
|
if (msecTmo==0) msecTmo=5000;
|
|
if (c!=NULL) {
|
|
NEW(aser, AsynSrvChan); aser->type=ASYNSRV_TYPE;
|
|
str_copy(aser->asyn_info.host, host);
|
|
aser->asyn_info.port=atoi(cport);
|
|
aser->asyn_info.chan=atoi(c);
|
|
|
|
iret=AsynSrv_Open(&aser->asyn_info);
|
|
if (iret==1) {
|
|
iret=AsynSrv_Config(&aser->asyn_info, "msecTmo", msecTmo, "idleHdl", idleHdl, NULL);
|
|
}
|
|
if (iret!=1) { SerA_error(); goto OnError; }
|
|
time(&t2);
|
|
ecnt=0;
|
|
logfileOut(LOG_MAIN, "connection to %s:%d/%d opened (%d sec)\n",
|
|
aser->asyn_info.host, aser->asyn_info.port, aser->asyn_info.chan,
|
|
t2-t1);
|
|
str_copy(aser->host, hostPort);
|
|
return((SerChannel *)aser);
|
|
} else {
|
|
NEW(tser, TermSrvChan); tser->type=TERMSRV_TYPE;
|
|
tser->tmo=msecTmo;
|
|
if (idleHdl==NULL) {
|
|
tser->idleHdl=SerWait;
|
|
} else {
|
|
tser->idleHdl=idleHdl;
|
|
}
|
|
ERR_I(CocCreateSockAdr(&sadr, host, atoi(p)));
|
|
ERR_SI(tser->fd=socket(AF_INET, SOCK_STREAM, 0));
|
|
ERR_SI(connect(tser->fd, (struct sockaddr *)&sadr, sizeof(sadr)));
|
|
time(&t2);
|
|
ecnt=0;
|
|
logfileOut(LOG_MAIN, "connected to %s (%d sec)\n", hostPort, t2-t1);
|
|
str_copy(tser->host, hostPort);
|
|
return ((SerChannel *)tser);
|
|
}
|
|
OnError:
|
|
time(&t2);
|
|
if (ecnt<4) {
|
|
logfileOut(LOG_MAIN, "failed after %d sec\n", t2-t1);
|
|
ecnt++;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
int SerSetTmo(SerChannel *serch, int msecTmo) {
|
|
AsynSrvChan *aser;
|
|
TermSrvChan *tser;
|
|
int iret;
|
|
|
|
if (serch->type==ASYNSRV_TYPE) {
|
|
aser=(AsynSrvChan *)serch;
|
|
iret=AsynSrv_Config(&aser->asyn_info, "msecTmo", msecTmo, NULL);
|
|
if (iret!=1) { SerA_error(); goto OnError; }
|
|
} else if (serch->type==TERMSRV_TYPE) {
|
|
tser=(TermSrvChan *)serch;
|
|
tser->tmo=msecTmo;
|
|
}
|
|
return 0;
|
|
OnError: return -1;
|
|
}
|
|
|
|
void SerClose(SerChannel *serch) {
|
|
AsynSrvChan *aser;
|
|
TermSrvChan *tser;
|
|
|
|
if (serch->type==ASYNSRV_TYPE) {
|
|
aser=(AsynSrvChan *)serch;
|
|
AsynSrv_Close(&aser->asyn_info, 1);
|
|
} else if (serch->type==TERMSRV_TYPE) {
|
|
tser=(TermSrvChan *)serch;
|
|
close(tser->fd);
|
|
}
|
|
serch->type=0;
|
|
}
|
|
|
|
SerChannel *SerCheck(SerChannel *serch) {
|
|
if (serch==NULL || serch->type==0) {
|
|
return(NULL);
|
|
} else {
|
|
return(serch);
|
|
}
|
|
}
|
|
|
|
char *SerCmd(SerChannel *serch, char *cmnd) {
|
|
int l, n;
|
|
AsynSrvChan *aser;
|
|
TermSrvChan *tser;
|
|
char *result, *pos;
|
|
char junk[256];
|
|
int iret, incomplete;
|
|
|
|
l=strlen(cmnd);
|
|
if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS);
|
|
cmnd[l]=EOT; l++;
|
|
cmnd[l]='\0';
|
|
|
|
logfileOut(LOG_SER, ">%s\n", cmnd);
|
|
if (serch->type==ASYNSRV_TYPE) {
|
|
aser=(AsynSrvChan *)serch;
|
|
iret=AsynSrv_SendCmnds(&aser->asyn_info, &aser->to_host, &aser->from_host, cmnd, NULL);
|
|
if (iret!=1) {
|
|
SerA_error();
|
|
SerClose(serch);
|
|
return(NULL);
|
|
}
|
|
result=AsynSrv_GetReply(&aser->asyn_info, &aser->from_host, NULL);
|
|
if (result==NULL) ERR_MSG("empty result");
|
|
} else if (serch->type==TERMSRV_TYPE) {
|
|
tser=(TermSrvChan *)serch;
|
|
ERR_I(iret=SerWait(0, tser->fd));
|
|
while (iret>0) { /* skip contents in type-ahead buffer */
|
|
ERR_SI(l=recv(tser->fd, junk, sizeof(junk)-1, 0));
|
|
if (l==0) {
|
|
ErrMsg("disconnected");
|
|
SerClose(serch);
|
|
goto OnError;
|
|
}
|
|
junk[l]='\0';
|
|
logfileOut(LOG_MAIN, "skipped: '%s'\n", junk);
|
|
ERR_I(iret=SerWait(0, tser->fd));
|
|
}
|
|
iret=send(tser->fd, cmnd, l, 0);
|
|
if (iret<0) {
|
|
ErrMsg("disconnected");
|
|
SerClose(serch);
|
|
goto OnError;
|
|
}
|
|
n=sizeof(tser->res);
|
|
pos=tser->res;
|
|
result=NULL;
|
|
incomplete=1;
|
|
while (incomplete) {
|
|
/* Wait for an event on tser->fd or a timeout tmo */
|
|
iret=tser->idleHdl(tser->tmo, tser->fd);
|
|
if (iret==0) {
|
|
if (result==NULL) ERR_MSG("timeout");
|
|
ERR_MSG("missing terminator");
|
|
}
|
|
ERR_SI(l=recv(tser->fd, pos, n, 0));
|
|
if (l==0) {
|
|
ErrMsg("disconnected");
|
|
SerClose(serch);
|
|
goto OnError;
|
|
}
|
|
n -= l;
|
|
if (n==0) ERR_MSG("answer too long");
|
|
while (l>0) {
|
|
if (*pos>' ') {
|
|
if (result==NULL) result=pos; /* skip trailing white space */
|
|
} else if (*pos<' ') { /* all control characters are treated as terminators */
|
|
if (result!=NULL) {
|
|
*pos='\0';
|
|
incomplete=0;
|
|
}
|
|
}
|
|
pos++; l--;
|
|
}
|
|
}
|
|
} else {
|
|
serch->type=0;
|
|
ERR_MSG("invalid channel");
|
|
}
|
|
logfileOut(LOG_SER, "<%s\n", result);
|
|
|
|
return(result);
|
|
OnError:
|
|
return(NULL);
|
|
}
|
|
|
|
/* obsolete ?
|
|
char *SerCmdC(SerChannel *serch, const char *cmnd) {
|
|
char cmd[SER_BUF_LEN];
|
|
int l;
|
|
|
|
l=strlen(cmnd);
|
|
if (l>=SER_BUF_LEN-1) ERR_COD(ENOBUFS);
|
|
strcpy(cmd, cmnd);
|
|
return(SerCmd(serch, cmd));
|
|
OnError: return(NULL);
|
|
}
|
|
*/
|
|
|