commit
36666a3ae9
32 changed files with 1687 additions and 0 deletions
-
57Makefile
-
24TODO
-
29include/appConfig.h
-
40include/client.h
-
6include/daemonize.h
-
50include/httpRequest.h
-
6include/logRotate.h
-
14include/monitor.h
-
51include/my.patch
-
29include/server.h
-
10include/signalHandling.h
-
9include/socket.h
-
8include/writeBuffer.h
-
17reader/Makefile
-
15reader/commonReader/Makefile
-
39reader/commonReader/clientClose.c
-
202reader/commonReader/clientRead.c
-
48reader/commonReader/writeBuffer.c
-
15reader/httpReader/Makefile
-
255reader/httpReader/httpRequest.c
-
19server/Makefile
-
40server/serverInit.c
-
238server/serverRun.c
-
35server/serverShutdown.c
-
17system/Makefile
-
23system/daemonize.c
-
70system/handleCmdLine.c
-
83system/logRotate.c
-
87system/monitor.c
-
26system/signalHandling.c
-
75system/socket.c
-
50xmlrpc.c
@ -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 |
||||
@ -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... |
||||
@ -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__ |
||||
@ -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__ |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef __DAEMONIZE_H__ |
||||
|
#define __DAEMONIZE_H__ |
||||
|
|
||||
|
void daemonize(void); |
||||
|
|
||||
|
#endif // __DAEMONIZE_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__ |
||||
@ -0,0 +1,6 @@ |
|||||
|
#ifndef __LOG_ROTATE_H__ |
||||
|
#define __LOG_ROTATE_H__ |
||||
|
|
||||
|
void logRotate(FILE ** handle, char * logPath, char * logNamePattern); |
||||
|
|
||||
|
#endif /* __LOG_ROTATE_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__ */ |
||||
@ -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__ |
||||
@ -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__ |
||||
@ -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__ |
||||
|
|
||||
@ -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__ */ |
||||
@ -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__ |
||||
@ -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 |
||||
@ -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 |
||||
@ -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); |
||||
|
} |
||||
@ -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) |
||||
|
{ |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
@ -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 |
||||
@ -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)); |
||||
|
} |
||||
@ -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 |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
@ -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 |
||||
@ -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); |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
@ -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"); |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
@ -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); |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue