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