
- 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
334 lines
9.1 KiB
C
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);
|
|
}
|