diff --git a/julprot.c b/julprot.c new file mode 100644 index 0000000..8d823a3 --- /dev/null +++ b/julprot.c @@ -0,0 +1,80 @@ +/** + * This is a protocol implementation for the new SICS asynchronous I/O + * infrastructure and the Juelich chopper system as used at MARS. + * + * The Juelich chopper control program likes checksums to come with + * messages and uses $ as both send and reply terminators. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, June 2008 + */ +#include +#include +#include +#include + +static int calculateJulCheckSum(char *realCommand){ + int i, checkSum = 0; + + for(i = 1; i < strlen(realCommand); i++){ + checkSum += (int)realCommand[i]; + } + return checkSum; +} +/*---------------------------------------------------------------------------*/ +int JulchoHandler(Ascon *a){ + char *data = NULL; + int checkSum, ret; + char checkBuffer[30], chr; + + switch(a->state){ + case AsconWriteStart: + data = GetCharArray(a->wrBuffer); + checkSum = calculateJulCheckSum(data); + snprintf(checkBuffer,30,"{%d}$", checkSum); + DynStringConcat(a->wrBuffer,checkBuffer); + a->state = AsconWriting; + a->wrPos = 0; + break; + case AsconReading: + ret = AsconReadChar(a->fd, &chr); + if(ret < 0){ + AsconError(a, "AsconReadChar failed:", errno); + return 1; + } else if (ret > 0) { + a->start = DoubleTime(); + if(chr == '$'){ + DynStringConcatChar(a->rdBuffer, '\0'); + a->state = AsconReadDone; + break; + } else { + if (DynStringConcatChar(a->rdBuffer, chr) == 0) { + AsconError(a, "DynStringConcatChar failed:", ENOMEM); + break; + } + } + } else if(ret == 0){ + if (a->timeout > 0) { + if (DoubleTime() - a->start > a->timeout) { + AsconError(a, "read timeout", 0); + a->state = AsconTimeout; + } + } + } + break; + default: + return AsconStdHandler(a); + } + return 1; +} +/*-------------------------------------------------------------------------*/ +void AddJulChoProtocoll(){ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("julcho"); + prot->init = AsconStdInit; + prot->handler = JulchoHandler; + AsconInsertProtocol(prot); +} diff --git a/make_gen b/make_gen index 8eb053e..64ae129 100644 --- a/make_gen +++ b/make_gen @@ -22,7 +22,7 @@ OBJ=psi.o buffer.o ruli.o dmc.o nxsans.o nextrics.o sps.o pimotor.o \ $(MZOBJ) amordrive.o amorset.o tcpdornier.o sinqhttp.o\ dgrambroadcast.o sinq.o tabledrive.o tcpdocho.o julcho.o \ ritastorage.o poldizug.o audinelib.o delcam.o el737hpdrivsps.o \ - rebin.o sanslirebin.o lmd200.o slsvme.o + rebin.o sanslirebin.o lmd200.o slsvme.o julprot.o sinqhttpprot.o .SECONDARY.: sanslirebin.c diff --git a/makefile_linux b/makefile_linux index c4a4bf3..5ad473e 100644 --- a/makefile_linux +++ b/makefile_linux @@ -11,7 +11,7 @@ include ../sllinux_def CC = gcc CFLAGS = -I$(HDFROOT)/include -DHDF4 -DHDF5 $(NI) -Ihardsup \ - -I.. -DCYGNUS -DNONINTF -g $(DFORTIFY) \ + -I.. -DCYGNUS -DNONINTF -g $(DFORTIFY) \ -Wall -Wno-unused -Wno-comment -Wno-switch -Werror EXTRA=nintf.o diff --git a/psi.c b/psi.c index f35bf41..48a523a 100644 --- a/psi.c +++ b/psi.c @@ -75,6 +75,11 @@ extern int MakeSansliRebin(SConnection *pCon, SicsInterp *pSics, void *pData, /* from lmd200.c */ extern int MakeLMD200(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]); +/* from julchoprot.c */ +extern void AddJulChoProtocoll(); +/* from sinqhttpprot.c */ +extern void AddHttpProtocoll(); + /*--------------------------------------------------------------------------*/ void SiteInit(void) { @@ -93,6 +98,12 @@ void SiteInit(void) { INIT(LinaStartup); INIT(HaakeStartup); INIT(AmiStartup); + + /* + * SICS specific Asynchronous I/O protocols + */ + AddJulChoProtocoll(); + AddHttpProtocoll(); } diff --git a/sinqhttpprot.c b/sinqhttpprot.c new file mode 100644 index 0000000..cc2cda1 --- /dev/null +++ b/sinqhttpprot.c @@ -0,0 +1,221 @@ +/** + * This is an asynchronous protocol implementation for HTTP. + * It includes special features to store binary data coming + * from a SINQ http histogram memory in a sinqdata object. + * Which has to be specified on initialisation. + * + * copyright: see file COPYRIGHT + * + * Mark Koennecke, June 2008 + */ +#include +#include +#include +#include +#include +/*---------------------------------------------------------------------*/ +typedef struct { + ghttp_request *request; + char *userName; + char *password; + pSICSData binData; +}HttpProt, *pHttpProt; +/*---------------------------------------------------------------------*/ +static int configRequest(Ascon *a){ + pHttpProt pHttp = (pHttpProt)a->private; + pDynString request; + char *uri = NULL; + + request = CreateDynString(64,64); + if(request == NULL){ + AsconError(a,"Out of memory", 122); + return 0; + } + DynStringConcat(request,"http://"); + DynStringConcat(request,a->hostport); + DynStringConcatChar(request,'/'); + DynStringConcat(request,GetCharArray(a->wrBuffer)); + uri = GetCharArray(request); + + ghttp_clean(pHttp->request); + ghttp_set_type(pHttp->request,ghttp_type_get); + ghttp_set_header(pHttp->request,"connection", "keep-alive"); + if(ghttp_set_uri(pHttp->request,uri) < 0){ + AsconError(a,"Bad URL", a->state); + return 0; + } + if(pHttp->userName != NULL && pHttp->password != NULL){ + ghttp_set_authinfo(pHttp->request, + pHttp->userName, pHttp->password); + } + ghttp_set_sync(pHttp->request,ghttp_async); + ghttp_prepare(pHttp->request); + DeleteDynString(request); + + return 1; +} +/*---------------------------------------------------------------------*/ +static int HttpHandler(Ascon *a) { + ghttp_status status; + pHttpProt pHttp = (pHttpProt)a->private; + char *pPtr = NULL, *pType = NULL; + HistInt *hmData = NULL; + int i, len; + + switch (a->state) { + case AsconKillMe: return 0; + case AsconConnectStart: + a->state = AsconConnecting; + break; + case AsconConnecting: + a->state = AsconConnectDone; /* success */ + break; + case AsconWriteStart: + if(configRequest(a)){ + a->state = AsconWriting; + } + break; + case AsconWriting: + status = ghttp_process(pHttp->request); + if(status == ghttp_error){ + ghttp_close(pHttp->request); + configRequest(a); + status = ghttp_process(pHttp->request); + } + if(status == ghttp_error){ + AsconError(a,"Server error", 123); + DynStringConcat(a->rdBuffer,"Server error"); + a->state = AsconReadDone; + } else { + a->state = AsconWriteDone; + } + a->start = DoubleTime(); + DynStringClear(a->rdBuffer); + break; + case AsconReadStart: + status = ghttp_process(pHttp->request); + switch(status){ + case ghttp_not_done: + if(DoubleTime() > a->start + a->timeout){ + AsconError(a," read timeout", 0); + a->state = AsconTimeout; + /* this to clear the line */ + ghttp_close(pHttp->request); + } + return 1; + case ghttp_done: + a->state = AsconReading; + break; + case ghttp_error: + /* + * A first error may not be an error but a + * reconnect + */ + ghttp_close(pHttp->request); + configRequest(a); + status = ghttp_process(pHttp->request); + if(status == ghttp_error){ + AsconError(a,"Server error", a->state); + DynStringConcat(a->rdBuffer,"Server error"); + a->state = AsconReadDone; + } + break; + default: + printf("Hugo\n"); + break; + } + break; + case AsconReading: + pPtr = ghttp_get_body(pHttp->request); + len = ghttp_get_body_len(pHttp->request); + if(strstr(pPtr,"ERROR") != NULL){ + AsconError(a,pPtr, a->state); + DynStringConcat(a->rdBuffer,pPtr); + } else if(strstr(pPtr,"Authentication Error") != NULL){ + DynStringConcat(a->rdBuffer,pPtr); + AsconError(a,pPtr, a->state); + } else { + pType = (char *)ghttp_get_header(pHttp->request,"Content-Type"); + if(strstr(pType,"sinqhm") == NULL){ + /* text data */ + for(i = 0; i < len; i++){ + DynStringConcatChar(a->rdBuffer, pPtr[i]); + } + } else { + hmData = (HistInt *)pPtr; + clearSICSData(pHttp->binData); + for(i = 0; i < len/sizeof(HistInt); i++){ + setSICSDataInt(pHttp->binData, i, htonl(hmData[i])); + } + DynStringCopy(a->rdBuffer,"SICSDATA"); + } + } + a->state = AsconReadDone; + break; + default: + return AsconStdHandler(a); + } + return 1; +} +/*------------------------------------------------------------------------*/ +static void killHttp(void *data){ + pHttpProt prot = (pHttpProt)data; + if(prot == NULL){ + return; + } + if(prot->request != NULL){ + ghttp_close(prot->request); + } + if(prot->password != NULL){ + free(prot->password); + } + if(prot->userName != NULL){ + free(prot->userName); + } + free(prot); +} +/*------------------------------------------------------------------------*/ +static int HttpProtInit(Ascon *a, SConnection *con, + int argc, char *argv[]){ + pHttpProt pHttp = NULL; + + pHttp = calloc(sizeof(HttpProt), 1); + if(pHttp == NULL){ + SCWrite(con,"ERROR: out of memory in HttpProtInit", eError); + return 0; + } + if(argc < 3){ + return 0; + } + a->hostport = strdup(argv[1]); + pHttp->binData = (pSICSData)FindCommandData(pServ->pSics, + argv[2], "SICSData"); + if(pHttp->binData == NULL){ + SCWrite(con,"ERROR: SICSData objct not found", eError); + return 0; + } + if(argc > 3){ + a->timeout = atof(argv[3]); + } else { + a->timeout = 10.; + } + if(argc > 5){ + pHttp->userName = strdup(argv[4]); + pHttp->password = strdup(argv[5]); + } + pHttp->request = ghttp_request_new(); + a->private = pHttp; + a->killPrivate = killHttp; + a->state = AsconConnectStart; + return 1; +} +/*-------------------------------------------------------------------------*/ +void AddHttpProtocoll(){ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("sinqhttp"); + prot->init = HttpProtInit; + prot->handler = HttpHandler; + AsconInsertProtocol(prot); +}