Browse Source

initial project revision

master
Georg Hopp 15 years ago
commit
36666a3ae9
  1. 57
      Makefile
  2. 24
      TODO
  3. 29
      include/appConfig.h
  4. 40
      include/client.h
  5. 6
      include/daemonize.h
  6. 50
      include/httpRequest.h
  7. 6
      include/logRotate.h
  8. 14
      include/monitor.h
  9. 51
      include/my.patch
  10. 29
      include/server.h
  11. 10
      include/signalHandling.h
  12. 9
      include/socket.h
  13. 8
      include/writeBuffer.h
  14. 17
      reader/Makefile
  15. 15
      reader/commonReader/Makefile
  16. 39
      reader/commonReader/clientClose.c
  17. 202
      reader/commonReader/clientRead.c
  18. 48
      reader/commonReader/writeBuffer.c
  19. 15
      reader/httpReader/Makefile
  20. 255
      reader/httpReader/httpRequest.c
  21. 19
      server/Makefile
  22. 40
      server/serverInit.c
  23. 238
      server/serverRun.c
  24. 35
      server/serverShutdown.c
  25. 17
      system/Makefile
  26. 23
      system/daemonize.c
  27. 70
      system/handleCmdLine.c
  28. 83
      system/logRotate.c
  29. 87
      system/monitor.c
  30. 26
      system/signalHandling.c
  31. 75
      system/socket.c
  32. 50
      xmlrpc.c

57
Makefile

@ -0,0 +1,57 @@
PROJECT = xmlrpc
INCLUDE = include
CFLAGS = -Wall -ggdb
###
# PROJECT CONFIG
#
SUBDIRS = system server reader
system_OBJ = daemonize.o handleCmdLine.o logRotate.o monitor.o \
signalHandling.o socket.o
server_OBJ = serverInit.o serverRun.o serverShutdown.o
commonReader_OBJ = clientClose.o clientRead.o writeBuffer.o
httpReader_OBJ = httpRequest.o
VPATH=$(INCLUDE)
export CFLAGS INCLUDE \
system_OBJ server_OBJ commonReader_OBJ httpReader_OBJ
OBJECTS=$(PROJECT).o \
$(addprefix system/,$(system_OBJ)) \
$(addprefix server/,$(server_OBJ)) \
$(addprefix reader/commonReader/,$(commonReader_OBJ)) \
$(addprefix reader/httpReader/,$(httpReader_OBJ))
###
# EXPLICIT RULES
#
$(PROJECT): $(PROJECT).o subdirs
gcc $(CFLAGS) -o $(PROJECT) -lexpat $(OBJECTS)
$(PROJECT).o: server.h monitor.h signalHandling.h daemonize.h appConfig.h
###
# IMPLICIT RULES
#
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
###
# PHONYS
#
.PHONY: clean subdirs subdirs_clean $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
subdirs_clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done
clean: subdirs_clean
-rm *.o

24
TODO

@ -0,0 +1,24 @@
integrate libicu for unicode support
integrate the http parsing process into the stream reading process at all
that is...a http parser is nothing else than a specialized stream reader
decouple all parts so that they are reusable at all...especially don't expect
a structure from one subcomponent as prereuqisite for another.
read trailing newlines from a request and ignore them instead of heading.
Heading newlines as long as other trailing chars than newlines should throw
an error as they are not specified within protocol.
Throw in this case is: write an HTTP Error code back on the connection and
close it as we don't expect any more sane data from it.
implement XMLRPC to C and vice versa argument mapping in some form...
in this process implement the XML parsing, i already use libexpat but only
as a testcase
start multiple workers as paralell connectionts exceed a given limit.
This can be done if everything else works fine.
make a lib and example application from most of this stuff to make it useable
from other projects. This again can be done later as long as i develope
with this goal in mind...

29
include/appConfig.h

@ -0,0 +1,29 @@
#ifndef __APP_CONFIG_H__
#define __APP_CONFIG_H__
#define MAXPENDING 10 /* Maximum outstanding connection requests */
#define MAXCLIENTS 1000 /* Maximum connection handled in paralell */
#define READBUFSIZE 2048 /* Size of receive buffer */
#define DEFAULTPORT 8801 /* default port for service */
#define DEFAULTPATH "logfiles"
#define LOGNAMEPATTERN "log-%Y-%m-%d_%Hh"
#undef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#undef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
typedef struct {
unsigned char verbose;
unsigned char doDaemon;
unsigned int maxPending;
unsigned int port;
char logPath[513];
char namePat[513];
} tAppConfig;
int
handleCmdLine(tAppConfig * config, int argc, char *argv[]);
#endif // __APP_CONFIG_H__

40
include/client.h

@ -0,0 +1,40 @@
#ifndef __CLIENT_H__
#define __CLIENT_H__
#include <stdio.h> /* for FILE */
#include <expat.h>
#include "httpRequest.h"
#define READBUFSIZE 2048 /* Size of receive readBuffer */
#define CLIENTMULTMAX 512U /* 1MB maximum size the readbuffer may grow */
#define READ_ERR_LONGLINE -2
#define READ_ERR_MEMORY -3
extern int verbose;
typedef struct {
int socket;
char * readBuffer;
char * writeBuffer;
unsigned int readPos;
unsigned int writePos;
unsigned int readBufMult;
char remoteAddr[16];
tHttpHeader httpHeader;
unsigned int bodyLenRemaining;
XML_Parser parser;
} tClient;
void clientClose(tClient * client);
int clientRead(tClient * client);
int clientWrite(tClient * client);
char * clientGetLine(tClient *, const char *, unsigned int *);
char * clientRemoveLine(tClient *, const char *, unsigned int *);
#endif // __CLIENT_H__

6
include/daemonize.h

@ -0,0 +1,6 @@
#ifndef __DAEMONIZE_H__
#define __DAEMONIZE_H__
void daemonize(void);
#endif // __DAEMONIZE_H__

