- Adapted indenation to new agreed upon system
- Added support for second generation scriptcontext based counter
This commit is contained in:
282
ascon.c
282
ascon.c
@ -18,13 +18,12 @@
|
||||
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
|
||||
*/
|
||||
|
||||
static int CreateSocketAdress(
|
||||
struct sockaddr_in *sockaddrPtr, /* Socket address */
|
||||
char *host, /* Host. NULL implies INADDR_ANY */
|
||||
int port) /* Port number */
|
||||
{
|
||||
struct hostent *hostent; /* Host database entry */
|
||||
struct in_addr addr; /* For 64/32 bit madness */
|
||||
static int CreateSocketAdress(struct sockaddr_in *sockaddrPtr, /* Socket address */
|
||||
char *host, /* Host. NULL implies INADDR_ANY */
|
||||
int port)
|
||||
{ /* Port number */
|
||||
struct hostent *hostent; /* Host database entry */
|
||||
struct in_addr addr; /* For 64/32 bit madness */
|
||||
|
||||
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
|
||||
sockaddrPtr->sin_family = AF_INET;
|
||||
@ -35,11 +34,11 @@ static int CreateSocketAdress(
|
||||
hostent = gethostbyname(host);
|
||||
if (hostent != NULL) {
|
||||
memcpy((char *) &addr,
|
||||
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
|
||||
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
|
||||
} else {
|
||||
addr.s_addr = inet_addr(host);
|
||||
if (addr.s_addr == (unsigned long)-1) {
|
||||
return 0; /* error */
|
||||
if (addr.s_addr == (unsigned long) -1) {
|
||||
return 0; /* error */
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -51,39 +50,45 @@ static int CreateSocketAdress(
|
||||
return 1;
|
||||
}
|
||||
|
||||
double DoubleTime(void) {
|
||||
double DoubleTime(void)
|
||||
{
|
||||
struct timeval now;
|
||||
/* the resolution of this function is usec, if the machine supports this
|
||||
and the mantissa of a double is 51 bits or more (31 for sec and 20 for micro)
|
||||
*/
|
||||
*/
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec + now.tv_usec / 1e6;
|
||||
}
|
||||
|
||||
void AsconError(Ascon *a, char *msg, int errorno) {
|
||||
static char *stateText[]={
|
||||
void AsconError(Ascon * a, char *msg, int errorno)
|
||||
{
|
||||
static char *stateText[] = {
|
||||
"state 0", "kill", "state 2", "notConnected",
|
||||
"connect", "start connect", "connect finished", "connect failed",
|
||||
"write", "start write", "write finished", "write failed",
|
||||
"read", "start read", "read finished", "read failed",
|
||||
"connect", "start connect", "connect finished", "connect failed",
|
||||
"write", "start write", "write finished", "write failed",
|
||||
"read", "start read", "read finished", "read failed",
|
||||
"state 16", "state 17", "state 18", "idle"
|
||||
};
|
||||
char *state;
|
||||
|
||||
|
||||
if (a->state < 0 || a->state > 19) {
|
||||
state = "bad state";
|
||||
} else {
|
||||
state = stateText[a->state];
|
||||
}
|
||||
if (errorno != 0) {
|
||||
a->errList = ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg, strerror(errorno), state);
|
||||
a->errList =
|
||||
ErrPutMsg(a->errList, "ASCERR: %s %s (during %s)", msg,
|
||||
strerror(errorno), state);
|
||||
} else {
|
||||
a->errList = ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state);
|
||||
a->errList =
|
||||
ErrPutMsg(a->errList, "ASCERR: %s (during %s)", msg, state);
|
||||
}
|
||||
a->state |= AsconFailed;
|
||||
}
|
||||
|
||||
static void AsconConnect(Ascon *a) {
|
||||
static void AsconConnect(Ascon * a)
|
||||
{
|
||||
/* input state: AsconConnectStart
|
||||
output state: AsconFailed or AsconConnecting */
|
||||
int ret;
|
||||
@ -91,17 +96,18 @@ static void AsconConnect(Ascon *a) {
|
||||
char *colon;
|
||||
int port;
|
||||
int oldopts;
|
||||
|
||||
|
||||
if (a->fd < 0) {
|
||||
a->fd = socket(AF_INET,SOCK_STREAM,0);
|
||||
a->fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (a->fd < 0) {
|
||||
AsconError(a, "socket failed:", errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
colon = strchr(a->hostport, ':');
|
||||
if (colon == NULL) return;
|
||||
port = atoi(colon+1);
|
||||
if (colon == NULL)
|
||||
return;
|
||||
port = atoi(colon + 1);
|
||||
if (port <= 0) {
|
||||
AsconError(a, "bad port number", 0);
|
||||
return;
|
||||
@ -116,48 +122,50 @@ static void AsconConnect(Ascon *a) {
|
||||
/* should we insert the workaround for lantronix server ? see network.c */
|
||||
oldopts = fcntl(a->fd, F_GETFL, 0);
|
||||
fcntl(a->fd, F_SETFL, oldopts | O_NONBLOCK);
|
||||
ret = connect(a->fd, (struct sockaddr *)&adr, sizeof(struct sockaddr_in));
|
||||
ret =
|
||||
connect(a->fd, (struct sockaddr *) &adr, sizeof(struct sockaddr_in));
|
||||
if (ret < 0) {
|
||||
switch(errno) {
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
case EISCONN:
|
||||
a->state = AsconConnecting;
|
||||
break;
|
||||
default:
|
||||
AsconError(a, "connect failed:", errno);
|
||||
return;
|
||||
}
|
||||
switch (errno) {
|
||||
case EINPROGRESS:
|
||||
case EALREADY:
|
||||
case EISCONN:
|
||||
a->state = AsconConnecting;
|
||||
break;
|
||||
default:
|
||||
AsconError(a, "connect failed:", errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
a->state = AsconConnecting;
|
||||
return;
|
||||
}
|
||||
|
||||
int AsconStdInit(Ascon *a, SConnection *con,
|
||||
int argc, char *argv[]) {
|
||||
int AsconStdInit(Ascon * a, SConnection * con, int argc, char *argv[])
|
||||
{
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
a->reconnectInterval = 10;
|
||||
a->hostport = strdup(argv[1]);
|
||||
if(argc > 2){
|
||||
a->sendTerminator = strdup(argv[2]);
|
||||
if (argc > 2) {
|
||||
a->sendTerminator = strdup(argv[2]);
|
||||
} else {
|
||||
a->sendTerminator = strdup("\n");
|
||||
a->sendTerminator = strdup("\n");
|
||||
}
|
||||
if(argc > 3){
|
||||
a->timeout = atof(argv[3]);
|
||||
if (argc > 3) {
|
||||
a->timeout = atof(argv[3]);
|
||||
} else {
|
||||
a->timeout = 2.0; /* sec */
|
||||
a->timeout = 2.0; /* sec */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AsconReadGarbage(int fd) {
|
||||
int AsconReadGarbage(int fd)
|
||||
{
|
||||
fd_set rmask;
|
||||
struct timeval tmo = {0,0};
|
||||
struct timeval tmo = { 0, 0 };
|
||||
int l, ret, result;
|
||||
char garbage[100];
|
||||
|
||||
|
||||
FD_ZERO(&rmask);
|
||||
result = 0;
|
||||
do {
|
||||
@ -179,7 +187,8 @@ int AsconReadGarbage(int fd) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrintChar(char chr) {
|
||||
void PrintChar(char chr)
|
||||
{
|
||||
if (chr <= 32 || chr >= 127) {
|
||||
printf("%2.2x ", chr);
|
||||
} else {
|
||||
@ -187,15 +196,16 @@ void PrintChar(char chr) {
|
||||
}
|
||||
}
|
||||
|
||||
int AsconConnectSuccess(int fd) {
|
||||
int AsconConnectSuccess(int fd)
|
||||
{
|
||||
fd_set wmask, rmask;
|
||||
struct timeval tmo = {0,0};
|
||||
struct timeval tmo = { 0, 0 };
|
||||
int oldopts;
|
||||
int ret;
|
||||
|
||||
|
||||
oldopts = fcntl(fd, F_GETFL, 0);
|
||||
assert(oldopts | O_NONBLOCK); /* fd must be in non-blocking mode */
|
||||
|
||||
|
||||
FD_ZERO(&wmask);
|
||||
FD_ZERO(&rmask);
|
||||
FD_SET(fd, &wmask);
|
||||
@ -203,33 +213,36 @@ int AsconConnectSuccess(int fd) {
|
||||
ret = uselect(fd + 1, &rmask, &wmask, NULL, &tmo);
|
||||
if (ret > 0) {
|
||||
assert(FD_ISSET(fd, &wmask));
|
||||
if (FD_ISSET(fd, &rmask)) { /* there may already be data for read */
|
||||
if (recv(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
if (FD_ISSET(fd, &rmask)) { /* there may already be data for read */
|
||||
if (recv(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
ret = ASCON_RECV_ERROR; /* first recv failed */
|
||||
}
|
||||
} else {
|
||||
if (send(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
if (send(fd, NULL, 0, 0) < 0) { /* zero length, check only return value */
|
||||
ret = ASCON_SEND_ERROR; /* first send failed */
|
||||
}
|
||||
}
|
||||
}
|
||||
fcntl(fd, F_SETFL, oldopts & ~ O_NONBLOCK); /* reset to blocking mode */
|
||||
fcntl(fd, F_SETFL, oldopts & ~O_NONBLOCK); /* reset to blocking mode */
|
||||
return ret;
|
||||
}
|
||||
|
||||
int AsconReadChar(int fd, char *chr) {
|
||||
int AsconReadChar(int fd, char *chr)
|
||||
{
|
||||
fd_set rmask;
|
||||
struct timeval tmo = {0,0};
|
||||
struct timeval tmo = { 0, 0 };
|
||||
int ret;
|
||||
|
||||
|
||||
FD_ZERO(&rmask);
|
||||
FD_SET(fd, &rmask);
|
||||
ret = uselect(fd + 1, &rmask, NULL, NULL, &tmo);
|
||||
if (ret <= 0) return ret;
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
ret = recv(fd, chr, 1, 0);
|
||||
/* PrintChar(*chr); */
|
||||
fflush(stdout);
|
||||
if (ret > 0) return 1;
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
if (ret == 0) {
|
||||
errno = ECONNRESET;
|
||||
return ASCON_DISCONNECTED;
|
||||
@ -237,26 +250,30 @@ int AsconReadChar(int fd, char *chr) {
|
||||
return ASCON_RECV_ERROR;
|
||||
}
|
||||
|
||||
int AsconWriteChars(int fd, char *data, int length) {
|
||||
int AsconWriteChars(int fd, char *data, int length)
|
||||
{
|
||||
fd_set wmask;
|
||||
struct timeval tmo = {0,0};
|
||||
struct timeval tmo = { 0, 0 };
|
||||
int ret;
|
||||
|
||||
if (length <= 0) return 0;
|
||||
|
||||
if (length <= 0)
|
||||
return 0;
|
||||
/*
|
||||
{ int i;
|
||||
for (i=0; i<length; i++) {
|
||||
PrintChar(data[i]);
|
||||
}
|
||||
}
|
||||
printf("<written\n");
|
||||
*/
|
||||
{ int i;
|
||||
for (i=0; i<length; i++) {
|
||||
PrintChar(data[i]);
|
||||
}
|
||||
}
|
||||
printf("<written\n");
|
||||
*/
|
||||
FD_ZERO(&wmask);
|
||||
FD_SET(fd, &wmask);
|
||||
ret = uselect(fd + 1, NULL, &wmask, NULL, &tmo);
|
||||
if (ret <= 0) return ASCON_SELECT_ERROR;
|
||||
if (ret <= 0)
|
||||
return ASCON_SELECT_ERROR;
|
||||
ret = send(fd, data, length, 0);
|
||||
if (ret > 0) return ret;
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
errno = ECONNRESET;
|
||||
return ASCON_DISCONNECTED;
|
||||
@ -266,14 +283,15 @@ int AsconWriteChars(int fd, char *data, int length) {
|
||||
|
||||
static double lastCall = 0;
|
||||
|
||||
int AsconStdHandler(Ascon *a) {
|
||||
int AsconStdHandler(Ascon * a)
|
||||
{
|
||||
int ret;
|
||||
int l;
|
||||
char chr;
|
||||
double now = DoubleTime();
|
||||
|
||||
if (now > lastCall + 0.5) { /* AsconStdHandler was not called since a long time (0.5 sec) */
|
||||
if (lastCall != 0) { /* extend timeout time (for debugging purposes) */
|
||||
|
||||
if (now > lastCall + 0.5) { /* AsconStdHandler was not called since a long time (0.5 sec) */
|
||||
if (lastCall != 0) { /* extend timeout time (for debugging purposes) */
|
||||
a->start += now - lastCall - 0.5;
|
||||
}
|
||||
}
|
||||
@ -287,17 +305,18 @@ int AsconStdHandler(Ascon *a) {
|
||||
if (ret == 0) {
|
||||
/* in progress */
|
||||
} else if (ret > 0) {
|
||||
a->state = AsconConnectDone; /* success */
|
||||
a->state = AsconConnectDone; /* success */
|
||||
} else if (ret < 0) {
|
||||
AsconError(a, "AsconConnectSuccess failed:", errno);
|
||||
}
|
||||
break;
|
||||
case AsconWriteStart:
|
||||
DynStringConcat(a->wrBuffer, a->sendTerminator);
|
||||
a->wrPos = 0;
|
||||
a->state = AsconWriting;
|
||||
if(strstr(GetCharArray(a->wrBuffer),"@@NOSEND@@") != NULL){
|
||||
a->state = AsconWriteDone;
|
||||
if (strstr(GetCharArray(a->wrBuffer), "@@NOSEND@@") != NULL) {
|
||||
a->state = AsconWriteDone;
|
||||
} else {
|
||||
DynStringConcat(a->wrBuffer, a->sendTerminator);
|
||||
a->wrPos = 0;
|
||||
a->state = AsconWriting;
|
||||
}
|
||||
break;
|
||||
case AsconWriting:
|
||||
@ -305,8 +324,8 @@ int AsconStdHandler(Ascon *a) {
|
||||
l = GetDynStringLength(a->wrBuffer) - a->wrPos;
|
||||
ret = AsconWriteChars(a->fd, GetCharArray(a->wrBuffer) + a->wrPos, l);
|
||||
if (ret < 0) {
|
||||
if(errno != EINTR && errno != EAGAIN){
|
||||
AsconError(a, "send failed:", errno);
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
AsconError(a, "send failed:", errno);
|
||||
}
|
||||
/*
|
||||
* Ooops: which state shall we go to after a write fail?
|
||||
@ -328,7 +347,7 @@ int AsconStdHandler(Ascon *a) {
|
||||
ret = AsconReadChar(a->fd, &chr);
|
||||
while (ret > 0) {
|
||||
a->start = DoubleTime();
|
||||
|
||||
|
||||
if (chr == '\n') {
|
||||
if (a->readState) {
|
||||
/* swallow LF after CR */
|
||||
@ -355,8 +374,8 @@ int AsconStdHandler(Ascon *a) {
|
||||
}
|
||||
if (ret < 0) {
|
||||
/* EINTR means we shall retry */
|
||||
if(errno != EINTR && errno != EAGAIN){
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
AsconError(a, "AsconReadChar failed:", errno);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -373,7 +392,7 @@ int AsconStdHandler(Ascon *a) {
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -381,28 +400,32 @@ int AsconStdHandler(Ascon *a) {
|
||||
#define MC_NAME(T) AsconProtocol##T
|
||||
#include "mclist.c"
|
||||
|
||||
static AsconProtocolList protocols={0};
|
||||
static AsconProtocolList protocols = { 0 };
|
||||
|
||||
void AsconInsertProtocol(AsconProtocol *protocol) {
|
||||
void AsconInsertProtocol(AsconProtocol * protocol)
|
||||
{
|
||||
AsconProtocolAdd(&protocols, protocol);
|
||||
}
|
||||
|
||||
AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
|
||||
int argc, char *argv[]) {
|
||||
AsconHandler AsconSetHandler(Ascon * a, SConnection * con,
|
||||
int argc, char *argv[])
|
||||
{
|
||||
AsconProtocol *p;
|
||||
|
||||
if (argc < 1) return NULL;
|
||||
|
||||
if (argc < 1)
|
||||
return NULL;
|
||||
if (strcasecmp(argv[0], "std") == 0) {
|
||||
if (argc < 2) return NULL;
|
||||
if (argc < 2)
|
||||
return NULL;
|
||||
AsconStdInit(a, con, argc, argv);
|
||||
return AsconStdHandler;
|
||||
}
|
||||
for (p = protocols.head; p!= NULL; p=p->next) {
|
||||
for (p = protocols.head; p != NULL; p = p->next) {
|
||||
if (strcasecmp(p->name, argv[0]) == 0) {
|
||||
if(p->init(a, con, argc, argv)){
|
||||
return p->handler;
|
||||
if (p->init(a, con, argc, argv)) {
|
||||
return p->handler;
|
||||
} else {
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -411,14 +434,16 @@ AsconHandler AsconSetHandler(Ascon *a, SConnection *con,
|
||||
|
||||
/* --- implementation of higher level interface ---- */
|
||||
|
||||
char *ConcatArgs(int argc, char *argv[]) {
|
||||
char *ConcatArgs(int argc, char *argv[])
|
||||
{
|
||||
return Arg2Tcl(argc, argv, NULL, -1);
|
||||
}
|
||||
|
||||
Ascon *AsconMake(SConnection *con, int argc, char *argv[]) {
|
||||
Ascon *AsconMake(SConnection * con, int argc, char *argv[])
|
||||
{
|
||||
Ascon *a;
|
||||
char *args;
|
||||
|
||||
|
||||
a = calloc(1, sizeof(*a));
|
||||
if (a == NULL) {
|
||||
SCWrite(con, "ERROR: no memory", eError);
|
||||
@ -427,7 +452,8 @@ Ascon *AsconMake(SConnection *con, int argc, char *argv[]) {
|
||||
a->handler = AsconSetHandler(a, con, argc, argv);
|
||||
if (a->handler == NULL) {
|
||||
args = ConcatArgs(argc, argv);
|
||||
if (!args) return NULL;
|
||||
if (!args)
|
||||
return NULL;
|
||||
SCPrintf(con, eError, "ERROR: illegal protocol: %s", args);
|
||||
free(args);
|
||||
return NULL;
|
||||
@ -441,7 +467,8 @@ Ascon *AsconMake(SConnection *con, int argc, char *argv[]) {
|
||||
return a;
|
||||
}
|
||||
|
||||
void AsconKill(Ascon *a) {
|
||||
void AsconKill(Ascon * a)
|
||||
{
|
||||
if (a->fd > 0) {
|
||||
close(a->fd);
|
||||
}
|
||||
@ -450,25 +477,28 @@ void AsconKill(Ascon *a) {
|
||||
if (a->hostport) {
|
||||
free(a->hostport);
|
||||
}
|
||||
if(a->sendTerminator){
|
||||
free(a->sendTerminator);
|
||||
if (a->sendTerminator) {
|
||||
free(a->sendTerminator);
|
||||
}
|
||||
if(a->private != NULL && a->killPrivate != NULL){
|
||||
a->killPrivate(a->private);
|
||||
if (a->private != NULL && a->killPrivate != NULL) {
|
||||
a->killPrivate(a->private);
|
||||
}
|
||||
free(a);
|
||||
}
|
||||
void AsconDisconnect(Ascon *a){
|
||||
if(a->fd > 0){
|
||||
close(a->fd);
|
||||
}
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
|
||||
void AsconDisconnect(Ascon * a)
|
||||
{
|
||||
if (a->fd > 0) {
|
||||
close(a->fd);
|
||||
}
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
}
|
||||
|
||||
AsconStatus AsconTask(Ascon *a) {
|
||||
AsconStatus AsconTask(Ascon * a)
|
||||
{
|
||||
double now;
|
||||
|
||||
|
||||
while (a->handler(a)) {
|
||||
switch (a->state) {
|
||||
case AsconReading:
|
||||
@ -503,7 +533,7 @@ AsconStatus AsconTask(Ascon *a) {
|
||||
if (now > a->lastReconnect + a->reconnectInterval) {
|
||||
a->lastReconnect = now;
|
||||
close(a->fd);
|
||||
/* allow the system to cleanup the socket, otherwise a reconnect will fail*/
|
||||
/* allow the system to cleanup the socket, otherwise a reconnect will fail */
|
||||
sleep(1);
|
||||
a->fd = -1;
|
||||
a->state = AsconConnectStart;
|
||||
@ -521,8 +551,10 @@ AsconStatus AsconTask(Ascon *a) {
|
||||
return AsconIdle;
|
||||
}
|
||||
|
||||
int AsconWrite(Ascon *a, char *command, int noResponse) {
|
||||
if (a->state <= AsconConnectFailed || a->state % 4 < AsconFinished) return 0;
|
||||
int AsconWrite(Ascon * a, char *command, int noResponse)
|
||||
{
|
||||
if (a->state <= AsconConnectFailed || a->state % 4 < AsconFinished)
|
||||
return 0;
|
||||
DynStringCopy(a->wrBuffer, command);
|
||||
a->noResponse = noResponse;
|
||||
a->state = AsconWriteStart;
|
||||
@ -531,9 +563,10 @@ int AsconWrite(Ascon *a, char *command, int noResponse) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *AsconRead(Ascon *a) {
|
||||
char *AsconRead(Ascon * a)
|
||||
{
|
||||
if (a->noResponse) {
|
||||
a->noResponse=0;
|
||||
a->noResponse = 0;
|
||||
return "";
|
||||
}
|
||||
if (a->state % 4 == AsconFailed) {
|
||||
@ -547,6 +580,7 @@ char *AsconRead(Ascon *a) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ErrMsg *AsconGetErrList(Ascon *a) {
|
||||
ErrMsg *AsconGetErrList(Ascon * a)
|
||||
{
|
||||
return a->errList;
|
||||
}
|
||||
|
Reference in New Issue
Block a user