- Currently disabled attempts at logging commands

- Added a warning for excessive data rates on monitors
- Added statistics to devser and thus to scriptcontext
- Added byte concatenation to dynstring
- Added aborting for reflection generation to fourmess.c
- Added data checksum testing to hipadaba, use for update tests
- Fixed interrupt discovery in network.c, caused invalid interrupt
  codes which in turn confused sicscron which had to be fixed too.
- Renamed ubcalc into ubcalcint in order to reclaim the ubcalc for Jurg
- Added an a3offset to tasub in order to fix what I perceive an IS problem
- Added support for the newer version of the Siemens SPS, the S7
- Added a not yet fully working sinqhttpopt driver which talks to
  http HM without libghttp
This commit is contained in:
koennecke
2010-12-20 10:18:03 +00:00
parent 598f4a65af
commit ccae9f0d16
9 changed files with 1183 additions and 95 deletions

470
sinqhttpopt.c Normal file
View File

@ -0,0 +1,470 @@
/**
* 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
*
* After finding that libghttp actually blocks on sockets, this is
* a reimplementation doing everything itself.
*
* Mark Koennecke, November 2010
*/
#include <stdio.h>
#include <ascon.h>
#include <ascon.i>
#include <unistd.h>
#include <sicsdata.h>
#include <HistMem.h>
#include "sicshipadaba.h"
#include <stptok.h>
extern char *trim(char *txt);
/*-------------------------------------------------------------------------------
* taken from libghttp
*/
static const char b64_alphabet[65] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/=" };
static char *
http_base64_encode(const char *text) {
/* The tricky thing about this is doing the padding at the end,
* doing the bit manipulation requires a bit of concentration only */
char *buffer = NULL;
char *point = NULL;
int inlen = 0;
int outlen = 0;
/* check our args */
if (text == NULL)
return NULL;
/* Use 'buffer' to store the output. Work out how big it should be...
* This must be a multiple of 4 bytes */
inlen = strlen( text );
/* check our arg...avoid a pesky FPE */
if (inlen == 0)
{
buffer = malloc(sizeof(char));
buffer[0] = '\0';
return buffer;
}
outlen = (inlen*4)/3;
if( (inlen % 3) > 0 ) /* got to pad */
outlen += 4 - (inlen % 3);
buffer = malloc( outlen + 1 ); /* +1 for the \0 */
memset(buffer, 0, outlen + 1); /* initialize to zero */
/* now do the main stage of conversion, 3 bytes at a time,
* leave the trailing bytes (if there are any) for later */
for( point=buffer; inlen>=3; inlen-=3, text+=3 ) {
*(point++) = b64_alphabet[ *text>>2 ];
*(point++) = b64_alphabet[ (*text<<4 & 0x30) | *(text+1)>>4 ];
*(point++) = b64_alphabet[ (*(text+1)<<2 & 0x3c) | *(text+2)>>6 ];
*(point++) = b64_alphabet[ *(text+2) & 0x3f ];
}
/* Now deal with the trailing bytes */
if( inlen ) {
/* We always have one trailing byte */
*(point++) = b64_alphabet[ *text>>2 ];
*(point++) = b64_alphabet[ (*text<<4 & 0x30) |
(inlen==2?*(text+1)>>4:0) ];
*(point++) = (inlen==1?'=':b64_alphabet[ *(text+1)<<2 & 0x3c ] );
*(point++) = '=';
}
*point = '\0';
return buffer;
}
/*---------------------------------------------------------------------*/
typedef struct {
char *userName;
char *password;
pSICSData binData;
pHdb node;
int sockHandle;
int bytesExpected;
char *contentType;
} HttpProt, *pHttpProt;
/*---------------------------------------------------------------------*/
static int HTTPcallback(int handle, void *userData)
{
Ascon *a = (Ascon *)userData;
pHttpProt pHttp = NULL;
unsigned char ch;
int length;
char *data;
if(a == NULL){
printf("really serious error in HTTPcallback\n");
return 0;
}
pHttp = (pHttpProt)a->private;
data = (char *)ANETreadPtr(handle,&length);
if(data != NULL){
DynStringConcatBytes(a->rdBuffer,data,length);
}
ANETreadConsume(handle,length);
return 1;
}
/*---------------------------------------------------------------------*/
static void sendAuth(pHttpProt pHttp)
{
char buffer[256];
char *encoded = NULL;
if(pHttp->userName != NULL){
snprintf(buffer,255,"%s:%s", pHttp->userName,pHttp->password);
encoded = http_base64_encode(buffer);
if(encoded != NULL){
snprintf(buffer,255,"Authorization: Basic %s\r\n\r\n", encoded);
free(encoded);
}
} else {
strcpy(buffer,"\r\n");
}
ANETwrite(pHttp->sockHandle,buffer,strlen(buffer));
}
/*---------------------------------------------------------------------*/
static void sendGet(pHttpProt pHttp, char *path)
{
char buffer[1024];
char hostname[256];
gethostname(hostname,255);
snprintf(buffer,1024,"GET %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
path, hostname);
ANETwrite(pHttp->sockHandle, buffer,strlen(buffer));
sendAuth(pHttp);
}
/*---------------------------------------------------------------------*/
static void sendPost(pHttpProt pHttp, char *path, char *data)
{
char buffer[1024];
char hostname[256];
gethostname(hostname,255);
snprintf(buffer,1024,"POST %s HTTP/1.1\r\nHost: %s\r\nConnection: keep-alive\r\n",
path, hostname);
ANETwrite(pHttp->sockHandle, buffer,strlen(buffer));
snprintf(buffer,1024,"Content-Length: %d\r\n", strlen(data));
ANETwrite(pHttp->sockHandle, buffer,strlen(buffer));
sendAuth(pHttp);
ANETwrite(pHttp->sockHandle,data,strlen(data));
}
/*---------------------------------------------------------------------*/
static void sendRequest(pHttpProt pHttp, char *data)
{
char *path, *dataCopy, *pPtr;
dataCopy = strdup(data);
pPtr = strchr(dataCopy,':');
if(pPtr == NULL){
path = dataCopy;
sendGet(pHttp,path);
free(dataCopy);
return;
} else {
if(strstr(dataCopy,"node") != NULL){
path = pPtr+1;
pPtr = strchr(path,':');
*pPtr = '\0';
pHttp->node = FindHdbNode(NULL,path,pServ->dummyCon);
path = pPtr+1;
sendGet(pHttp,path);
free(dataCopy);
return;
} else if(strstr(dataCopy,"post") != NULL){
path = pPtr+1;
pPtr = strchr(path,':');
*pPtr = '\0';
sendPost(pHttp,path, pPtr+1);
free(dataCopy);
}
}
}
/*---------------------------------------------------------------------*/
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 = GetCharArray(a->rdBuffer);
len = GetDynStringLength(a->rdBuffer);
if (strstr(pPtr, "ERROR") != NULL) {
AsconError(a, pPtr, 0);
} else if (strstr(pPtr, "Authentication Error") != NULL) {
AsconError(a, pPtr, 0);
} else {
pType = pHttp->contentType;
if (strstr(pType, "sinqhm") != NULL) {
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);
DynStringClear(a->rdBuffer);
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 processHeader(Ascon *a)
{
char line[132], *pPtr, *data, *colon;
pHttpProt pHttp = (pHttpProt) a->private;
int status, length;
data = GetCharArray(a->rdBuffer);
assert(data != NULL);
/*
* printf("%s",data);
*/
pPtr = data;
pPtr = stptok(pPtr, line, 132, "\n");
sscanf(line,"HTTP/1.%*d %03d", &status);
if(status != 200 && status != 201){
AsconError(a,line,AsconFailure);
return 0;
}
while((pPtr = stptok(pPtr,line,132,"\n")) != NULL){
colon = strchr(line,':');
if(colon != NULL){
*colon = '\0';
colon++;
strtolower(line);
if(strstr(line,"content-length") != NULL){
pHttp->bytesExpected = atoi(trim(colon));
}
if(strstr(line,"content-type") != NULL){
if(pHttp->contentType != NULL){
free(pHttp->contentType);
}
pHttp->contentType = strdup(trim(colon));
}
if(strstr(line,"connection") != NULL){
strtolower(colon);
if(strstr(colon,"close") != NULL){
pHttp->bytesExpected = INT32_MAX;
}
}
}
}
/**
* Hack off the header
*/
pPtr = strstr(data, "\r\n\r\n");
length = GetDynStringLength(a->rdBuffer);
length -= 4 + (pPtr - data);
if(length > 0){
data = malloc(length*sizeof(char));
if(data == NULL){
AsconError(a,"Out of memory", AsconFailure);
return 0;
}
memcpy(data,pPtr+4,length);
DynStringClear(a->rdBuffer);
DynStringConcatBytes(a->rdBuffer,data,length);
free(data);
} else {
DynStringClear(a->rdBuffer);
}
return 1;
}
/*---------------------------------------------------------------------*/
static int HttpHandler(Ascon * a)
{
pHttpProt pHttp = (pHttpProt) a->private;
int socke, selStat, port, status;
fd_set rmask;
struct timeval tmo = { 0, 0 };
char buffer[1024];
char *hostport, *colon;
switch (a->state) {
case AsconConnectStart:
a->state = AsconConnecting;
break;
case AsconConnecting:
a->state = AsconConnectDone; /* success */
break;
case AsconWriteStart:
if(!ANETvalidHandle(pHttp->sockHandle)){
hostport = strdup(a->hostport);
colon = strchr(hostport, ':');
if (colon == NULL){
port = 80;
} else {
*colon = '\0';
port = atoi(colon + 1);
}
if (port <= 0) {
AsconError(a, "bad port number", 0);
return 1;
}
pHttp->sockHandle = ANETconnect(hostport,port);
free(hostport);
if(pHttp->sockHandle < 0){
AsconError(a,"Failed to connect", 0);
} else {
ANETsetReadCallback(pHttp->sockHandle,
HTTPcallback, a,NULL);
a->state = AsconWriting;
}
} else {
a->state = AsconWriting;
}
return 1;
break;
case AsconWriting:
sendRequest(pHttp,GetCharArray(a->wrBuffer));
a->state = AsconWriteDone;
a->start = DoubleTime();
pHttp->bytesExpected = -1;
DynStringClear(a->rdBuffer);
return 1;
break;
case AsconReading:
ANETprocess();
/**
* Here we have basically three conditions to check:
* - <cr><ld><cr><lf> detected means that we received
* the complete header.
* - enough bytes read: termination
* - socket closed means all data has been read
*/
if(strstr(GetCharArray(a->rdBuffer), "\r\n\r\n") != NULL){
status = processHeader(a);
if(status != 1){
a->state = AsconReadDone;
return 1;
}
}
if(!ANETvalidHandle(pHttp->sockHandle)){
handleReply(a);
a->state = AsconReadDone;
return 1;
}
if(pHttp->bytesExpected > 0 && GetDynStringLength(a->rdBuffer) >= pHttp->bytesExpected ){
handleReply(a);
a->state = AsconReadDone;
return 1;
}
return 0;
break;
default:
return AsconStdHandler(a);
}
return 1;
}
/*------------------------------------------------------------------------*/
static void killHttp(void *data)
{
pHttpProt prot = (pHttpProt) data;
if (prot == NULL) {
return;
}
if (prot->password != NULL) {
free(prot->password);
}
if (prot->userName != NULL) {
free(prot->userName);
}
if(prot->contentType != NULL){
free(prot->contentType);
}
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 object 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->sockHandle = -10;
pHttp->contentType = strdup("text/html");
a->private = pHttp;
a->killPrivate = killHttp;
a->state = AsconConnectStart;
return 1;
}
/*-------------------------------------------------------------------------*/
void AddHttpOptProtocoll()
{
AsconProtocol *prot = NULL;
prot = calloc(sizeof(AsconProtocol), 1);
prot->name = strdup("sinqhttpopt");
prot->init = HttpProtInit;
prot->handler = HttpHandler;
AsconInsertProtocol(prot);
}