50
include/httpRequest.h

@ -0,0 +1,50 @@
#ifndef __HTTP_REQUEST_H__
#define __HTTP_REQUEST_H__
#define HTTP_REQ_OPTIONS 0
#define HTTP_REQ_GET 1
#define HTTP_REQ_HEAD 2
#define HTTP_REQ_POST 3
#define HTTP_REQ_PUT 4
#define HTTP_REQ_DELETE 5
#define HTTP_REQ_TRACE 6
#define HTTP_REQ_CONNECT 7
extern char httpRequest[8][8];
typedef struct {
char * method;
char * requestUri;
char * httpVersion;
} tRequestLine;
typedef struct {
char * key;
char * value;
} tHttpHeaderLine;
typedef struct {
tRequestLine req;
tHttpHeaderLine * headers;
unsigned int headersCount;
unsigned char bodyLength;
} tHttpHeader;
typedef struct {
tHttpHeader header;
unsigned int length;
char * body;
} tHttpRequest;
int getHttpRequest(char **, unsigned int *, tHttpRequest *);
void freeHttpRequest(tHttpRequest *);
void freeHttpHeader(tHttpHeader *);
unsigned char httpHeaderIsStarted(tHttpHeader *);
int httpHeaderIsComplete(tHttpHeader *);
int httpHeaderGet(char **, unsigned int *, tHttpHeader *);
void httpHeaderParseRequestLine(tHttpHeader *, const char *, unsigned int);
#endif // __HTTP_REQUEST_H__

6
include/logRotate.h

@ -0,0 +1,6 @@
#ifndef __LOG_ROTATE_H__
#define __LOG_ROTATE_H__
void logRotate(FILE ** handle, char * logPath, char * logNamePattern);
#endif /* __LOG_ROTATE_H__ */

14
include/monitor.h

@ -0,0 +1,14 @@
#ifndef __MONITOR_H__
#define __MONITOR_H__
#include <syslog.h> /* for logging */
#define MON_INFO 0
#define MON_WARNING 1
#define MON_CRITICAL 2
#define MON_FAILURE 3
int monitor(unsigned int sev, const char * pattern, const char * message);
int syslogMonitor (unsigned int logLvl, unsigned int sev, const char *pattern, const char * message, ...) __attribute__ ((format (printf, 4, 5)));
#endif /* __MONITOR_H__ */

51
include/my.patch

@ -0,0 +1,51 @@
--- ../../xmlrpc/include/client.h 2010-08-12 20:15:42.000000000 +0200
+++ ./include/virtualitemreceiver/client.h 2010-09-13 20:51:51.284184703 +0200
@@ -3,31 +3,26 @@
#include <stdio.h> /* for FILE */
-#include <expat.h>
+#include <expat.h>
+#include "httpRequest.h"
+
+#define READBUFSIZE 2048 /* Size of receive buffer */
+#define CLIENTMULTMAX 512U /* 1MB maximum size the readbuffer may grow */
-#include "httpRequest.h"
+#define WRITE_ERR_IO -1
+#define WRITE_ERR_NOPRINT -2
-#define READBUFSIZE 2048 /* Size of receive readBuffer */
-
-extern int verbose;
+#define READ_ERR_LONGLINE -2
typedef struct {
int socket;
- char * readBuffer;
- char * writeBuffer;
+ char * readBuffer;
+ char * writeBuffer;
unsigned int readPos;
- unsigned int writePos;
+ unsigned int writePos;
+ unsigned int readBufMult;
+ unsigned int writeBufMult;
char remoteAddr[16];
tHttpHeader httpHeader;
unsigned int bodyLenRemaining;
XML_Parser parser;
} tClient;
-void clientClose(tClient * client);
-int clientRead(tClient * client);
-int clientWrite(tClient * client);
+void clientClose(tClient *);
+int clientRead(tClient *);
+int writeRemaining(tClient *);
+int writeBuffer(tClient *);
#endif // __CLIENT_H__

29
include/server.h

@ -0,0 +1,29 @@
#ifndef __SERVER_H__
#define __SERVER_H__
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/select.h> /* for select system call and related */
#include "client.h"
typedef struct {
int servSock;
tClient clients[FD_SETSIZE];
unsigned int maxFd;
fd_set socks;
char logPath[512];
char namePat[512];
FILE * wHandle;
} tServer;
void serverShutdown(tServer * server);
void serverInit(
tServer * server,
unsigned int port,
unsigned int pending,
const char * logPath,
const char * namePat);
void serverRun(tServer * server);
#endif // __SERVER_H__

10
include/signalHandling.h

@ -0,0 +1,10 @@
#ifndef __SIGNAL_HANDLING_H__
#define __SIGNAL_HANDLING_H__
extern volatile int doShutdown;
void terminate(int signum);
void init_signals(void);
#endif // __SIGNAL_HANDLING_H__

9
include/socket.h

@ -0,0 +1,9 @@
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include <arpa/inet.h> /* for in_port_t */
int initServerSocket(in_port_t port, int backlog);
int acceptConnection(int servSock, char remoteAddr[16]);
#endif /* __SOCKET_H__ */

8
include/writeBuffer.h

@ -0,0 +1,8 @@
#ifndef __WRITE_BUFFER_H__
#define __WRITE_BUFFER_H__
#include <stdio.h> /* for FILE */
int writeBuffer(char ** buffer, unsigned int * readPos, FILE * wHandle);
#endif // __WRITE_BUFFER_H__

17
reader/Makefile

@ -0,0 +1,17 @@
SUBDIRS=commonReader httpReader
.PHONY: all clean subdirs subdirs_clean $(SUBDIRS)
all: $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
subdirs_clean:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir clean; \
done
clean: subdirs_clean

15
reader/commonReader/Makefile

