diff --git a/ascon.c b/ascon.c index fe1f1995..0e66da8c 100644 --- a/ascon.c +++ b/ascon.c @@ -71,7 +71,8 @@ void AsconError(Ascon *a, char *msg, int errorno) "timeout" }; char *state; - + char num[8]; + if (a->state < 0 || a->state >= AsconMaxState) { state = "bad state"; } else { @@ -128,8 +129,10 @@ static void AsconConnect(Ascon * a) return; } colon = strchr(a->hostport, ':'); - if (colon == NULL) + if (colon == NULL) { + AsconError(a, "expected 'host:port' or 'unconnected'", 0); return; + } port = atoi(colon + 1); if (port <= 0) { AsconError(a, "bad port number", 0); @@ -321,6 +324,7 @@ int AsconBaseHandler(Ascon * a) if (ret == 0) { /* in progress */ } else if (ret > 0) { + DynStringClear(a->errmsg); a->state = AsconConnectDone; /* success */ } else if (ret < 0) { AsconError(a, "ASC3", errno); @@ -419,7 +423,7 @@ int AsconStdHandler(Ascon * a) int result; char chr; int ret, l; - char *cmd, *opt; + char *cmd, *opt, *buf; switch (a->state) { case AsconWriteStart: @@ -464,9 +468,18 @@ int AsconStdHandler(Ascon * a) } if (a->replyTerminator != NULL) { if (strchr(a->replyTerminator, chr) != NULL) { - a->state = AsconReadDone; - if (chr == '\n' || chr == '\r') { - DynStringBackspace(a->rdBuffer); /* remove LF or CR */ + if (a->compositeTerminator) { + /* one character was o.k., but all have to match */ + l = strlen(a->replyTerminator); + buf = GetCharArray(a->rdBuffer) + GetDynStringLength(a->rdBuffer) - l; + if (strncmp(buf, a->replyTerminator, l) == 0) { + a->state = AsconReadDone; + } + } else { + a->state = AsconReadDone; + if (chr == '\n' || chr == '\r') { + DynStringBackspace(a->rdBuffer); /* remove LF or CR */ + } } } } else { @@ -502,10 +515,13 @@ int AsconStdHandler(Ascon * a) * Treat hex strings as terminators right. Note that this * is limited to single character terminators. * M.Z. changed strstr to strncmp (more precise) + * + * M.Z. add new option (composite terminator): + * convert 'term' to term */ -static void AsconCheckTerminators(Ascon *a) +void AsconCheckTerminators(Ascon *a) { - int c; + int c, i, l; if (a->sendTerminator != NULL && strncmp(a->sendTerminator,"0x",2) == 0) { sscanf(a->sendTerminator,"%x",&c); @@ -517,6 +533,17 @@ static void AsconCheckTerminators(Ascon *a) a->replyTerminator[0] = (char)c; a->replyTerminator[1] = '\0'; } + a->compositeTerminator = 0; + if (a->replyTerminator != NULL && a->replyTerminator[0] == '\'') { + l = strlen(a->replyTerminator); + if (l > 2 && a->replyTerminator[l-1] == '\'') { + for (i = 0; i < l - 2; i++) { + a->replyTerminator[i] = a->replyTerminator[i+1]; + } + a->replyTerminator[l-2] = '\0'; + a->compositeTerminator = 1; + } + } } int AsconInterpreteArgs(int argc, char *argv[], @@ -715,6 +742,7 @@ AsconStatus AsconTask(Ascon * a) return AsconUnconnected; case AsconConnectDone: a->state = AsconIdle; + DynStringClear(a->errmsg); /* connection o.k. */ return AsconReady; case AsconWriteDone: if (a->noResponse) { @@ -731,6 +759,7 @@ AsconStatus AsconTask(Ascon * a) case AsconReadDone: a->state = AsconIdle; a->responseValid = 1; + DynStringClear(a->errmsg); return AsconReady; case AsconIdle: return AsconReady; @@ -794,5 +823,14 @@ char *AsconGetError(Ascon *a) int AsconLastState(Ascon *a) { - return (int)a->state; + return (int)a->state; } + +char *AsconHostport(Ascon *a) +{ + if (a==NULL) { + return NULL; + } + return a->hostport; +} + diff --git a/ascon.h b/ascon.h index 93651aba..3a46deec 100644 --- a/ascon.h +++ b/ascon.h @@ -19,7 +19,7 @@ typedef enum { AsconUnconnected, AsconPending, AsconReady, - AsconFailure + AsconFailure /* codes after this indicate also failure */ } AsconStatus; /** \brief make a new asynchronous connection @@ -96,8 +96,15 @@ void AsconError(Ascon *a, char *msg, int errorno); /** * \brief return the last ascon state. Only used for statistics - * \param a The Adcon to query + * \param a The Ascon to query * \return the AsconState as an integer. */ int AsconLastState(Ascon *a); + +/** + * \brief return host:port + * \param a The Ascon to query + * \return the host and port + */ +char *AsconHostport(Ascon *a); #endif diff --git a/ascon.i b/ascon.i index 02565009..2c510287 100644 --- a/ascon.i +++ b/ascon.i @@ -55,6 +55,7 @@ typedef int (* AsconHandler)(Ascon *connection); struct Ascon { AsconState state; /**< the current state */ int fd; /**< socket */ + int conState; /**< 1: connection refused, 0: else */ int readState; /**< (std) last char was CR */ pDynString rdBuffer; /**< read buffer */ pDynString wrBuffer; /**< write buffer */ @@ -73,6 +74,7 @@ struct Ascon { char lastChar; /**< last char read */ char *separator; /**< (std) separator for multiline responses */ int lineCount; /**< number of lines expected (counting down) */ + int compositeTerminator; /**< the terminator contains several chars */ void *private; /**< private data of protocol */ void (*killPrivate)(void *); /**< kill function for private */ }; @@ -116,6 +118,8 @@ int AsconStdHandler(Ascon *a); * if no replyTerminator is given, or if it is empty, CR, LF or CR/LF all are detected * as terminators. If the terminator is CR, LF or CR/LF, it is removed from the result, * all other terminators are kept in the result. + * is the first and the last character are single quotes (') is is treated as a composite + * terminator and not as a list of single character terminators * separator is used for multiline responses. If this parameter * is given (and not empty) a command may be followed by a line count in curly brackets, * indicating that a multiline response is expected. All the lines of the response are @@ -180,4 +184,14 @@ int AsconWriteChars(int fd, char *data, int length); */ void AsconError(Ascon *a, char *msg, int errorno); +int AsconInterpreteArgs(int argc, char *argv[], + int parc, char *parn[], char *pars[]); + + +/** + * Treat hex strings as terminators right. Note that this + * is limited to single character terminators. + */ +void AsconCheckTerminators(Ascon *a); + #endif