/* * genbinprot.c * * This is a generic binary protocol handler for scriptcontext. It expects a * command of the form: * * writepointer:writecount:readpointer:readcount * * And will writecount bytes from the data area writepointer and * read readcount bytes into the memory area under readpointer. * If writecount is 0, the nothing will be written. This can * be used to read a binary message in parts. Both writepointer and * readpointer are memory addresses in hexadecimal. * * This is a workaround for the essential weakness of devser not being * able to work with binary protocols. * * Created on: Jul 7, 2010 * Author: koennecke */ #include #include #include #include #include #include /*-----------------------------------------------------------------*/ typedef struct { char *writePointer; unsigned int toWrite; char *readPointer; unsigned int readCount; unsigned int toRead; }GenBin, *pGenBin; /*------------------------------------------------------------------*/ static void initGenBin(Ascon *a) { pGenBin self = (pGenBin)a->private; char *pPtr = NULL, pToken[60]; long lval; pPtr = GetCharArray(a->wrBuffer); pPtr = stptok(pPtr,pToken,60,":"); sscanf(pToken,"%lx",&lval); self->writePointer = (char *)lval; pPtr = stptok(pPtr,pToken,60,":"); sscanf(pToken,"%d",&self->toWrite); pPtr = stptok(pPtr,pToken,60,":"); sscanf(pToken,"%lx",&lval); self->readPointer = (char *)lval; pPtr = stptok(pPtr,pToken,60,":"); sscanf(pToken,"%d",&self->toRead); a->wrPos = 0; self->readCount = 0; } /*------------------------------------------------------------------*/ static int GenBinHandler(Ascon *a) { pGenBin self = (pGenBin)a->private; unsigned int toWrite; int ret; char chr; switch(a->state){ case AsconWriteStart: AsconReadGarbage(a->fd); initGenBin(a); a->state = AsconWriting; break; case AsconWriting: toWrite = self->toWrite - a->wrPos; if(toWrite == 0){ a->state = AsconWriteDone; } else { ret = AsconWriteChars(a->fd, self->writePointer+a->wrPos, toWrite); if (ret < 0) { if (errno != EINTR && errno != EAGAIN) { AsconError(a, "send failed:", errno); } } else { a->wrPos += ret; if(a->wrPos >= self->toWrite){ a->state = AsconWriteDone; } } } break; case AsconReading: if(self->readCount >= self->toRead){ a->state = AsconReadDone; DynStringCopy(a->rdBuffer,"OK"); } else { ret = AsconReadChar(a->fd, &chr); if (ret < 0) { /* EINTR means we must retry */ if (errno != EINTR && errno != EAGAIN) { AsconError(a, "AsconReadChar failed:", errno); } return 1; } else if (ret > 0) { a->start = DoubleTime(); self->readPointer[self->readCount] = chr; self->readCount++; } else if (ret == 0) { if (a->timeout > 0) { if (DoubleTime() - a->start > a->timeout) { AsconError(a, "read timeout", 0); a->state = AsconTimeout; } } return 0; } } break; default: return AsconStdHandler(a); } return 1; } /*------------------------------------------------------------------------*/ static int GenBinInit(Ascon * a, SConnection * con, int argc, char *argv[]) { pGenBin priv = NULL; priv = calloc(sizeof(GenBin), 1); a->fd = -1; a->state = AsconConnectStart; a->reconnectInterval = 10; a->hostport = strdup(argv[1]); if (argc > 2) { a->timeout = atof(argv[2]); } else { a->timeout = 2.0; /* sec */ } a->private = priv; a->killPrivate = free; return 1; } /*------------------------------------------------------------------------*/ void AddGenBinProtocoll() { AsconProtocol *prot = NULL; prot = calloc(sizeof(AsconProtocol), 1); prot->name = strdup("genbin"); prot->init = GenBinInit; prot->handler = GenBinHandler; AsconInsertProtocol(prot); }