@ -0,0 +1,15 @@
INCLUDE=include
VPATH=../../$(INCLUDE)
OBJECTS=$(commonReader_OBJ)
all: $(OBJECTS)
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
%.o: client.h
.PHONY: clean
clean:
-rm *.o

39
reader/commonReader/clientClose.c

@ -0,0 +1,39 @@
#include <stdlib.h> /* for free() */
#include <unistd.h> /* for close() */
#include <sys/socket.h> /* for shutdown() */
#include <string.h> /* for memset and stuff */
#include <expat.h>
#include "../../include/client.h"
#include "../../include/monitor.h"
#include "../../include/httpRequest.h"
void clientClose(tClient * client)
{
if (0 != verbose) {
syslog(LOG_INFO, "closing socket for %s", client->remoteAddr);
}
/* close socket an remove from fd_set */
shutdown(client->socket, SHUT_RDWR);
close(client->socket);
/* free readBuffer */
if (NULL != client->readBuffer) {
free(client->readBuffer);
client->readBuffer = NULL;
}
if (NULL != client->writeBuffer) {
free(client->writeBuffer);
client->writeBuffer = NULL;
}
client->readPos = 0;
client->writePos = 0;
freeHttpHeader(&(client->httpHeader));
XML_ParserFree(client->parser);
memset(client->remoteAddr, 0, 16);
}

202
reader/commonReader/clientRead.c

@ -0,0 +1,202 @@
#include <unistd.h> /* for getopt */
#include <stdlib.h> /* for exit */
#include <string.h> /* for memset and stuff */
#include <errno.h> /* for errno */
#include "../../include/client.h"
#include "../../include/monitor.h"
#define GET_MULTIPLIER(size) (((size) - 1) / READBUFSIZE + 1)
static int
_clientReallocBuffer(tClient * client, unsigned int newSize)
{
unsigned int newMult = GET_MULTIPLIER(newSize);
if (CLIENTMULTMAX < newMult) {
/* line exceeds maximum line length */
return 0;
}
if (client->readBufMult < newMult) {
char * newBuffer = calloc(newMult * READBUFSIZE, sizeof(char));
if (NULL == newBuffer) {
syslogMonitor(LOG_ERR, MON_CRITICAL, "calloc",
"calloc for readbuffer[%s] failed",
client->remoteAddr);
exit(EXIT_FAILURE);
}
if (NULL != client->readBuffer) {
memcpy(newBuffer, client->readBuffer, client->readPos);
free(client->readBuffer);
client->readBuffer = newBuffer;
client->readBufMult = newMult;
} else {
/*
* we can't get the resized buffer so return the
* old multiplier
*/
newMult = client->readBufMult;
}
}
return newMult;
}
int
clientRead(tClient * client)
{
int readSize;
char readBuf[READBUFSIZE];
/*
* initialize values // read data from socket
*/
memset(readBuf, 0, READBUFSIZE);
readSize = read(client->socket, readBuf, READBUFSIZE);
switch (readSize) {
case -1:
syslogMonitor(LOG_WARNING, MON_WARNING, "socket.read",
"read returns -1 for client[%s]: %s - connection closed",
client->remoteAddr, strerror(errno));
break;
case 0:
break;
default:
if (!_clientReallocBuffer(client, client->readPos + readSize)) {
syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline",
"got to long line from client[%s] - connection closed",
client->remoteAddr);
return READ_ERR_LONGLINE;
}
if (client->readPos +readSize > client->readBufMult *READBUFSIZE) {
syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline",
"can't allocate enough memory for read on client[%s]"
" - connection closed",
client->remoteAddr);
return READ_ERR_MEMORY;
}
memcpy(client->readBuffer+client->readPos, readBuf, readSize);
client->readPos += readSize;
break;
}
return readSize;
}
#define EOB(client,addr) ((addr) -(client)->readBuffer >= (client)->readPos)
#define REMAINING(client,addr) ((client)->readPos - ((addr) - (client)->readBuffer))
static char *
_clientGetLineDelimiter(tClient * client, const char * delim, unsigned int len)
{
char * foundDelim = memchr(client->readBuffer, delim[0], client->readPos);
while (NULL != foundDelim && !EOB(client, foundDelim)) {
unsigned int i = 0;
while (i < len && !EOB(client, &(foundDelim[i])) && foundDelim[i] == delim[i]) i++;
if (i == len) {
return foundDelim;
} else {
if (!EOB(client, ++foundDelim)) {
foundDelim = memchr(foundDelim, delim[0], REMAINING(client, foundDelim));
}
}
}
return NULL;
}
/*
* this returns a newly allocate buffer, with the found line
* copied to it.
* The calles has to take care to free this buffer again,
* after he uses it.
*/
char *
clientConsumeLine(tClient * client, const char * delim, unsigned int * len)
{
char * found = clientGetLine(client, delin, len);
char * line = NULL;
if (NULL != found) {
line = calloc(*len +1, sizeof(char));
memcpy(line, found, *len);
}
return line;
}
/*
* as a side effect this gives sets length of the found line in len
*/
char *
clientGetLine(tClient * client, const char * delim, unsigned int * len)
{
char * foundDelim = _clientGetLineDelimiter(client, delim, *len);
if (NULL != foundDelim) {
*len = foundDelim -client->readBuffer -1;
return client->readBuffer;
}
return NULL;
}
char *
clientRemoveLine(tClient * client, const char * delim, unsigned int * len)
{
unsigned int lineLen;
char * foundDelim = _clientGetLineDelimiter(client, delim, &lineLen);
if (NULL != foundDelim) {
char * actAddr = client->readBuffer +client->readPos;
if (actAddr == foundDelim +*len) {
memset(client->readBuffer, 0, client->readPos);
*len = client->readPos = 0;
} else {
unsigned int moveSize = actAddr -foundDelim -*len;
unsigned int clearSize = actAddr -client->readBuffer -moveSize;
memmove(client->readBuffer, foundDelim +*len, moveSize);
memset(client->readBuffer +moveSize, 0, clearSize);
*len = client->readPos = moveSize;
}
return client->readBuffer;
}
return NULL;
}
/*
* fill a buffer from a stream. This call might not fill the whole
* buffer at once, as not len size data might have been written to
* the stream. In this case it returns a pointer to the position
* the next read has to occur.
* SIDEEFFECT: additially *len is set to the remaining size to read.
*/
char *
clientGetBuffer(tClient * client, char * buffer, unsigned int * len)
{
}

