Files
sicspsi/sinqhttpprot.c
koennecke 3eed3432cb - Added some hipadab array math
- Added missing cnvrt files, stolen from Markus
- Debugged the new sinqhttpopt driver for SINQ HTTP HM
- Debugged the driver for the new S7 Siemens SPS
- Added handling of hexadecimal terminators to ascon.c
- Increased the write buffer size in asynnet again
- Fixed  a core dump in lld.c
- Added writing of second gen HM to nxscript.c
- Added doubletime command to SICS
- Fixed a core dump issue in sicshdbadapter.c on dimension changes
- Modified sicsobj to look for lower case keys too
2011-04-08 14:18:43 +00:00

334 lines
9.1 KiB
C

/**
* 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
*
* Expanded to handle post:url:data style and node:path:data syntax
* in preparation for a full second generation HM object.
*
* Mark Koennecke, May 2009
*/
#include <stdio.h>
#include <ascon.h>
#include <ascon.i>
#include <ghttp.h>
#include <sicsdata.h>
#include <HistMem.h>
#include "uselect.h"
#include "sicshipadaba.h"
/*---------------------------------------------------------------------*/
typedef struct {
ghttp_request *request;
char *userName;
char *password;
pSICSData binData;
pHdb node;
} HttpProt, *pHttpProt;
/*---------------------------------------------------------------------*/
static int configRequest(Ascon * a)
{
pHttpProt pHttp = (pHttpProt) a->private;
pDynString request;
char *uri = NULL;
char *data, *pPtr, *path, *dataCopy;
pHttp->node = NULL;
ghttp_clean(pHttp->request);
ghttp_set_header(pHttp->request, "connection", "keep-alive");
request = CreateDynString(64, 64);
if (request == NULL) {
AsconError(a, "Out of memory", 0);
return 0;
}
DynStringConcat(request, "http://");
DynStringConcat(request, a->hostport);
DynStringConcatChar(request, '/');
data = GetCharArray(a->wrBuffer);
if(strstr(data,"node:") == data){
dataCopy = strdup(data);
path = strchr(dataCopy,':')+1;
uri = strchr(path,':');
*uri = '\0';
uri++;
pHttp->node = FindHdbNode(NULL,path,pServ->dummyCon);
DynStringConcat(request,uri);
ghttp_set_type(pHttp->request, ghttp_type_get);
free(dataCopy);
} else if(strstr(data,"post:") == data){
dataCopy = strdup(data);
uri = strchr(dataCopy,':') + 1;
pPtr = strchr(uri,':');
*pPtr = '\0';
ghttp_set_type(pHttp->request, ghttp_type_post);
DynStringConcat(request,uri);
pPtr++;
ghttp_set_body(pHttp->request,strdup(pPtr), strlen(pPtr));
free(dataCopy);
} else {
ghttp_set_type(pHttp->request, ghttp_type_get);
DynStringConcat(request, GetCharArray(a->wrBuffer));
}
uri = GetCharArray(request);
if (ghttp_set_uri(pHttp->request, uri) < 0) {
AsconError(a, "Bad URL", 0);
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, *path = 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, 0);
DynStringConcat(a->rdBuffer, pPtr);
} else if (strstr(pPtr, "Authentication Error") != NULL) {
DynStringConcat(a->rdBuffer, pPtr);
AsconError(a, pPtr, 0);
} 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;
len = len / sizeof(HistInt);
if(pHttp->node == NULL){
clearSICSData(pHttp->binData);
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");
} else {
if(pHttp->node->value.arrayLength != len){
if(pHttp->node->value.v.intArray != NULL){
free(pHttp->node->value.v.intArray);
}
pHttp->node->value.v.intArray = malloc(len*sizeof(int));
if(pHttp->node->value.v.intArray == NULL){
AsconError(a,"Out of memory ",0);
return;
}
pHttp->node->value.arrayLength = len;
}
for(i = 0; i < len; i++){
pHttp->node->value.v.intArray[i] = htonl(hmData[i]);
}
NotifyHipadabaPar(pHttp->node,NULL);
/*
path = GetHipadabaPath(pHttp->node);
if(path != NULL){
printf("Sinqhttpprot has updated node: %s\n", path);
free(path);
}
*/
}
}
}
}
/*---------------------------------------------------------------------*/
static int HttpHandler(Ascon * a)
{
ghttp_status status;
pHttpProt pHttp = (pHttpProt) a->private;
int socke, selStat;
fd_set rmask;
struct timeval tmo = { 0, 0 };
char buffer[1024];
ghttp_current_status procStatus;
switch (a->state) {
case AsconConnectStart:
a->state = AsconConnecting;
break;
case AsconConnecting:
a->state = AsconConnectDone; /* success */
break;
case AsconWriteStart:
if (configRequest(a)) {
a->state = AsconWriting;
}
return 1;
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", 0);
DynStringConcat(a->rdBuffer, "Server error");
a->state = AsconReadDone;
} else {
procStatus = ghttp_get_status(pHttp->request);
if (procStatus.proc == ghttp_proc_response_hdrs
|| procStatus.proc == ghttp_proc_response) {
a->state = AsconWriteDone;
} else {
return 0;
}
}
a->start = DoubleTime();
DynStringClear(a->rdBuffer);
break;
case AsconReadStart:
socke = ghttp_get_socket(pHttp->request);
FD_ZERO(&rmask);
FD_SET(socke, &rmask);
selStat = uselect(socke + 1, &rmask, NULL, NULL, &tmo);
if (selStat > 0 && FD_ISSET(socke, &rmask)) {
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:
socke = ghttp_get_socket(pHttp->request);
/*
FD_ZERO(&rmask);
FD_SET(socke, &rmask);
selStat = uselect(socke + 1, &rmask, NULL, NULL, &tmo);
if (selStat == 0) {
return 1;
}
*/
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 0;
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", 0);
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);
}