Files
sics/site_ansto/hardsup/aqp_opalstatus.c
Ferdi Franceschini 19f6c8541c SICS-128: Added a reactor status protocol handler called OPALSTAT for the asyncqueue.
OPALSTAT uses HTTP/1.1 and sets the UserAgent to SICS to avoid re-directs.  It also sends
the SICS version and revision numbers in the UserAgent string.
2014-04-29 15:29:03 +10:00

148 lines
4.1 KiB
C

/* @file aqp_opalstatus.c
* @brief
* Implements a simple protocol to GET reactor status using an HTTP/1.1 GET.
* It sets the UserAgent as SICS to avoid re-directs because we don't handle them.
* If the HTTP status is not OK then it returns the status in the data buffer.
*/
#include "../made_config.h"
#include <sics.h>
#include <asyncqueue.h>
#define HTTP_OK "HTTP/1.1 200 OK"
#define HTTP11 " HTTP/1.1\r\n"
#if defined SICS_VERSION && defined SICS_REVISION
#define USERAGENT "User-Agent: SICS Version = " SICS_VERSION " Revision = " SICS_REVISION "\r\n"
#else
#define USERAGENT "User-Agent: SICS\r\n"
#endif
#define HOST "Host: neutron.ansto.gov.au\r\n"
enum replystates {START, HEADER, CHKHEADEREND, MSG};
static pAsyncProtocol OPAL_Protocol = NULL;
static int OPAL_Tx(pAsyncProtocol p, pAsyncTxn txn) {
if (txn == NULL) {
return 0;
}
txn->txn_status = ATX_ACTIVE;
if (AsyncUnitWrite(txn->unit, txn->out_buf, txn->out_len) < 0) {
return 0;
}
return 1;
}
/* The header and message are followed by the character sequences given below,
* HEADER cr lf cr lf <msg len> cr lf
* MESSAGE cr lf 0x30 cr lf cr lf
* So we assume that the header is terminated by two consecutive crlf char
* pairs which are eventually followed by another crlf
* The message is assumed to be terminated by a crlf pair eventually followed
* by two more crlf pairs of characters
* Processing is simplified by discarding cr chars and counting lf chars */
static int OPAL_Rx(pAsyncProtocol p, pAsyncTxn txn, int ch) {
int ret = 1;
static int nlctr = 0;
static enum replystates state = START;
if (ch == '\r') {
return ret;
}
switch (state) {
case START:
if (ch == '\n') {
/* check HTTP status */
if ( strncmp(txn->inp_buf, HTTP_OK, strlen(HTTP_OK) ) == 0 ) {
txn->inp_idx = 0;
nlctr = 0;
state = HEADER;
} else
ret = AQU_POP_CMD;
} else if (txn->inp_idx < txn->inp_len)
txn->inp_buf[txn->inp_idx++] = ch;
else
ret = AQU_POP_CMD;
break;
case HEADER:
if (ch == '\n') {
nlctr++;
state = CHKHEADEREND;
}
break;
case CHKHEADEREND:
if (nlctr == 1 && ch == '\n')
nlctr++;
else if (nlctr == 1 && ch != '\n') {
txn->inp_idx = 0;
nlctr = 0;
state = HEADER;
} else if (nlctr == 2 && ch == '\n') {
txn->inp_idx = 0;
nlctr = 0;
state = MSG;
}
break;
case MSG:
if (txn->inp_idx >= txn->inp_len)
ret = AQU_POP_CMD;
if (nlctr == 0 && ch != '\n')
txn->inp_buf[txn->inp_idx++] = ch;
else if (nlctr == 2 && ch == '\n')
ret = AQU_POP_CMD;
else
nlctr++;
break;
}
if (ret == AQU_POP_CMD) {
nlctr = 0;
state = START;
}
return ret;
}
static int OPAL_Ev(pAsyncProtocol p, pAsyncTxn pTxn, int event) {
if (event == AQU_TIMEOUT) {
pTxn->txn_status = ATX_TIMEOUT;
return AQU_POP_CMD;
}
return AQU_POP_CMD;
}
/* Append HTTP/1.1 and Host: line to message */
static int OPAL_PrepareTxn(pAsyncProtocol p, pAsyncTxn txn, const char* cmd, int cmd_len, int rsp_len) {
int msglen;
msglen = cmd_len + strlen(HTTP11) + strlen(USERAGENT) + strlen(HOST) + 3;
txn->out_buf = (char*) malloc(msglen);
if (txn->out_buf == NULL) {
SICSLogWrite("ERROR: Out of memory in OPAL_PrepareTxn", eError);
return 0;
}
strcpy(txn->out_buf, cmd);
strcat(txn->out_buf, HTTP11);
strcat(txn->out_buf, USERAGENT);
strcat(txn->out_buf, HOST);
strcat(txn->out_buf, "\r\n");
txn->out_len = msglen;
txn->out_idx = 0;
if (txn->inp_buf != NULL) {
free(txn->inp_buf);
}
txn->inp_len = rsp_len;
txn->inp_idx = 0;
txn->txn_state = 0;
txn->txn_status = 0;
return 1;
}
void OpalStatusInitProtocol(SicsInterp *pSics) {
if (OPAL_Protocol == NULL) {
OPAL_Protocol = AsyncProtocolCreate(pSics, "OPALSTAT", NULL, NULL);
OPAL_Protocol->sendCommand = OPAL_Tx;
OPAL_Protocol->handleInput = OPAL_Rx;
OPAL_Protocol->killPrivate = NULL;
OPAL_Protocol->handleEvent = OPAL_Ev;
OPAL_Protocol->prepareTxn = OPAL_PrepareTxn;
}
}