48
reader/commonReader/writeBuffer.c

@ -0,0 +1,48 @@
#include <stdio.h> /* for ferror() */
#include <string.h> /* for memset and stuff */
int
writeBuffer(char ** buffer, unsigned int * readPos, FILE * wHandle)
{
char * nlpos = strchr(*buffer, '\n');
int written = 0;
while (NULL != nlpos) {
unsigned int moveSize, clearSize;
char * actAddr;
*nlpos = '\0';
if (0 != strlen(*buffer)) {
/* write remaining stuff to file */
fputs(*buffer, wHandle);
if (ferror(wHandle)) {
return -1;
}
fputc('\n', wHandle);
if (ferror(wHandle)) {
return -1;
}
fflush(wHandle);
if (ferror(wHandle)) {
return -1;
}
written += strlen(*buffer) + 1;
}
actAddr = *buffer + *readPos;
moveSize = actAddr - nlpos - 1;
clearSize = actAddr - *buffer - moveSize;
memmove(*buffer, nlpos+1, moveSize);
memset(*buffer + moveSize, 0, clearSize);
*readPos = moveSize;
nlpos = strchr(*buffer, '\n');
}
return written;
}

15
reader/httpReader/Makefile

@ -0,0 +1,15 @@
INCLUDE=include
VPATH=../../$(INCLUDE)
OBJECTS=$(httpReader_OBJ)
all: $(OBJECTS)
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
%.o: httpRequest.h
.PHONY: clean
clean:
-rm *.o

255
reader/httpReader/httpRequest.c

@ -0,0 +1,255 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include "../../include/appConfig.h"
#include "../../include/httpRequest.h"
#include "../../include/client.h"
#define SPACE 0x20
char httpRequest[8][8] = {
"OPTIONS",
"GET",
"HEAD",
"POST",
"PUT",
"DELETE",
"TRACE",
"CONNECT"
};
/*
* Gedanken zum request einlese:
* der client liest stumpf daten, außerdem implementiert er eine Methode um die
* erste Zeile aus dem readbuffer zu entfernen.
* Des weiteren eine Methode getLine die NULL zurück gibt wenn noch keine Zeile
* komplett ist, ansonsten einen Pointer auf diese.
* Der servercode triggert das Daten lesen des client, versucht dann die erste
* Zeile zu lesen und gibt diese im erfolgsfall an den httpCode weiter um
* dann wenn dieser ein OK gibt die erste Zeile über den clientCode wieder zu entfernen.
* Leere Zeile vor der request line werden ignoriert.
* Ebenso leere Zailen nachdem der request komplett eingelesen ist.
* Nachdem alle Header Zeile eingelesen wurden...d.H. sobald eine leere Header Zeile
* gelesen wurde wird exakt bodyLength vom client versucht zu lesen...hierbei
* können die Daten die von client kommen in den body buffer übertragen werden.
* Dabei kann im client code der buffer immer entsprechend zurück gesetzt werden.
*/
int
httpHeaderGetLine(tHttpHeader * header, char ** buffer, unsigned int * readPos)
{
return 1;
}
void
httpHeaderParseRequestLine(tHttpHeader * header, const char * line, unsigned int len)
{
}
int
httpHeaderIsComplete(tHttpHeader * header)
{
if (NULL == header->req.method) {
return 0;
}
return 1;
}
unsigned char
httpHeaderIsStarted(tHttpHeader * header) {
return 1;
}
static void
httpRequestStrip(char ** buffer, unsigned int * readPos)
{
char * end = *buffer;
/* remove all surrounding CRLF */
while (('\r' == *end || '\n' == *end) && *end) {
end++;
}
if (end != *buffer) {
memmove(*buffer, end, *readPos - (end - *buffer));
memset(*buffer, 0, end - *buffer);
*readPos -= (end - * buffer);
}
}
int
httpHeaderGet(char ** buffer, unsigned int * readPos, tHttpHeader * request)
{
char * end = *buffer;
unsigned int readPosNew;
httpRequestStrip(buffer, readPos);
end = strstr(*buffer, "\r\n\r\n");
/* get header if not already read and complete */
if (!httpHeaderIsComplete(request) && NULL != end) {
/* get request line */
char * methodEnd = strchr(*buffer, SPACE);
char * uriEnd = strchr(methodEnd + 1, SPACE);
char * lineEnd = strstr(*buffer, "\r\n");
request->req.method =
calloc(methodEnd-*buffer+1, sizeof(char));
request->req.requestUri =
calloc(uriEnd-methodEnd, sizeof(char));
request->req.httpVersion =
calloc(lineEnd-uriEnd, sizeof(char));
sscanf(*buffer, "%s %s %s\r\n",
request->req.method,
request->req.requestUri,
request->req.httpVersion);
readPosNew = (*buffer + *readPos) - lineEnd - 2;
memmove(*buffer, lineEnd + 2, readPosNew);
memset(*buffer + readPosNew, 0, *readPos - readPosNew);
*readPos = readPosNew;
/* get all header lines */
do {
char * keyEnd = strchr(*buffer, ':');
lineEnd = strstr(*buffer, "\r\n");
if (lineEnd != *buffer) {
tHttpHeaderLine * actHeader;
char * actKey = NULL;
request->headersCount += 1;
request->headers = realloc(request->headers,
request->headersCount * sizeof(tHttpHeaderLine));
actHeader = &(request->headers[request->headersCount-1]);
memset(actHeader, 0, sizeof(tHttpHeaderLine));
actKey = actHeader->key = calloc(keyEnd-*buffer+1, sizeof(char));
actHeader->value = calloc(lineEnd-keyEnd-1, sizeof(char));
sscanf(*buffer, "%[^:]:%s\r\n",
actHeader->key, actHeader->value);
//while (NULL != actKey && *actKey != '\0' && (*actKey = tolower(*(actKey++)))); // strtolower
for (; NULL != actKey && *actKey != '\0'; actKey++) {
*actKey = tolower(*actKey);
}
if (0 == strncmp("content-length", actHeader->key, strlen(actHeader->key))) {
request->bodyLength = atoi(actHeader->value);
}
}
readPosNew = (*buffer + *readPos) - lineEnd - 2;
memmove(*buffer, lineEnd + 2, readPosNew);
memset(*buffer + readPosNew, 0, *readPos - readPosNew);
*readPos = readPosNew;
} while (lineEnd != *buffer);
return request->bodyLength;
}
return 0;
}
int
getHttpRequest(char ** buffer, unsigned int * readPos, tHttpRequest * request)
{
/* get body if header is read and body incomplete */
if (request->header.bodyLength != request->length) {
size_t size = MIN(
request->header.bodyLength - request->length,
*readPos);
if (0 != size) {
if (NULL == request->body) {
request->body = calloc(request->header.bodyLength, sizeof(char));
}
memcpy(request->body + request->length, *buffer, size);
memmove(*buffer, *buffer + size, *readPos - size);
memset(*buffer + (*readPos - size), 0, size);
*readPos -= size;
request->length += size;
}
}
return 0;
}
void
freeHttpHeader(tHttpHeader * header) {
unsigned int i;
if (NULL != header->req.method) {
free(header->req.method);
}
if (NULL != header->req.requestUri) {
free(header->req.requestUri);
}
if (NULL != header->req.httpVersion) {
free(header->req.httpVersion);
}
for (i=0; i<header->headersCount; i++) {
if (NULL != header->headers[i].key) {
free(header->headers[i].key);
}
if (NULL != header->headers[i].value) {
free(header->headers[i].value);
}
}
if (NULL != header->headers) {
free(header->headers);
}
memset (header, 0, sizeof (tHttpHeader));
}
void
freeHttpRequest(tHttpRequest * request) {
unsigned int i;
if (NULL != request->header.req.method) {
free(request->header.req.method);
request->header.req.method = NULL;
}
if (NULL != request->header.req.requestUri) {
free(request->header.req.requestUri);
request->header.req.requestUri = NULL;
}
if (NULL != request->header.req.httpVersion) {
free(request->header.req.httpVersion);
request->header.req.httpVersion = NULL;
}
for (i=0; i<request->header.headersCount; i++) {
if (NULL != request->header.headers[i].key) {
free(request->header.headers[i].key);
request->header.headers[i].key = NULL;
}
if (NULL != request->header.headers[i].value) {
free(request->header.headers[i].value);
request->header.headers[i].value = NULL;
}
}
if (NULL != request->header.headers) {
free(request->header.headers);
request->header.headers = NULL;
}
if (NULL != request->body) {
free(request->body);
request->body = NULL;
}
memset (request, 0, sizeof (tHttpRequest));
}

