aqhome: completed adapting to msgio2 interface.

This commit is contained in:
Martin Preuss
2023-07-12 13:33:04 +02:00
parent 39987b31c7
commit 08c3875a26
66 changed files with 1765 additions and 3914 deletions

76
aqhome/http/0BUILD Normal file
View File

@@ -0,0 +1,76 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhhttp" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="false" install="$(pkgincludedir)/ipc" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/http" >
endpoint_http.h
</headers>
<headers dist="true" >
endpoint_http_p.h
</headers>
<sources>
$(local/typefiles)
endpoint_http.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
</subdirs>
</target>
</gwbuild>

302
aqhome/http/endpoint_http.c Normal file
View File

@@ -0,0 +1,302 @@
#if 0
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "aqhome/http/endpoint_http_p.h"
#include <gwenhywfar/endpoint_tcpc.h>
#include <gwenhywfar/debug.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define AQH_ENDPOINT_HTTP_NAME "http"
#define AQH_ENDPOINT_HTTP_BUFFERSIZE 1024
#define AQH_ENDPOINT_HTTP_BOOKMARK_HEADER 0
#define AQH_ENDPOINT_HTTP_BOOKMARK_BODY 1
GWEN_INHERIT(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP)
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static int _handleReadable(GWEN_MSG_ENDPOINT *ep, GWEN_UNUSED GWEN_MSG_ENDPOINT_MGR *emgr);
static int _readCommand(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen);
static int _readHeader(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen);
static int _readBody(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen);
static int _readLineCheckEmpty(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen);
static int _calcCurrentLineLength(const GWEN_MSG_ENDPOINT *ep);
static int _parseCommandLineCheckIfHeaderNeeded(char *buffer, GWEN_DB_NODE *dbCurrentReadCommand);
GWEN_MSG_ENDPOINT *AQH_HttpEndpoint_new(const char *host, int port, const char *name, int groupId)
{
GWEN_MSG_ENDPOINT *ep;
AQH_ENDPOINT_HTTP *xep;
ep=GWEN_TcpcEndpoint_new(host, port, name?name:AQH_ENDPOINT_HTTP_NAME, groupId);
if (ep==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "here");
return NULL;
}
GWEN_NEW_OBJECT(AQH_ENDPOINT_HTTP, xep);
GWEN_INHERIT_SETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep, xep, _freeData);
xep->currentReadBuffer=GWEN_Buffer_new(0, 256, 0, 1);
xep->currentReadHeader=GWEN_DB_Group_new("header");
xep->currentReadCommand=GWEN_DB_Group_new("cmd");
GWEN_MsgEndpoint_SetDefaultBufferSize(ep, AQH_ENDPOINT_HTTP_BUFFERSIZE);
// GWEN_MsgEndpoint_SetIsMsgCompleteFn(ep, _isMsgComplete);
GWEN_MsgEndpoint_SetHandleReadableFn(ep, _handleReadable);
return ep;
}
void _freeData(void *bp, void *p)
{
AQH_ENDPOINT_HTTP *xep;
xep=(AQH_ENDPOINT_HTTP*) p;
GWEN_DB_Group_free(xep->currentReadHeader);
GWEN_DB_Group_free(xep->currentReadCommand);
GWEN_Buffer_free(xep->currentReadBuffer);
GWEN_FREE_OBJECT(xep);
}
int _handleReadable(GWEN_MSG_ENDPOINT *ep, GWEN_UNUSED GWEN_MSG_ENDPOINT_MGR *emgr)
{
AQH_ENDPOINT_HTTP *xep;
int rv;
uint8_t buffer[AQH_ENDPOINT_HTTP_BUFFERSIZE];
const uint8_t *ptr;
int len;
DBG_DEBUG(GWEN_LOGDOMAIN, "Reading from endpoint %s", GWEN_MsgEndpoint_GetName(ep));
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
do {
rv=read(GWEN_MsgEndpoint_GetFd(ep), buffer, sizeof(buffer));
} while( (rv<0) && errno==EINTR);
if (rv<0) {
if (errno==EAGAIN || errno==EWOULDBLOCK)
return GWEN_ERROR_TRY_AGAIN;
DBG_INFO(GWEN_LOGDOMAIN, "Error on read(): %s (%d)", strerror(errno), errno);
return GWEN_ERROR_IO;
}
else if (rv==0) {
DBG_INFO(GWEN_LOGDOMAIN, "EOF met on read()");
return GWEN_ERROR_IO;
}
len=rv;
ptr=buffer;
/* len=number of bytes read into buffer */
while(len) {
switch(xep->readMode) {
case AQH_EndpointHttpd_ReadMode_Command:
rv=_readCommand(ep, &ptr, &len);
break;
case AQH_EndpointHttpd_ReadMode_Headers:
rv=_readHeader(ep, &ptr, &len);
break;
case AQH_EndpointHttpd_ReadMode_Body:
rv=_readBody(ep, &ptr, &len);
break;
default:
DBG_ERROR(AQH_LOGDOMAIN, "Unexpected read mode %d", xep->readMode);
return GWEN_ERROR_INTERNAL;
}
}
return 0;
}
/* rv: 1 if packet complete, <0 on error, 0 if packet not complete */
int _readCommand(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen)
{
AQH_ENDPOINT_HTTP *xep;
int rv;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
rv=_readLineCheckEmpty(ep, pPtr, pLen);
if (rv>=0) {
if (rv==1) {
DBG_ERROR(AQH_LOGDOMAIN, "Empty command line received");
return GWEN_ERROR_BAD_DATA;
}
/* line complete, parse command */
rv=_parseCommandLineCheckIfHeaderNeeded(GWEN_Buffer_GetStart(xep->currentReadBuffer), xep->currentReadCommand);
if (rv==0) {
/* no header follows, stay in readMode AQH_EndpointHttpd_ReadMode_Command for next command */
DBG_INFO(AQH_LOGDOMAIN, "No header expected, packet finished");
return 1;
}
/* line complete, set bookmark 0=pos of header begin, advance readMode */
GWEN_Buffer_SetBookmark(xep->currentReadBuffer, AQH_ENDPOINT_HTTP_BOOKMARK_HEADER, GWEN_Buffer_GetPos(xep->currentReadBuffer));
xep->readMode=AQH_EndpointHttpd_ReadMode_Headers;
DBG_INFO(AQH_LOGDOMAIN, "Start reading headers");
}
return 0;
}
int _readHeader(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen)
{
AQH_ENDPOINT_HTTP *xep;
int rv;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
rv=_readLineCheckEmpty(ep, pPtr, pLen);
if (rv==1) {
/* line complete and empty */
// TODO: parse header
GWEN_Buffer_SetBookmark(xep->currentReadBuffer, AQH_ENDPOINT_HTTP_BOOKMARK_BODY, GWEN_Buffer_GetPos(xep->currentReadBuffer));
xep->readMode=AQH_EndpointHttpd_ReadMode_Body;
}
return 0;
}
int _readBody(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen)
{
}
/* ret: -1 if line not complete, 1 if line complete and empty, 0 if line complete and not empty */
int _readLineCheckEmpty(GWEN_MSG_ENDPOINT *ep, const uint8_t **pPtr, int *pLen)
{
AQH_ENDPOINT_HTTP *xep;
const uint8_t *ptr=*pPtr;
int len=*pLen;
const uint8_t *p2;
int rv;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
p2=memchr(ptr, 10, len);
if (p2) {
int l2;
uint32_t pos;
int currentLineLength;
l2=p2-ptr+1; /* also count the LF byte itself */
GWEN_Buffer_AppendBytes(xep->currentReadBuffer, (const char*) ptr, l2);
currentLineLength=_calcCurrentLineLength(ep);
pos=GWEN_Buffer_GetPos(xep->currentReadBuffer);
/* set bookmark 0: pos of header begin */
GWEN_Buffer_SetBookmark(xep->currentReadBuffer, 0, pos);
xep->lastLineStartPos=pos;
ptr+=l2;
len-=l2;
rv=(currentLineLength==0)?1:0;
}
else {
GWEN_Buffer_AppendBytes(xep->currentReadBuffer, (const char*) ptr, len);
ptr+=len;
len=0;
rv=-1;
}
*pPtr=ptr;
*pLen=len;
return rv;
}
int _calcCurrentLineLength(const GWEN_MSG_ENDPOINT *ep)
{
AQH_ENDPOINT_HTTP *xep;
const uint8_t *ptr;
int len=0;
xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_ENDPOINT_HTTP, ep);
ptr=(const uint8_t*) (GWEN_Buffer_GetStart(xep->currentReadBuffer)+xep->lastLineStartPos);
while(*ptr && *ptr!=10 && *ptr!=13)
len++;
return len;
}
int _parseCommandLineCheckIfHeaderNeeded(char *buffer, GWEN_DB_NODE *dbCurrentReadCommand)
{
char *p;
char *s;
s=buffer;
/* read command */
p=strchr(s, ' ');
if (!p) {
DBG_ERROR(AQH_LOGDOMAIN, "Bad format of HTTP request (%s)", buffer);
return GWEN_ERROR_INVALID;
}
*p=0;
GWEN_DB_SetCharValue(dbCurrentReadCommand, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s);
*p=' '; /* restore buffer */
p++;
s=p;
/* read URL */
p=strchr(s, ' ');
if (!p) {
DBG_ERROR(AQH_LOGDOMAIN, "Bad format of HTTP request (%s)", buffer);
return GWEN_ERROR_INVALID;
}
*p=0;
GWEN_DB_SetCharValue(dbCurrentReadCommand, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s);
*p=' '; /* restore buffer */
p++;
s=p;
if (*s==0) {
/* no protocol information follows, so we assume HTTP/0.9 */
return 0;
}
else {
GWEN_DB_SetCharValue(dbCurrentReadCommand, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
}
return 1;
}
#endif

View File

@@ -0,0 +1,22 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQH_ENDPOINT_HTTP_H
#define AQH_ENDPOINT_HTTP_H
#include <aqhome/api.h>
#include <gwenhywfar/endpoint.h>
#endif

View File

@@ -0,0 +1,42 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQH_ENDPOINT_HTTP_P_H
#define AQH_ENDPOINT_HTTP_P_H
#include "aqhome/http/endpoint_http.h"
#include <gwenhywfar/db.h>
#include <gwenhywfar/buffer.h>
enum {
AQH_EndpointHttpd_ReadMode_Command=0,
AQH_EndpointHttpd_ReadMode_Headers,
AQH_EndpointHttpd_ReadMode_Body
};
typedef struct AQH_ENDPOINT_HTTP AQH_ENDPOINT_HTTP;
struct AQH_ENDPOINT_HTTP {
int readMode;
GWEN_BUFFER *currentReadBuffer;
GWEN_DB_NODE *currentReadCommand;
GWEN_DB_NODE *currentReadHeader;
int currentBodyPos;
int currentBodySize;
int lastLineStartPos;
};
#endif