diff --git a/asyncprotocol.c b/asyncprotocol.c index 8dc0f1fa..ac9d6f6c 100644 --- a/asyncprotocol.c +++ b/asyncprotocol.c @@ -3,14 +3,35 @@ #include int defaultSendCommand(pAsyncProtocol p, pAsyncTxn txn) { + int i, iRet; + int state; + const char *term = "\r\n"; + if (p->sendTerminator) + term = p->sendTerminator; + state = 0; + for (i = 0; i < txn->out_len; ++i) { + if (txn->out_buf[i] == 0x00) { /* end of transmission */ + break; + } + else if (txn->out_buf[i] == term[state]) { + ++state; + continue; + } + state = 0; + } txn->txn_state = 0; - /* TODO: anything? */ - return AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len); + iRet = AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len); + if (iRet <= 0) + return iRet; + if (term[state] != 0) + iRet = AsyncUnitWrite(txn->unit, term, strlen(term)); + return iRet; } int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch) { - /* TODO: generic terminators */ - char term[] = { 0x0D, 0x0A, 0x00 }; + const char *term = "\r\n"; + if (p->replyTerminator) + term = p->replyTerminator; if (ch == term[txn->txn_state]) ++txn->txn_state; else @@ -27,14 +48,16 @@ int defaultHandleInput(pAsyncProtocol p, pAsyncTxn txn, int ch) { } int defaultHandleEvent(pAsyncProtocol p, pAsyncTxn txn, int event) { - /* TODO */ + /* TODO: handle the event */ + return AQU_POP_CMD; } int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_len, int rsp_len) { - /* TODO: generic terminators */ - char term[] = { 0x0D, 0x0A, 0x00 }; int i; int state; + const char *term = "\r\n"; + if (p->sendTerminator) + term = p->sendTerminator; state = 0; for (i = 0; i < cmd_len; ++i) { if (cmd[i] == 0x00) { /* end of transmission */ @@ -48,10 +71,12 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_ state = 0; } if (term[state] == 0) { + /* outgoing command is correctly terminated */ txn->out_buf = malloc(cmd_len + 1); memcpy(txn->out_buf, cmd, cmd_len + 1); } else { + /* outgoing command is NOT correctly terminated */ int tlen = strlen(term); txn->out_buf = malloc(cmd_len + tlen + 1); memcpy(txn->out_buf, cmd, cmd_len); @@ -68,14 +93,98 @@ int defaultPrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_ return 1; } +static const char* hex = "0123456789ABCDEF"; + +/*--------------------------------------------------------------------*/ +static void encodeTerminator(char *result, char *terminator) +{ + if (terminator) + while (*terminator) { + *result++ = '0'; + *result++ = 'x'; + *result++ = hex[(*terminator >> 4) &0xF]; + *result++ = hex[(*terminator) &0xF]; + ++terminator; + } + *result = '\0'; + return; +} + +static int fromHex(const char* code) { + int icode = -1; + int result = -1; + if (code[0] == '0' && (code[1] == 'x' || code[1] == 'X')) { + if (code[2] >= '0' && code[2] <= '9') + icode = (code[2] - '0'); + else if (code[2] >= 'a' && code[2] <= 'f') + icode = 10 + (code[2] - 'a'); + else if (code[2] >= 'A' && code[2] <= 'F') + icode = 10 + (code[2] - 'A'); + if (icode < 0) + return -1; + result = icode << 4; + icode = -1; + if (code[3] >= '0' && code[3] <= '9') + icode = (code[3] - '0'); + else if (code[3] >= 'a' && code[3] <= 'f') + icode = 10 + (code[3] - 'a'); + else if (code[3] >= 'A' && code[3] <= 'F') + icode = 10 + (code[3] - 'A'); + if (icode < 0) + return -1; + result |= icode; + return result; + } + return -1; +} +/*--------------------------------------------------------------------*/ +static char *decodeTerminator(char *code) +{ + int count = 0, icode; + char *pResult; + char* pCh; + char* pQt = NULL; /* pointer to quote character if found */ + + if (code == NULL) + return NULL; + count = strlen(code); + pResult = (char *) malloc(count + 1); + if (!pResult) + return NULL; + memset(pResult, 0, count + 1); + + pCh = pResult; + if (*code == '\'' || *code == '"') /* check for leading quote */ + pQt = code++; + + while (*code) { + if (pQt && *code == *pQt) /* check for trailing quote */ + break; + + if (code[0] == '\\' && code[1] == 'r') { /* CR */ + *pCh++ = '\r'; + code += 2; + } + else if (code[0] == '\\' && code[1] == 'n') { /* LF */ + *pCh++ = '\n'; + code += 2; + } + else if ((icode = fromHex(code)) >= 0) { /* Hex: 0xFF */ + *pCh++ = icode; + code += 4; + } + else /* literal */ + *pCh++ = *code++; + } + *pCh = '\0'; + + return pResult; +} int AsyncProtocolNoAction(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { char line[132]; pAsyncProtocol self = (pAsyncProtocol) pData; - if (argc > 1) { - /* TODO: handle parameters like terminators */ - } snprintf(line, 132, "%s does not understand %s", argv[0], argv[1]); SCWrite(pCon, line, eError); return 0; @@ -86,20 +195,68 @@ int AsyncProtocolAction(SConnection *pCon, SicsInterp *pSics, { char line[132]; pAsyncProtocol self = (pAsyncProtocol) pData; - /* TODO: terminators */ - snprintf(line, 132, "%s does not understand %s", argv[0], argv[1]); - SCWrite(pCon, line, eError); - return 0; + if (argc > 1) { + /* handle genecic parameters like terminators */ + if (strcasecmp(argv[1], "sendterminator") == 0) { + if (argc > 2) { + char* pPtr = decodeTerminator(argv[2]); + if (pPtr) { + if (self->sendTerminator) + free(self->sendTerminator); + self->sendTerminator = pPtr; + } + SCSendOK(pCon); + } + else + { + char term[132]; + char line[1024]; + encodeTerminator(term, self->sendTerminator); + sprintf(line, "%s.sendTerminator = \"%s\"", argv[0], term); + SCWrite(pCon, line, eValue); + } + return 1; + } + if (strcasecmp(argv[1], "replyterminator") == 0) { + if (argc > 2) { + char* pPtr = decodeTerminator(argv[2]); + if (pPtr) { + if (self->replyTerminator) + free(self->replyTerminator); + self->replyTerminator = pPtr; + } + SCSendOK(pCon); + } + else + { + char term[132]; + char line[1024]; + encodeTerminator(term, self->replyTerminator); + sprintf(line, "%s.replyTerminator = \"%s\"", argv[0], term); + SCWrite(pCon, line, eValue); + } + return 1; + } + } + /* TODO: other actions */ + return AsyncProtocolNoAction(pCon, pSics, pData, argc,argv); } void defaultKillPrivate(pAsyncProtocol p) { - /* TODO: anything? */ + if (p->privateData) { + /* TODO: anything? */ + } } void AsyncProtocolKill(void *pData) { pAsyncProtocol self = (pAsyncProtocol) pData; - DeleteDescriptor(self->pDes); + if(self->pDes) + DeleteDescriptor(self->pDes); /* TODO: more destruction maybe */ + if(self->sendTerminator != NULL) + free(self->sendTerminator); + if(self->replyTerminator != NULL) + free(self->replyTerminator); if (self->killPrivate) self->killPrivate(self); } @@ -137,6 +294,8 @@ pAsyncProtocol AsyncProtocolCreate(SicsInterp *pSics, const char* protocolName, self->handleEvent = defaultHandleEvent; self->prepareTxn = defaultPrepareTxn; self->killPrivate = defaultKillPrivate; + self->sendTerminator = strdup("\r\n"); + self->replyTerminator = strdup("\r\n"); return self; } diff --git a/asyncprotocol.h b/asyncprotocol.h index 8bb70eab..2bf04d18 100644 --- a/asyncprotocol.h +++ b/asyncprotocol.h @@ -48,6 +48,8 @@ struct __async_txn { struct __async_protocol { pObjectDescriptor pDes; char* protocolName; + char *sendTerminator; + char *replyTerminator; void* privateData; int (* sendCommand)(pAsyncProtocol p, pAsyncTxn txn); int (* handleInput)(pAsyncProtocol p, pAsyncTxn txn, int ch);