19
server/Makefile

@ -0,0 +1,19 @@
INCLUDE=include
VPATH=../$(INCLUDE)
OBJECTS=$(server_OBJ)
all: $(OBJECTS)
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
server.h: client.h
server%.o: server.h monitor.h
serverRun.o serverInit.o: socket.h logRotate.h
serverRun.o serverShutdown.o: writeBuffer.h
serverRun.o: signalHandling.h httpRequest.h
.PHONY: clean
clean:
-rm *.o

40
server/serverInit.c

@ -0,0 +1,40 @@
#include <sys/select.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for getopt */
#include "../include/server.h"
#include "../include/socket.h"
#include "../include/monitor.h"
#include "../include/logRotate.h"
void
serverInit(
tServer * server,
unsigned int port,
unsigned int pending,
const char * logPath,
const char * namePat)
{
FD_ZERO(&(server->socks));
server->servSock = initServerSocket(port, pending);
server->maxFd = server->servSock;
FD_SET(server->servSock, &(server->socks));
strncpy(server->logPath, logPath, sizeof(server->logPath)-1);
strncpy(server->namePat, namePat, sizeof(server->namePat)-1);
memset(server->clients, 0, sizeof(server->clients));
/*
* try to open file (firstrun)
*/
if (NULL == server->wHandle) {
logRotate(&(server->wHandle), server->logPath, server->namePat);
if (NULL == server->wHandle) {
syslogMonitor(LOG_ERR, MON_INFO, "logfile.rotate",
"no valid handle for logfile - service terminated");
exit(EXIT_FAILURE);
}
}
}

238
server/serverRun.c

