From 36666a3ae97d7425f1864d27436a95d274f9d40e Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Thu, 30 Sep 2010 13:42:24 +0200 Subject: [PATCH] initial project revision --- Makefile | 57 +++++++ TODO | 24 +++ include/appConfig.h | 29 ++++ include/client.h | 40 +++++ include/daemonize.h | 6 + include/httpRequest.h | 50 ++++++ include/logRotate.h | 6 + include/monitor.h | 14 ++ include/my.patch | 51 ++++++ include/server.h | 29 ++++ include/signalHandling.h | 10 ++ include/socket.h | 9 ++ include/writeBuffer.h | 8 + reader/Makefile | 17 ++ reader/commonReader/Makefile | 15 ++ reader/commonReader/clientClose.c | 39 +++++ reader/commonReader/clientRead.c | 202 +++++++++++++++++++++++ reader/commonReader/writeBuffer.c | 48 ++++++ reader/httpReader/Makefile | 15 ++ reader/httpReader/httpRequest.c | 255 ++++++++++++++++++++++++++++++ server/Makefile | 19 +++ server/serverInit.c | 40 +++++ server/serverRun.c | 238 ++++++++++++++++++++++++++++ server/serverShutdown.c | 35 ++++ system/Makefile | 17 ++ system/daemonize.c | 23 +++ system/handleCmdLine.c | 70 ++++++++ system/logRotate.c | 83 ++++++++++ system/monitor.c | 87 ++++++++++ system/signalHandling.c | 26 +++ system/socket.c | 75 +++++++++ xmlrpc.c | 50 ++++++ 32 files changed, 1687 insertions(+) create mode 100644 Makefile create mode 100644 TODO create mode 100644 include/appConfig.h create mode 100644 include/client.h create mode 100644 include/daemonize.h create mode 100644 include/httpRequest.h create mode 100644 include/logRotate.h create mode 100644 include/monitor.h create mode 100644 include/my.patch create mode 100644 include/server.h create mode 100644 include/signalHandling.h create mode 100644 include/socket.h create mode 100644 include/writeBuffer.h create mode 100644 reader/Makefile create mode 100644 reader/commonReader/Makefile create mode 100644 reader/commonReader/clientClose.c create mode 100644 reader/commonReader/clientRead.c create mode 100644 reader/commonReader/writeBuffer.c create mode 100644 reader/httpReader/Makefile create mode 100644 reader/httpReader/httpRequest.c create mode 100644 server/Makefile create mode 100644 server/serverInit.c create mode 100644 server/serverRun.c create mode 100644 server/serverShutdown.c create mode 100644 system/Makefile create mode 100644 system/daemonize.c create mode 100644 system/handleCmdLine.c create mode 100644 system/logRotate.c create mode 100644 system/monitor.c create mode 100644 system/signalHandling.c create mode 100644 system/socket.c create mode 100644 xmlrpc.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fa62041 --- /dev/null +++ b/Makefile @@ -0,0 +1,57 @@ +PROJECT = xmlrpc +INCLUDE = include +CFLAGS = -Wall -ggdb + +### +# PROJECT CONFIG +# +SUBDIRS = system server reader + +system_OBJ = daemonize.o handleCmdLine.o logRotate.o monitor.o \ + signalHandling.o socket.o +server_OBJ = serverInit.o serverRun.o serverShutdown.o +commonReader_OBJ = clientClose.o clientRead.o writeBuffer.o +httpReader_OBJ = httpRequest.o + +VPATH=$(INCLUDE) + +export CFLAGS INCLUDE \ + system_OBJ server_OBJ commonReader_OBJ httpReader_OBJ + +OBJECTS=$(PROJECT).o \ + $(addprefix system/,$(system_OBJ)) \ + $(addprefix server/,$(server_OBJ)) \ + $(addprefix reader/commonReader/,$(commonReader_OBJ)) \ + $(addprefix reader/httpReader/,$(httpReader_OBJ)) + +### +# EXPLICIT RULES +# +$(PROJECT): $(PROJECT).o subdirs + gcc $(CFLAGS) -o $(PROJECT) -lexpat $(OBJECTS) + +$(PROJECT).o: server.h monitor.h signalHandling.h daemonize.h appConfig.h + +### +# IMPLICIT RULES +# +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +### +# PHONYS +# +.PHONY: clean subdirs subdirs_clean $(SUBDIRS) + +subdirs: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +subdirs_clean: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean; \ + done + +clean: subdirs_clean + -rm *.o diff --git a/TODO b/TODO new file mode 100644 index 0000000..8c3de9f --- /dev/null +++ b/TODO @@ -0,0 +1,24 @@ +integrate libicu for unicode support + +integrate the http parsing process into the stream reading process at all + that is...a http parser is nothing else than a specialized stream reader + +decouple all parts so that they are reusable at all...especially don't expect + a structure from one subcomponent as prereuqisite for another. + +read trailing newlines from a request and ignore them instead of heading. + Heading newlines as long as other trailing chars than newlines should throw + an error as they are not specified within protocol. + Throw in this case is: write an HTTP Error code back on the connection and + close it as we don't expect any more sane data from it. + +implement XMLRPC to C and vice versa argument mapping in some form... + in this process implement the XML parsing, i already use libexpat but only + as a testcase + +start multiple workers as paralell connectionts exceed a given limit. + This can be done if everything else works fine. + +make a lib and example application from most of this stuff to make it useable + from other projects. This again can be done later as long as i develope + with this goal in mind... diff --git a/include/appConfig.h b/include/appConfig.h new file mode 100644 index 0000000..9945cc2 --- /dev/null +++ b/include/appConfig.h @@ -0,0 +1,29 @@ +#ifndef __APP_CONFIG_H__ +#define __APP_CONFIG_H__ + +#define MAXPENDING 10 /* Maximum outstanding connection requests */ +#define MAXCLIENTS 1000 /* Maximum connection handled in paralell */ +#define READBUFSIZE 2048 /* Size of receive buffer */ +#define DEFAULTPORT 8801 /* default port for service */ +#define DEFAULTPATH "logfiles" +#define LOGNAMEPATTERN "log-%Y-%m-%d_%Hh" + +#undef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +#undef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) + +typedef struct { + unsigned char verbose; + unsigned char doDaemon; + unsigned int maxPending; + unsigned int port; + char logPath[513]; + char namePat[513]; +} tAppConfig; + +int +handleCmdLine(tAppConfig * config, int argc, char *argv[]); + +#endif // __APP_CONFIG_H__ diff --git a/include/client.h b/include/client.h new file mode 100644 index 0000000..69ba90a --- /dev/null +++ b/include/client.h @@ -0,0 +1,40 @@ +#ifndef __CLIENT_H__ +#define __CLIENT_H__ + +#include /* for FILE */ + +#include + +#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__ diff --git a/include/daemonize.h b/include/daemonize.h new file mode 100644 index 0000000..209aed3 --- /dev/null +++ b/include/daemonize.h @@ -0,0 +1,6 @@ +#ifndef __DAEMONIZE_H__ +#define __DAEMONIZE_H__ + +void daemonize(void); + +#endif // __DAEMONIZE_H__ diff --git a/include/httpRequest.h b/include/httpRequest.h new file mode 100644 index 0000000..23bf5b9 --- /dev/null +++ b/include/httpRequest.h @@ -0,0 +1,50 @@ +#ifndef __HTTP_REQUEST_H__ +#define __HTTP_REQUEST_H__ + +#define HTTP_REQ_OPTIONS 0 +#define HTTP_REQ_GET 1 +#define HTTP_REQ_HEAD 2 +#define HTTP_REQ_POST 3 +#define HTTP_REQ_PUT 4 +#define HTTP_REQ_DELETE 5 +#define HTTP_REQ_TRACE 6 +#define HTTP_REQ_CONNECT 7 + +extern char httpRequest[8][8]; + + +typedef struct { + char * method; + char * requestUri; + char * httpVersion; +} tRequestLine; + +typedef struct { + char * key; + char * value; +} tHttpHeaderLine; + +typedef struct { + tRequestLine req; + tHttpHeaderLine * headers; + unsigned int headersCount; + + unsigned char bodyLength; +} tHttpHeader; + +typedef struct { + tHttpHeader header; + unsigned int length; + char * body; +} tHttpRequest; + + +int getHttpRequest(char **, unsigned int *, tHttpRequest *); +void freeHttpRequest(tHttpRequest *); +void freeHttpHeader(tHttpHeader *); +unsigned char httpHeaderIsStarted(tHttpHeader *); +int httpHeaderIsComplete(tHttpHeader *); +int httpHeaderGet(char **, unsigned int *, tHttpHeader *); +void httpHeaderParseRequestLine(tHttpHeader *, const char *, unsigned int); + +#endif // __HTTP_REQUEST_H__ diff --git a/include/logRotate.h b/include/logRotate.h new file mode 100644 index 0000000..7318f96 --- /dev/null +++ b/include/logRotate.h @@ -0,0 +1,6 @@ +#ifndef __LOG_ROTATE_H__ +#define __LOG_ROTATE_H__ + +void logRotate(FILE ** handle, char * logPath, char * logNamePattern); + +#endif /* __LOG_ROTATE_H__ */ diff --git a/include/monitor.h b/include/monitor.h new file mode 100644 index 0000000..35c6a40 --- /dev/null +++ b/include/monitor.h @@ -0,0 +1,14 @@ +#ifndef __MONITOR_H__ +#define __MONITOR_H__ + +#include /* 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__ */ diff --git a/include/my.patch b/include/my.patch new file mode 100644 index 0000000..b9399a2 --- /dev/null +++ b/include/my.patch @@ -0,0 +1,51 @@ +--- ../../xmlrpc/include/client.h 2010-08-12 20:15:42.000000000 +0200 ++++ ./include/virtualitemreceiver/client.h 2010-09-13 20:51:51.284184703 +0200 +@@ -3,31 +3,26 @@ + + #include /* for FILE */ + +-#include ++#include ++#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__ diff --git a/include/server.h b/include/server.h new file mode 100644 index 0000000..90b5908 --- /dev/null +++ b/include/server.h @@ -0,0 +1,29 @@ +#ifndef __SERVER_H__ +#define __SERVER_H__ + +#include /* for printf() and fprintf() */ +#include /* 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__ diff --git a/include/signalHandling.h b/include/signalHandling.h new file mode 100644 index 0000000..0bd25b0 --- /dev/null +++ b/include/signalHandling.h @@ -0,0 +1,10 @@ +#ifndef __SIGNAL_HANDLING_H__ +#define __SIGNAL_HANDLING_H__ + +extern volatile int doShutdown; + +void terminate(int signum); +void init_signals(void); + +#endif // __SIGNAL_HANDLING_H__ + diff --git a/include/socket.h b/include/socket.h new file mode 100644 index 0000000..36a070a --- /dev/null +++ b/include/socket.h @@ -0,0 +1,9 @@ +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#include /* for in_port_t */ + +int initServerSocket(in_port_t port, int backlog); +int acceptConnection(int servSock, char remoteAddr[16]); + +#endif /* __SOCKET_H__ */ diff --git a/include/writeBuffer.h b/include/writeBuffer.h new file mode 100644 index 0000000..74f2f0f --- /dev/null +++ b/include/writeBuffer.h @@ -0,0 +1,8 @@ +#ifndef __WRITE_BUFFER_H__ +#define __WRITE_BUFFER_H__ + +#include /* for FILE */ + +int writeBuffer(char ** buffer, unsigned int * readPos, FILE * wHandle); + +#endif // __WRITE_BUFFER_H__ diff --git a/reader/Makefile b/reader/Makefile new file mode 100644 index 0000000..f7dfac2 --- /dev/null +++ b/reader/Makefile @@ -0,0 +1,17 @@ +SUBDIRS=commonReader httpReader + +.PHONY: all clean subdirs subdirs_clean $(SUBDIRS) + +all: $(SUBDIRS) + +subdirs: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ + +subdirs_clean: + for dir in $(SUBDIRS); do \ + $(MAKE) -C $$dir clean; \ + done + +clean: subdirs_clean diff --git a/reader/commonReader/Makefile b/reader/commonReader/Makefile new file mode 100644 index 0000000..ba94eb4 --- /dev/null +++ b/reader/commonReader/Makefile @@ -0,0 +1,15 @@ +INCLUDE=include +VPATH=../../$(INCLUDE) + +OBJECTS=$(commonReader_OBJ) + +all: $(OBJECTS) + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +%.o: client.h + +.PHONY: clean +clean: + -rm *.o diff --git a/reader/commonReader/clientClose.c b/reader/commonReader/clientClose.c new file mode 100644 index 0000000..ddf7b58 --- /dev/null +++ b/reader/commonReader/clientClose.c @@ -0,0 +1,39 @@ +#include /* for free() */ +#include /* for close() */ +#include /* for shutdown() */ +#include /* for memset and stuff */ + +#include + +#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); +} diff --git a/reader/commonReader/clientRead.c b/reader/commonReader/clientRead.c new file mode 100644 index 0000000..4705e4f --- /dev/null +++ b/reader/commonReader/clientRead.c @@ -0,0 +1,202 @@ +#include /* for getopt */ +#include /* for exit */ +#include /* for memset and stuff */ +#include /* 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) +{ +} diff --git a/reader/commonReader/writeBuffer.c b/reader/commonReader/writeBuffer.c new file mode 100644 index 0000000..c18e39d --- /dev/null +++ b/reader/commonReader/writeBuffer.c @@ -0,0 +1,48 @@ +#include /* for ferror() */ +#include /* 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; +} diff --git a/reader/httpReader/Makefile b/reader/httpReader/Makefile new file mode 100644 index 0000000..c9324e5 --- /dev/null +++ b/reader/httpReader/Makefile @@ -0,0 +1,15 @@ +INCLUDE=include +VPATH=../../$(INCLUDE) + +OBJECTS=$(httpReader_OBJ) + +all: $(OBJECTS) + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +%.o: httpRequest.h + +.PHONY: clean +clean: + -rm *.o diff --git a/reader/httpReader/httpRequest.c b/reader/httpReader/httpRequest.c new file mode 100644 index 0000000..7bffbc9 --- /dev/null +++ b/reader/httpReader/httpRequest.c @@ -0,0 +1,255 @@ +#include +#include +#include +#include + +#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; iheadersCount; 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; iheader.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)); +} diff --git a/server/Makefile b/server/Makefile new file mode 100644 index 0000000..ed8b696 --- /dev/null +++ b/server/Makefile @@ -0,0 +1,19 @@ +INCLUDE=include +VPATH=../$(INCLUDE) + +OBJECTS=$(server_OBJ) + +all: $(OBJECTS) + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +server.h: client.h +server%.o: server.h monitor.h +serverRun.o serverInit.o: socket.h logRotate.h +serverRun.o serverShutdown.o: writeBuffer.h +serverRun.o: signalHandling.h httpRequest.h + +.PHONY: clean +clean: + -rm *.o diff --git a/server/serverInit.c b/server/serverInit.c new file mode 100644 index 0000000..35ec117 --- /dev/null +++ b/server/serverInit.c @@ -0,0 +1,40 @@ +#include /* for select system call and related */ +#include /* for memset and stuff */ +#include /* 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); + } + } +} diff --git a/server/serverRun.c b/server/serverRun.c new file mode 100644 index 0000000..a3f69ec --- /dev/null +++ b/server/serverRun.c @@ -0,0 +1,238 @@ +#include /* for select system call and related */ +#include /* for memset and stuff */ +#include /* for exit */ +#include /* for errno */ +#include /* for write */ + +#include + +#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); + } + } + } + } + } +} diff --git a/server/serverShutdown.c b/server/serverShutdown.c new file mode 100644 index 0000000..f1e3bbf --- /dev/null +++ b/server/serverShutdown.c @@ -0,0 +1,35 @@ +#include /* for printf() and fprintf() */ +#include /* for select system call and related */ +#include /* for select system call and related */ +#include /* for exit */ +#include /* for memset and stuff */ +#include /* for getopt */ +#include /* 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); + } +} diff --git a/system/Makefile b/system/Makefile new file mode 100644 index 0000000..621e410 --- /dev/null +++ b/system/Makefile @@ -0,0 +1,17 @@ +INCLUDE=include +VPATH=../$(INCLUDE) + +OBJECTS=$(system_OBJ) + +all: $(OBJECTS) + +%.o: %.c + gcc $(CFLAGS) -c $< -o $@ + +logRotate.o signalHandling.o socket.o: monitor.h +serverRun.o: signalHandling.h httpRequest.h +handleCmdLine.o: appConfig.h + +.PHONY: clean +clean: + -rm *.o diff --git a/system/daemonize.c b/system/daemonize.c new file mode 100644 index 0000000..6776da1 --- /dev/null +++ b/system/daemonize.c @@ -0,0 +1,23 @@ +#include /* for printf() and fprintf() */ +#include /* for getopt */ +#include + + +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); +} diff --git a/system/handleCmdLine.c b/system/handleCmdLine.c new file mode 100644 index 0000000..a972e99 --- /dev/null +++ b/system/handleCmdLine.c @@ -0,0 +1,70 @@ +#include /* for getopt */ +#include +#include +#include + +#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; +} diff --git a/system/logRotate.c b/system/logRotate.c new file mode 100644 index 0000000..48c2461 --- /dev/null +++ b/system/logRotate.c @@ -0,0 +1,83 @@ +#include /* for select system call and related */ +#include +#include /* for fork and exec */ +#include +#include +#include /* fopen and stuff */ +#include /* exit */ +#include /* strncpy, memcpy, etc. */ +#include +#include + +#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"); + } +} diff --git a/system/monitor.c b/system/monitor.c new file mode 100644 index 0000000..51e4995 --- /dev/null +++ b/system/monitor.c @@ -0,0 +1,87 @@ +#include /* for system() */ +#include +#include +#include +#include +#include +#include /* 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; +} diff --git a/system/signalHandling.c b/system/signalHandling.c new file mode 100644 index 0000000..7e2d2ee --- /dev/null +++ b/system/signalHandling.c @@ -0,0 +1,26 @@ +#include /* 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); +} diff --git a/system/socket.c b/system/socket.c new file mode 100644 index 0000000..fba5160 --- /dev/null +++ b/system/socket.c @@ -0,0 +1,75 @@ +#include /* for printf() and fprintf() */ +#include /* for socket(), bind(), and connect() */ +#include /* for sockaddr_in and inet_ntoa() */ +#include /* for atoi() and exit() */ +#include /* for memset() */ +#include /* for close() */ +#include /* for errno */ +#include + +#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; +} diff --git a/xmlrpc.c b/xmlrpc.c new file mode 100644 index 0000000..ee0c698 --- /dev/null +++ b/xmlrpc.c @@ -0,0 +1,50 @@ +#include /* for memset and stuff */ +#include /* 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; +}