/** * 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 void handleReply(Ascon *a){ char *pPtr = NULL, *pType = NULL; int len, i, *dataPtr = NULL; HistInt *hmData = NULL; pHttpProt pHttp = (pHttpProt)a->private; 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); len = len/sizeof(HistInt); dataPtr = getSICSDataPointer(pHttp->binData, 0, len); for(i = 0; i < len; i++){ dataPtr[i] = htonl(hmData[i]); } assignSICSType(pHttp->binData, 0, len, INTTYPE); DynStringCopy(a->rdBuffer,"SICSDATA"); } } } /*---------------------------------------------------------------------*/ static int HttpHandler(Ascon *a) { ghttp_status status; pHttpProt pHttp = (pHttpProt)a->private; int socke, selStat; fd_set rmask; struct timeval tmo = {0,0}; switch (a->state) { 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: socke = ghttp_get_socket(pHttp->request); FD_ZERO(&rmask); FD_SET(socke,&rmask); selStat = select(socke+1,&rmask, NULL, NULL, &tmo); if(selStat != 0){ status = ghttp_process(pHttp->request); a->state = AsconReading; } else { 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; break; case AsconReading: 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: handleReply(a); a->state = AsconReadDone; 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; } return 1; break; } 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); }