@ -0,0 +1,238 @@
#include <sys/select.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for exit */
#include <errno.h> /* for errno */
#include <unistd.h> /* for write */
#include <expat.h>
#include "../include/appConfig.h"
#include "../include/server.h"
#include "../include/client.h"
#include "../include/socket.h"
#include "../include/monitor.h"
#include "../include/logRotate.h"
#include "../include/signalHandling.h"
#include "../include/httpRequest.h"
#define RESPONSE " 200 OK\r\nServer: xmlrpc\r\nStatus: 200\r\nContent-Length: 10\r\nContent-Type: text/plain\r\n\r\n0123456789"
int Depth;
void XMLCALL
start(void *data, const char *el, const char **attr) {
int i;
for (i = 0; i < Depth; i++)
printf(" ");
printf("%s", el);
for (i = 0; attr[i]; i += 2) {
printf(" %s='%s'", attr[i], attr[i + 1]);
}
printf("\n");
Depth++;
} /* End of start handler */
void XMLCALL
end(void *data, const char *el) {
int i;
Depth--;
for (i = 0; i < Depth; i++)
printf(" ");
printf("--\n");
} /* End of end handler */
void
serverRun(tServer * server)
{
syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");
while (!doShutdown) /* until error or signal */
{
fd_set rfds;
fd_set wfds;
int i;
memcpy(&rfds, &(server->socks), sizeof(fd_set));
FD_ZERO(&wfds);
for (i=3; i<=server->maxFd; i++) {
tClient * actClient = &(server->clients)[i];
if (FD_ISSET(i, &(server->socks))
&& NULL != actClient->writeBuffer
&& 0 != strlen(actClient->writeBuffer)) {
FD_SET(i, &wfds);
}
}
/*
* wait for handles to become ready
*/
if (-1 == select((server->maxFd)+1, &rfds, &wfds, NULL, NULL))
{
switch (errno) {
default:
case EBADF:
case EINVAL:
case ENOMEM:
doShutdown = 1;
/* Fallthrough */
case EINTR:
syslogMonitor(LOG_ERR, MON_INFO, "select",
"select systemcall failed: [%s] - service terminated",
strerror(errno));
continue; /* in while loop above */
}
}
/*
* handle accept
*/
if (FD_ISSET(server->servSock, &rfds)) {
int fd;
char remoteAddr[16] = "";
if (-1 != (fd = acceptConnection(server->servSock, remoteAddr))) {
(server->clients)[fd].socket = fd; // save the socket handle within the client struct
strncpy(
(server->clients)[fd].remoteAddr,
remoteAddr,
sizeof((server->clients)[fd].remoteAddr)-1);
FD_SET(fd, &(server->socks));
server->maxFd = MAX(fd, server->maxFd);
(server->clients)[fd].parser = XML_ParserCreate("UTF-8");
XML_SetElementHandler((server->clients)[fd].parser, &start, &end);
}
FD_CLR(server->servSock, &rfds);
}
/* handle reads (max 10 before next select, else we block accept for to long) */
for (i=3; i<=server->maxFd; i++) {
// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
tClient * actClient = &(server->clients)[i];
if (FD_ISSET(i, &rfds)) {
switch (clientRead(actClient)) {
case -1:
syslogMonitor(LOG_WARNING, MON_INFO, "socket.read",
"read on socket for %s returns -1: %s",
actClient->remoteAddr, strerror(errno));
/* FALLTHROUGH */
case 0:
clientClose(actClient);
FD_CLR(i, &(server->socks));
break;
default:
if (! httpHeaderIsComplete(&(actClient->httpHeader))) {
char delim[] = "\r\n";
unsigned int len = strlen(delim);
char * line = clientGetLine(actClient, delim, &len);
/*
* len might be 0, thus indicatin an empty line
* this might happen in two cases
* 1. when a header is not already started
* (could be identifies by a null req.method
* 2. if a header is started, then it indicates
* the end of the header.
*/
while (! httpHeaderIsStarted(&(actClient->httpHeader))) {
if (0 != len) {
httpHeaderParseRequestLine(&(actClient->httpHeader), line, len);
// TODO: do some error handling here
}
len = strlen(delim);
clientRemoveLine(actClient, delim, &len); // TODO: do some error handling here
len = strlen(delim);
line = clientGetLine(actClient, delim, &len);
}
while (NULL != line) {
if (NULL == actClient->httpHeader.req.method) {
}
}
}
if (!httpHeaderIsComplete(&(actClient->httpHeader))) {
actClient->bodyLenRemaining = httpHeaderGet(
&(actClient->readBuffer),
&(actClient->readPos),
&(actClient->httpHeader));
}
if (httpHeaderIsComplete(&(actClient->httpHeader))) {
size_t size = MIN(actClient->bodyLenRemaining, actClient->readPos);
unsigned int isLast = !(size - actClient->bodyLenRemaining);
enum XML_Status expatStat;
expatStat = XML_Parse(actClient->parser, actClient->readBuffer, size, isLast);
actClient->readPos -= size;
actClient->bodyLenRemaining -= size;
memmove(actClient->readBuffer, actClient->readBuffer + size, actClient->readPos);
memset(actClient->readBuffer + actClient->readPos, 0, size);
if (isLast && NULL == actClient->writeBuffer) {
actClient->writeBuffer = calloc(
strlen(actClient->httpHeader.req.httpVersion) +
strlen(RESPONSE) + 3,
sizeof(char));
sprintf(actClient->writeBuffer, "%s%s",
actClient->httpHeader.req.httpVersion,
RESPONSE);
freeHttpHeader(&(actClient->httpHeader));
XML_ParserFree(actClient->parser);
actClient->parser = NULL;
}
}
break;
}
}
}
/* handle writes */
for (i=3; i<=server->maxFd; i++) {
// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
tClient * actClient = &(server->clients)[i];
// TODO: the && is only symptom fix...need to find real bug.
if (FD_ISSET(i, &wfds) && NULL != actClient->writeBuffer) {
int writeSize = 0;
int toWrite = strlen(actClient->writeBuffer);
writeSize = write(actClient->socket, actClient->writeBuffer, toWrite);
if (0 < writeSize) {
if (writeSize == toWrite) {
free(actClient->writeBuffer);
actClient->writeBuffer = NULL;
clientClose(actClient);
FD_CLR(i, &(server->socks));
} else {
memmove(actClient->writeBuffer, actClient->writeBuffer + writeSize, toWrite - writeSize);
memset(actClient->writeBuffer + (toWrite - writeSize), 0, writeSize);
}
}
}
}
}
}

35
server/serverShutdown.c

@ -0,0 +1,35 @@
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/select.h> /* for select system call and related */
#include <sys/socket.h> /* for select system call and related */
#include <stdlib.h> /* for exit */
#include <string.h> /* for memset and stuff */
#include <unistd.h> /* for getopt */
#include <errno.h> /* for errno */
#include "../include/server.h"
#include "../include/monitor.h"
#include "../include/writeBuffer.h"
void
serverShutdown(tServer * server)
{
int i;
for (i=3; i<=server->maxFd; i++) {
if (FD_ISSET(i, &(server->socks))) {
if (i == server->servSock) {
shutdown(server->servSock, SHUT_RDWR);
close(server->servSock);
} else {
/* actual do nothing except closing the client */
clientClose(&((server->clients)[i]));
FD_CLR(i, &(server->socks));
}
}
}
if (NULL != server->wHandle) {
fclose(server->wHandle);
}
}

17
system/Makefile

@ -0,0 +1,17 @@
INCLUDE=include
VPATH=../$(INCLUDE)
OBJECTS=$(system_OBJ)
all: $(OBJECTS)
%.o: %.c
gcc $(CFLAGS) -c $< -o $@
logRotate.o signalHandling.o socket.o: monitor.h
serverRun.o: signalHandling.h httpRequest.h
handleCmdLine.o: appConfig.h
.PHONY: clean
clean:
-rm *.o

23
system/daemonize.c

@ -0,0 +1,23 @@
#include <stdio.h> /* for printf() and fprintf() */
#include <unistd.h> /* for getopt */
#include <stdlib.h>
void daemonize(void) {
pid_t pid;
if (0 > ((pid = fork()))) {
perror("deamoinze[fork]");
exit(EXIT_FAILURE);
} else if (0 != pid) {
exit(EXIT_SUCCESS);
}
/* make new child session leader */
setsid();
/* connect all standard streams to /dev/null */
freopen("/dev/null", "w", stderr);
freopen("/dev/null", "r", stdin);
freopen("/dev/null", "w", stdout);
}

70
system/handleCmdLine.c

@ -0,0 +1,70 @@
#include <unistd.h> /* for getopt */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../include/appConfig.h"
int
handleCmdLine(tAppConfig * config, int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "Dvp:l:n:b:")) != -1) {
switch (opt) {
case 'p':
/* port */
config->port = atoi(optarg);
break;
case 'l':
/* logPath */
strncpy(config->logPath, optarg, sizeof(config->logPath)-1);
break;
case 'n':
/* logNamePattern */
strncpy(config->namePat, optarg, sizeof(config->namePat)-1);
break;
case 'b':
/* maxPending (connection backlog) */
config->maxPending = atoi(optarg);
break;
case 'v':
/* verbose */
config->verbose = 1;
break;
case 'D':
/* verbose */
config->doDaemon = 1;
break;
default:
/* '?' */
fprintf(
stderr,
"Usage: %s [-p port] [-l logPath] [-n logNamePattern] [-c maxClient] [-b backlog] [-v] [-D]\n"
"Defaults:\n"
"\t%-20s: port this service will use [%d]\n"
"\t%-20s: path where the logfiles will be stored [%s/]\n"
"\t%-20s: patten used by strftime to create the log filename [%s]\n"
"\t%-20s: maximum connection backlog [%d]\n"
"\t%-20s: be more verbose in syslog [off]\n"
"\t%-20s: deamonize me\n",
argv[0],
"-p port", DEFAULTPORT,
"-l logPath", DEFAULTPATH,
"-n logNamePattern", LOGNAMEPATTERN,
"-b backlog", MAXPENDING,
"-v",
"-D");
exit(EXIT_FAILURE);
}
}
return 0;
}

83
system/logRotate.c

@ -0,0 +1,83 @@
#include <sys/select.h> /* for select system call and related */
#include <time.h>
#include <unistd.h> /* for fork and exec */
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h> /* fopen and stuff */
#include <stdlib.h> /* exit */
#include <string.h> /* strncpy, memcpy, etc. */
#include <syslog.h>
#include <errno.h>
#include "../include/monitor.h"
extern int verbose;
void logRotate(FILE ** handle, char * path, char * pattern) {
static char logName[1024] = "";
char strftimeName[128] = "";
char newLogName[1024] = "";
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
if (tmp == NULL) {
syslogMonitor(LOG_ERR, MON_INFO, "logrotate.localtime",
"can't get localtime for new logname. continue with old one");
return;
}
if (strftime(strftimeName, sizeof(strftimeName)-1, pattern, tmp) == 0) {
syslogMonitor(LOG_ERR, MON_INFO, "logrotate.strftime",
"strftime returned 0 for new logname. continue with old one");
return;
}
snprintf(newLogName, sizeof(newLogName)-1, "%s/%s", path, strftimeName);
if (0 != strncmp(logName, newLogName, sizeof(logName)-1)) {
if (0 != verbose) {
syslog(LOG_INFO, "actual logfile name: %s", logName);
syslog(LOG_INFO, "new logfile name: %s", newLogName);
}
if (NULL != *handle) {
fclose(*handle);
pid_t gzipPid = fork();
switch(gzipPid) {
pid_t tmpPid;
case 0:
// We don't care about finishing of child, so decouple it
// by using a second child that stop immediatly
tmpPid = fork();
if (0 == tmpPid) {
syslog(LOG_INFO, "gzip: %s", logName);
if (-1 == execl("/bin/gzip", "/bin/gzip", "-9", logName, (char *) 0)) {
syslogMonitor(LOG_ERR, MON_INFO, "logrotate.gzip",
"execl failed for gzip %s: %s", logName, strerror(errno));
}
}
exit(EXIT_SUCCESS);
case -1:
syslogMonitor(LOG_ERR, MON_INFO, "logrotate.fork",
"fork failed for gzip %s: %s", logName, strerror(errno));
break;
default:
wait(NULL);
break;
}
}
strncpy(logName, newLogName, sizeof(logName)-1);
*handle = fopen(logName, "w");
}
}

87
system/monitor.c

@ -0,0 +1,87 @@
#include <stdlib.h> /* for system() */
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h> /* for ellipse handling */
#include "../include/signalHandling.h"
#include "../include/monitor.h"
#define MONITORCMD "/usr/bin/monitor"
#define MONITORTYPE "test"
#define MONITORNAME "virtualitemlogreceiver"
const char severity[][10] = {
"info",
"warning",
"critical",
"failure"
};
int
monitor(
unsigned int sev,
const char * pattern,
const char * message
) {
char monCall[1024];
int ret;
snprintf(monCall, 1023,
"%s %s %s.%s.%s \"%s\"",
MONITORCMD,
severity[sev],
MONITORTYPE,
MONITORNAME,
pattern,
message);
ret = system(monCall);
if (WIFSIGNALED(ret)) {
switch (WTERMSIG(ret)) {
case SIGINT:
case SIGQUIT:
syslog(LOG_INFO, "interrupted in monitor call");
doShutdown=1;
}
}
if (-1 == ret || 0 != WEXITSTATUS(ret)) {
syslog(LOG_ERR, "call monitoring failed: %s", strerror(errno));
}
return ret;
}
/* this handles simple %d and %s replacements,
* complexer stuff must be prepared via snprintf
* the complete message should not extend 1024
* Bytes, else it will be truncated silently */
int
syslogMonitor(
unsigned int logLvl,
unsigned int sev,
const char * pattern,
const char * message,
...
) {
va_list args;
char buffer[1025];
int maxBuf = sizeof(buffer)/sizeof(buffer[0]);
memset(buffer, 0, maxBuf);
va_start(args, message);
vsnprintf(buffer, 1024, message, args);
va_end(args);
syslog(logLvl, "%s", buffer);
monitor(sev, pattern, buffer);
return 0;
}

26
system/signalHandling.c

@ -0,0 +1,26 @@
#include <signal.h> /* for signal() and signal names */
#include "../include/monitor.h"
volatile int doShutdown;
void terminate(int signum)
{
signal(signum, SIG_IGN);
syslogMonitor(LOG_INFO, MON_INFO, "signals",
"caugth deadly signal %d, service terminated", signum);
doShutdown = 1;
}
void init_signals(void)
{
signal(SIGTERM, terminate);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, terminate);
signal(SIGQUIT, terminate);
signal(SIGABRT, terminate);
signal(SIGALRM, SIG_IGN);
signal(SIGURG, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
}

75
system/socket.c

@ -0,0 +1,75 @@
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), bind(), and connect() */
#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <errno.h> /* for errno */
#include <syslog.h>
#include "../include/monitor.h"
extern int verbose;
int initServerSocket(in_port_t port, int backlog) {
int sock; /* socket descriptor for server */
struct sockaddr_in addr; /* Local address */
/* Create socket for incoming connections */
if (-1 == (sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
syslogMonitor(LOG_ERR, MON_INFO, "server.socket",
"error opening socket: %s - service terminated",
strerror(errno));
exit(EXIT_FAILURE);
}
/* Construct local address structure */
memset(&addr, 0, sizeof(addr)); /* Zero out structure */
addr.sin_family = AF_INET; /* Internet address family */
addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
addr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
if (-1 == bind(sock, (struct sockaddr *) &addr, sizeof(addr))) {
syslogMonitor(LOG_ERR, MON_INFO, "server.bind",
"error binding socket: %s - service terminated",
strerror(errno));
exit(EXIT_FAILURE);
}
/* Mark the socket so it will listen for incoming connections */
if (-1 == listen(sock, backlog)) {
syslogMonitor(LOG_ERR, MON_INFO, "server.listen",
"error binding socket: %s - service terminated",
strerror(errno));
exit(EXIT_FAILURE);
}
return sock;
}
int acceptConnection(int servSock, char remoteAddr[16]) {
int sock; /* Socket descriptor for client */
struct sockaddr_in addr; /* Client address */
unsigned int len; /* Length of client address data structure */
/* Set the size of the in-out parameter */
len = sizeof(addr);
/* Wait for a client to connect */
if (-1 == (sock = accept(servSock, (struct sockaddr *) &addr, &len))) {
syslogMonitor(LOG_ERR, MON_INFO, "server.accept",
"error acception connection: %s", strerror(errno));
} else {
strncpy (remoteAddr, inet_ntoa(addr.sin_addr), sizeof(remoteAddr)-1);
}
/* clntSock is connected to a client! */
if (0 != verbose) {
syslog(LOG_INFO, "handling client %s\n", inet_ntoa(addr.sin_addr));
}
return sock;
}

50
xmlrpc.c

@ -0,0 +1,50 @@
#include <string.h> /* for memset and stuff */
#include <syslog.h> /* for logging */
#include "include/server.h"
#include "include/monitor.h"
#include "include/signalHandling.h"
#include "include/appConfig.h"
#include "include/daemonize.h"
int verbose;
int main(int argc, char *argv[])
{
tServer server;
tAppConfig appConfig = {
0,
0,
MAXPENDING,
DEFAULTPORT,
DEFAULTPATH,
LOGNAMEPATTERN
};
memset(&server, 0, sizeof(server));
handleCmdLine(&appConfig, argc, argv);
verbose = appConfig.verbose;
/* decouple procss from controlling shell and make it session leader */
if (appConfig.doDaemon) {
daemonize();
}
init_signals();
openlog(argv[0], LOG_PID, LOG_USER);
syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");
serverInit(
&server,
appConfig.port,
appConfig.maxPending,
appConfig.logPath,
appConfig.namePat);
serverRun(&server);
serverShutdown(&server);
return 0;
}
Loading…
Cancel
Save