Commit 36666a3ae97d7425f1864d27436a95d274f9d40e

Authored by Georg Hopp
0 parents

initial project revision

  1 +PROJECT = xmlrpc
  2 +INCLUDE = include
  3 +CFLAGS = -Wall -ggdb
  4 +
  5 +###
  6 +# PROJECT CONFIG
  7 +#
  8 +SUBDIRS = system server reader
  9 +
  10 +system_OBJ = daemonize.o handleCmdLine.o logRotate.o monitor.o \
  11 + signalHandling.o socket.o
  12 +server_OBJ = serverInit.o serverRun.o serverShutdown.o
  13 +commonReader_OBJ = clientClose.o clientRead.o writeBuffer.o
  14 +httpReader_OBJ = httpRequest.o
  15 +
  16 +VPATH=$(INCLUDE)
  17 +
  18 +export CFLAGS INCLUDE \
  19 + system_OBJ server_OBJ commonReader_OBJ httpReader_OBJ
  20 +
  21 +OBJECTS=$(PROJECT).o \
  22 + $(addprefix system/,$(system_OBJ)) \
  23 + $(addprefix server/,$(server_OBJ)) \
  24 + $(addprefix reader/commonReader/,$(commonReader_OBJ)) \
  25 + $(addprefix reader/httpReader/,$(httpReader_OBJ))
  26 +
  27 +###
  28 +# EXPLICIT RULES
  29 +#
  30 +$(PROJECT): $(PROJECT).o subdirs
  31 + gcc $(CFLAGS) -o $(PROJECT) -lexpat $(OBJECTS)
  32 +
  33 +$(PROJECT).o: server.h monitor.h signalHandling.h daemonize.h appConfig.h
  34 +
  35 +###
  36 +# IMPLICIT RULES
  37 +#
  38 +%.o: %.c
  39 + gcc $(CFLAGS) -c $< -o $@
  40 +
  41 +###
  42 +# PHONYS
  43 +#
  44 +.PHONY: clean subdirs subdirs_clean $(SUBDIRS)
  45 +
  46 +subdirs: $(SUBDIRS)
  47 +
  48 +$(SUBDIRS):
  49 + $(MAKE) -C $@
  50 +
  51 +subdirs_clean:
  52 + for dir in $(SUBDIRS); do \
  53 + $(MAKE) -C $$dir clean; \
  54 + done
  55 +
  56 +clean: subdirs_clean
  57 + -rm *.o
  1 +integrate libicu for unicode support
  2 +
  3 +integrate the http parsing process into the stream reading process at all
  4 + that is...a http parser is nothing else than a specialized stream reader
  5 +
  6 +decouple all parts so that they are reusable at all...especially don't expect
  7 + a structure from one subcomponent as prereuqisite for another.
  8 +
  9 +read trailing newlines from a request and ignore them instead of heading.
  10 + Heading newlines as long as other trailing chars than newlines should throw
  11 + an error as they are not specified within protocol.
  12 + Throw in this case is: write an HTTP Error code back on the connection and
  13 + close it as we don't expect any more sane data from it.
  14 +
  15 +implement XMLRPC to C and vice versa argument mapping in some form...
  16 + in this process implement the XML parsing, i already use libexpat but only
  17 + as a testcase
  18 +
  19 +start multiple workers as paralell connectionts exceed a given limit.
  20 + This can be done if everything else works fine.
  21 +
  22 +make a lib and example application from most of this stuff to make it useable
  23 + from other projects. This again can be done later as long as i develope
  24 + with this goal in mind...
  1 +#ifndef __APP_CONFIG_H__
  2 +#define __APP_CONFIG_H__
  3 +
  4 +#define MAXPENDING 10 /* Maximum outstanding connection requests */
  5 +#define MAXCLIENTS 1000 /* Maximum connection handled in paralell */
  6 +#define READBUFSIZE 2048 /* Size of receive buffer */
  7 +#define DEFAULTPORT 8801 /* default port for service */
  8 +#define DEFAULTPATH "logfiles"
  9 +#define LOGNAMEPATTERN "log-%Y-%m-%d_%Hh"
  10 +
  11 +#undef MAX
  12 +#define MAX(x,y) ((x) > (y) ? (x) : (y))
  13 +
  14 +#undef MIN
  15 +#define MIN(x,y) ((x) < (y) ? (x) : (y))
  16 +
  17 +typedef struct {
  18 + unsigned char verbose;
  19 + unsigned char doDaemon;
  20 + unsigned int maxPending;
  21 + unsigned int port;
  22 + char logPath[513];
  23 + char namePat[513];
  24 +} tAppConfig;
  25 +
  26 +int
  27 +handleCmdLine(tAppConfig * config, int argc, char *argv[]);
  28 +
  29 +#endif // __APP_CONFIG_H__
  1 +#ifndef __CLIENT_H__
  2 +#define __CLIENT_H__
  3 +
  4 +#include <stdio.h> /* for FILE */
  5 +
  6 +#include <expat.h>
  7 +
  8 +#include "httpRequest.h"
  9 +
  10 +#define READBUFSIZE 2048 /* Size of receive readBuffer */
  11 +#define CLIENTMULTMAX 512U /* 1MB maximum size the readbuffer may grow */
  12 +
  13 +#define READ_ERR_LONGLINE -2
  14 +#define READ_ERR_MEMORY -3
  15 +
  16 +extern int verbose;
  17 +
  18 +typedef struct {
  19 + int socket;
  20 + char * readBuffer;
  21 + char * writeBuffer;
  22 + unsigned int readPos;
  23 + unsigned int writePos;
  24 + unsigned int readBufMult;
  25 + char remoteAddr[16];
  26 +
  27 + tHttpHeader httpHeader;
  28 + unsigned int bodyLenRemaining;
  29 +
  30 + XML_Parser parser;
  31 +} tClient;
  32 +
  33 +
  34 +void clientClose(tClient * client);
  35 +int clientRead(tClient * client);
  36 +int clientWrite(tClient * client);
  37 +char * clientGetLine(tClient *, const char *, unsigned int *);
  38 +char * clientRemoveLine(tClient *, const char *, unsigned int *);
  39 +
  40 +#endif // __CLIENT_H__
  1 +#ifndef __DAEMONIZE_H__
  2 +#define __DAEMONIZE_H__
  3 +
  4 +void daemonize(void);
  5 +
  6 +#endif // __DAEMONIZE_H__
  1 +#ifndef __HTTP_REQUEST_H__
  2 +#define __HTTP_REQUEST_H__
  3 +
  4 +#define HTTP_REQ_OPTIONS 0
  5 +#define HTTP_REQ_GET 1
  6 +#define HTTP_REQ_HEAD 2
  7 +#define HTTP_REQ_POST 3
  8 +#define HTTP_REQ_PUT 4
  9 +#define HTTP_REQ_DELETE 5
  10 +#define HTTP_REQ_TRACE 6
  11 +#define HTTP_REQ_CONNECT 7
  12 +
  13 +extern char httpRequest[8][8];
  14 +
  15 +
  16 +typedef struct {
  17 + char * method;
  18 + char * requestUri;
  19 + char * httpVersion;
  20 +} tRequestLine;
  21 +
  22 +typedef struct {
  23 + char * key;
  24 + char * value;
  25 +} tHttpHeaderLine;
  26 +
  27 +typedef struct {
  28 + tRequestLine req;
  29 + tHttpHeaderLine * headers;
  30 + unsigned int headersCount;
  31 +
  32 + unsigned char bodyLength;
  33 +} tHttpHeader;
  34 +
  35 +typedef struct {
  36 + tHttpHeader header;
  37 + unsigned int length;
  38 + char * body;
  39 +} tHttpRequest;
  40 +
  41 +
  42 +int getHttpRequest(char **, unsigned int *, tHttpRequest *);
  43 +void freeHttpRequest(tHttpRequest *);
  44 +void freeHttpHeader(tHttpHeader *);
  45 +unsigned char httpHeaderIsStarted(tHttpHeader *);
  46 +int httpHeaderIsComplete(tHttpHeader *);
  47 +int httpHeaderGet(char **, unsigned int *, tHttpHeader *);
  48 +void httpHeaderParseRequestLine(tHttpHeader *, const char *, unsigned int);
  49 +
  50 +#endif // __HTTP_REQUEST_H__
  1 +#ifndef __LOG_ROTATE_H__
  2 +#define __LOG_ROTATE_H__
  3 +
  4 +void logRotate(FILE ** handle, char * logPath, char * logNamePattern);
  5 +
  6 +#endif /* __LOG_ROTATE_H__ */
  1 +#ifndef __MONITOR_H__
  2 +#define __MONITOR_H__
  3 +
  4 +#include <syslog.h> /* for logging */
  5 +
  6 +#define MON_INFO 0
  7 +#define MON_WARNING 1
  8 +#define MON_CRITICAL 2
  9 +#define MON_FAILURE 3
  10 +
  11 +int monitor(unsigned int sev, const char * pattern, const char * message);
  12 +int syslogMonitor (unsigned int logLvl, unsigned int sev, const char *pattern, const char * message, ...) __attribute__ ((format (printf, 4, 5)));
  13 +
  14 +#endif /* __MONITOR_H__ */
  1 +--- ../../xmlrpc/include/client.h 2010-08-12 20:15:42.000000000 +0200
  2 ++++ ./include/virtualitemreceiver/client.h 2010-09-13 20:51:51.284184703 +0200
  3 +@@ -3,31 +3,26 @@
  4 +
  5 + #include <stdio.h> /* for FILE */
  6 +
  7 +-#include <expat.h>
  8 ++#include <expat.h>
  9 ++#include "httpRequest.h"
  10 ++
  11 ++#define READBUFSIZE 2048 /* Size of receive buffer */
  12 ++#define CLIENTMULTMAX 512U /* 1MB maximum size the readbuffer may grow */
  13 +
  14 +-#include "httpRequest.h"
  15 ++#define WRITE_ERR_IO -1
  16 ++#define WRITE_ERR_NOPRINT -2
  17 +
  18 +-#define READBUFSIZE 2048 /* Size of receive readBuffer */
  19 +-
  20 +-extern int verbose;
  21 ++#define READ_ERR_LONGLINE -2
  22 +
  23 + typedef struct {
  24 + int socket;
  25 +- char * readBuffer;
  26 +- char * writeBuffer;
  27 ++ char * readBuffer;
  28 ++ char * writeBuffer;
  29 + unsigned int readPos;
  30 +- unsigned int writePos;
  31 ++ unsigned int writePos;
  32 ++ unsigned int readBufMult;
  33 ++ unsigned int writeBufMult;
  34 + char remoteAddr[16];
  35 +
  36 + tHttpHeader httpHeader;
  37 + unsigned int bodyLenRemaining;
  38 +
  39 + XML_Parser parser;
  40 + } tClient;
  41 +
  42 +
  43 +-void clientClose(tClient * client);
  44 +-int clientRead(tClient * client);
  45 +-int clientWrite(tClient * client);
  46 ++void clientClose(tClient *);
  47 ++int clientRead(tClient *);
  48 ++int writeRemaining(tClient *);
  49 ++int writeBuffer(tClient *);
  50 +
  51 + #endif // __CLIENT_H__
  1 +#ifndef __SERVER_H__
  2 +#define __SERVER_H__
  3 +
  4 +#include <stdio.h> /* for printf() and fprintf() */
  5 +#include <sys/select.h> /* for select system call and related */
  6 +
  7 +#include "client.h"
  8 +
  9 +typedef struct {
  10 + int servSock;
  11 + tClient clients[FD_SETSIZE];
  12 + unsigned int maxFd;
  13 + fd_set socks;
  14 + char logPath[512];
  15 + char namePat[512];
  16 + FILE * wHandle;
  17 +} tServer;
  18 +
  19 +
  20 +void serverShutdown(tServer * server);
  21 +void serverInit(
  22 + tServer * server,
  23 + unsigned int port,
  24 + unsigned int pending,
  25 + const char * logPath,
  26 + const char * namePat);
  27 +void serverRun(tServer * server);
  28 +
  29 +#endif // __SERVER_H__
  1 +#ifndef __SIGNAL_HANDLING_H__
  2 +#define __SIGNAL_HANDLING_H__
  3 +
  4 +extern volatile int doShutdown;
  5 +
  6 +void terminate(int signum);
  7 +void init_signals(void);
  8 +
  9 +#endif // __SIGNAL_HANDLING_H__
  10 +
  1 +#ifndef __SOCKET_H__
  2 +#define __SOCKET_H__
  3 +
  4 +#include <arpa/inet.h> /* for in_port_t */
  5 +
  6 +int initServerSocket(in_port_t port, int backlog);
  7 +int acceptConnection(int servSock, char remoteAddr[16]);
  8 +
  9 +#endif /* __SOCKET_H__ */
  1 +#ifndef __WRITE_BUFFER_H__
  2 +#define __WRITE_BUFFER_H__
  3 +
  4 +#include <stdio.h> /* for FILE */
  5 +
  6 +int writeBuffer(char ** buffer, unsigned int * readPos, FILE * wHandle);
  7 +
  8 +#endif // __WRITE_BUFFER_H__
  1 +SUBDIRS=commonReader httpReader
  2 +
  3 +.PHONY: all clean subdirs subdirs_clean $(SUBDIRS)
  4 +
  5 +all: $(SUBDIRS)
  6 +
  7 +subdirs: $(SUBDIRS)
  8 +
  9 +$(SUBDIRS):
  10 + $(MAKE) -C $@
  11 +
  12 +subdirs_clean:
  13 + for dir in $(SUBDIRS); do \
  14 + $(MAKE) -C $$dir clean; \
  15 + done
  16 +
  17 +clean: subdirs_clean
  1 +INCLUDE=include
  2 +VPATH=../../$(INCLUDE)
  3 +
  4 +OBJECTS=$(commonReader_OBJ)
  5 +
  6 +all: $(OBJECTS)
  7 +
  8 +%.o: %.c
  9 + gcc $(CFLAGS) -c $< -o $@
  10 +
  11 +%.o: client.h
  12 +
  13 +.PHONY: clean
  14 +clean:
  15 + -rm *.o
  1 +#include <stdlib.h> /* for free() */
  2 +#include <unistd.h> /* for close() */
  3 +#include <sys/socket.h> /* for shutdown() */
  4 +#include <string.h> /* for memset and stuff */
  5 +
  6 +#include <expat.h>
  7 +
  8 +#include "../../include/client.h"
  9 +#include "../../include/monitor.h"
  10 +#include "../../include/httpRequest.h"
  11 +
  12 +void clientClose(tClient * client)
  13 +{
  14 + if (0 != verbose) {
  15 + syslog(LOG_INFO, "closing socket for %s", client->remoteAddr);
  16 + }
  17 +
  18 + /* close socket an remove from fd_set */
  19 + shutdown(client->socket, SHUT_RDWR);
  20 + close(client->socket);
  21 +
  22 + /* free readBuffer */
  23 + if (NULL != client->readBuffer) {
  24 + free(client->readBuffer);
  25 + client->readBuffer = NULL;
  26 + }
  27 + if (NULL != client->writeBuffer) {
  28 + free(client->writeBuffer);
  29 + client->writeBuffer = NULL;
  30 + }
  31 + client->readPos = 0;
  32 + client->writePos = 0;
  33 +
  34 + freeHttpHeader(&(client->httpHeader));
  35 +
  36 + XML_ParserFree(client->parser);
  37 +
  38 + memset(client->remoteAddr, 0, 16);
  39 +}
  1 +#include <unistd.h> /* for getopt */
  2 +#include <stdlib.h> /* for exit */
  3 +#include <string.h> /* for memset and stuff */
  4 +#include <errno.h> /* for errno */
  5 +
  6 +#include "../../include/client.h"
  7 +#include "../../include/monitor.h"
  8 +
  9 +#define GET_MULTIPLIER(size) (((size) - 1) / READBUFSIZE + 1)
  10 +
  11 +static int
  12 +_clientReallocBuffer(tClient * client, unsigned int newSize)
  13 +{
  14 + unsigned int newMult = GET_MULTIPLIER(newSize);
  15 +
  16 + if (CLIENTMULTMAX < newMult) {
  17 + /* line exceeds maximum line length */
  18 + return 0;
  19 + }
  20 +
  21 + if (client->readBufMult < newMult) {
  22 +
  23 + char * newBuffer = calloc(newMult * READBUFSIZE, sizeof(char));
  24 +
  25 + if (NULL == newBuffer) {
  26 + syslogMonitor(LOG_ERR, MON_CRITICAL, "calloc",
  27 + "calloc for readbuffer[%s] failed",
  28 + client->remoteAddr);
  29 +
  30 + exit(EXIT_FAILURE);
  31 + }
  32 +
  33 + if (NULL != client->readBuffer) {
  34 + memcpy(newBuffer, client->readBuffer, client->readPos);
  35 + free(client->readBuffer);
  36 +
  37 + client->readBuffer = newBuffer;
  38 + client->readBufMult = newMult;
  39 + } else {
  40 + /*
  41 + * we can't get the resized buffer so return the
  42 + * old multiplier
  43 + */
  44 + newMult = client->readBufMult;
  45 + }
  46 +
  47 + }
  48 +
  49 + return newMult;
  50 +}
  51 +
  52 +int
  53 +clientRead(tClient * client)
  54 +{
  55 + int readSize;
  56 + char readBuf[READBUFSIZE];
  57 +
  58 + /*
  59 + * initialize values // read data from socket
  60 + */
  61 + memset(readBuf, 0, READBUFSIZE);
  62 + readSize = read(client->socket, readBuf, READBUFSIZE);
  63 +
  64 + switch (readSize) {
  65 + case -1:
  66 + syslogMonitor(LOG_WARNING, MON_WARNING, "socket.read",
  67 + "read returns -1 for client[%s]: %s - connection closed",
  68 + client->remoteAddr, strerror(errno));
  69 + break;
  70 +
  71 + case 0:
  72 + break;
  73 +
  74 + default:
  75 + if (!_clientReallocBuffer(client, client->readPos + readSize)) {
  76 + syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline",
  77 + "got to long line from client[%s] - connection closed",
  78 + client->remoteAddr);
  79 +
  80 + return READ_ERR_LONGLINE;
  81 + }
  82 +
  83 + if (client->readPos +readSize > client->readBufMult *READBUFSIZE) {
  84 + syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline",
  85 + "can't allocate enough memory for read on client[%s]"
  86 + " - connection closed",
  87 + client->remoteAddr);
  88 +
  89 + return READ_ERR_MEMORY;
  90 + }
  91 +
  92 + memcpy(client->readBuffer+client->readPos, readBuf, readSize);
  93 + client->readPos += readSize;
  94 + break;
  95 + }
  96 +
  97 + return readSize;
  98 +}
  99 +
  100 +#define EOB(client,addr) ((addr) -(client)->readBuffer >= (client)->readPos)
  101 +#define REMAINING(client,addr) ((client)->readPos - ((addr) - (client)->readBuffer))
  102 +
  103 +static char *
  104 +_clientGetLineDelimiter(tClient * client, const char * delim, unsigned int len)
  105 +{
  106 + char * foundDelim = memchr(client->readBuffer, delim[0], client->readPos);
  107 +
  108 + while (NULL != foundDelim && !EOB(client, foundDelim)) {
  109 +
  110 + unsigned int i = 0;
  111 +
  112 + while (i < len && !EOB(client, &(foundDelim[i])) && foundDelim[i] == delim[i]) i++;
  113 +
  114 + if (i == len) {
  115 + return foundDelim;
  116 + } else {
  117 + if (!EOB(client, ++foundDelim)) {
  118 + foundDelim = memchr(foundDelim, delim[0], REMAINING(client, foundDelim));
  119 + }
  120 + }
  121 + }
  122 +
  123 + return NULL;
  124 +}
  125 +
  126 +/*
  127 + * this returns a newly allocate buffer, with the found line
  128 + * copied to it.
  129 + * The calles has to take care to free this buffer again,
  130 + * after he uses it.
  131 + */
  132 +char *
  133 +clientConsumeLine(tClient * client, const char * delim, unsigned int * len)
  134 +{
  135 + char * found = clientGetLine(client, delin, len);
  136 + char * line = NULL;
  137 +
  138 + if (NULL != found) {
  139 + line = calloc(*len +1, sizeof(char));
  140 + memcpy(line, found, *len);
  141 + }
  142 +
  143 + return line;
  144 +}
  145 +
  146 +/*
  147 + * as a side effect this gives sets length of the found line in len
  148 + */
  149 +char *
  150 +clientGetLine(tClient * client, const char * delim, unsigned int * len)
  151 +{
  152 + char * foundDelim = _clientGetLineDelimiter(client, delim, *len);
  153 +
  154 + if (NULL != foundDelim) {
  155 + *len = foundDelim -client->readBuffer -1;
  156 + return client->readBuffer;
  157 + }
  158 +
  159 + return NULL;
  160 +}
  161 +
  162 +char *
  163 +clientRemoveLine(tClient * client, const char * delim, unsigned int * len)
  164 +{
  165 + unsigned int lineLen;
  166 + char * foundDelim = _clientGetLineDelimiter(client, delim, &lineLen);
  167 +
  168 + if (NULL != foundDelim) {
  169 + char * actAddr = client->readBuffer +client->readPos;
  170 +
  171 + if (actAddr == foundDelim +*len) {
  172 +
  173 + memset(client->readBuffer, 0, client->readPos);
  174 + *len = client->readPos = 0;
  175 +
  176 + } else {
  177 +
  178 + unsigned int moveSize = actAddr -foundDelim -*len;
  179 + unsigned int clearSize = actAddr -client->readBuffer -moveSize;
  180 +
  181 + memmove(client->readBuffer, foundDelim +*len, moveSize);
  182 + memset(client->readBuffer +moveSize, 0, clearSize);
  183 + *len = client->readPos = moveSize;
  184 + }
  185 +
  186 + return client->readBuffer;
  187 + }
  188 +
  189 + return NULL;
  190 +}
  191 +
  192 +/*
  193 + * fill a buffer from a stream. This call might not fill the whole
  194 + * buffer at once, as not len size data might have been written to
  195 + * the stream. In this case it returns a pointer to the position
  196 + * the next read has to occur.
  197 + * SIDEEFFECT: additially *len is set to the remaining size to read.
  198 + */
  199 +char *
  200 +clientGetBuffer(tClient * client, char * buffer, unsigned int * len)
  201 +{
  202 +}
  1 +#include <stdio.h> /* for ferror() */
  2 +#include <string.h> /* for memset and stuff */
  3 +
  4 +
  5 +int
  6 +writeBuffer(char ** buffer, unsigned int * readPos, FILE * wHandle)
  7 +{
  8 + char * nlpos = strchr(*buffer, '\n');
  9 + int written = 0;
  10 +
  11 + while (NULL != nlpos) {
  12 + unsigned int moveSize, clearSize;
  13 + char * actAddr;
  14 +
  15 + *nlpos = '\0';
  16 +
  17 + if (0 != strlen(*buffer)) {
  18 + /* write remaining stuff to file */
  19 + fputs(*buffer, wHandle);
  20 + if (ferror(wHandle)) {
  21 + return -1;
  22 + }
  23 +
  24 + fputc('\n', wHandle);
  25 + if (ferror(wHandle)) {
  26 + return -1;
  27 + }
  28 +
  29 + fflush(wHandle);
  30 + if (ferror(wHandle)) {
  31 + return -1;
  32 + }
  33 +
  34 + written += strlen(*buffer) + 1;
  35 + }
  36 +
  37 + actAddr = *buffer + *readPos;
  38 + moveSize = actAddr - nlpos - 1;
  39 + clearSize = actAddr - *buffer - moveSize;
  40 + memmove(*buffer, nlpos+1, moveSize);
  41 + memset(*buffer + moveSize, 0, clearSize);
  42 + *readPos = moveSize;
  43 +
  44 + nlpos = strchr(*buffer, '\n');
  45 + }
  46 +
  47 + return written;
  48 +}
  1 +INCLUDE=include
  2 +VPATH=../../$(INCLUDE)
  3 +
  4 +OBJECTS=$(httpReader_OBJ)
  5 +
  6 +all: $(OBJECTS)
  7 +
  8 +%.o: %.c
  9 + gcc $(CFLAGS) -c $< -o $@
  10 +
  11 +%.o: httpRequest.h
  12 +
  13 +.PHONY: clean
  14 +clean:
  15 + -rm *.o
  1 +#include <string.h>
  2 +#include <stdlib.h>
  3 +#include <stdio.h>
  4 +#include <ctype.h>
  5 +
  6 +#include "../../include/appConfig.h"
  7 +#include "../../include/httpRequest.h"
  8 +#include "../../include/client.h"
  9 +
  10 +#define SPACE 0x20
  11 +
  12 +
  13 +char httpRequest[8][8] = {
  14 + "OPTIONS",
  15 + "GET",
  16 + "HEAD",
  17 + "POST",
  18 + "PUT",
  19 + "DELETE",
  20 + "TRACE",
  21 + "CONNECT"
  22 +};
  23 +
  24 +/*
  25 + * Gedanken zum request einlese:
  26 + * der client liest stumpf daten, außerdem implementiert er eine Methode um die
  27 + * erste Zeile aus dem readbuffer zu entfernen.
  28 + * Des weiteren eine Methode getLine die NULL zurück gibt wenn noch keine Zeile
  29 + * komplett ist, ansonsten einen Pointer auf diese.
  30 + * Der servercode triggert das Daten lesen des client, versucht dann die erste
  31 + * Zeile zu lesen und gibt diese im erfolgsfall an den httpCode weiter um
  32 + * dann wenn dieser ein OK gibt die erste Zeile über den clientCode wieder zu entfernen.
  33 + * Leere Zeile vor der request line werden ignoriert.
  34 + * Ebenso leere Zailen nachdem der request komplett eingelesen ist.
  35 + * Nachdem alle Header Zeile eingelesen wurden...d.H. sobald eine leere Header Zeile
  36 + * gelesen wurde wird exakt bodyLength vom client versucht zu lesen...hierbei
  37 + * können die Daten die von client kommen in den body buffer übertragen werden.
  38 + * Dabei kann im client code der buffer immer entsprechend zurück gesetzt werden.
  39 + */
  40 +int
  41 +httpHeaderGetLine(tHttpHeader * header, char ** buffer, unsigned int * readPos)
  42 +{
  43 + return 1;
  44 +}
  45 +
  46 +void
  47 +httpHeaderParseRequestLine(tHttpHeader * header, const char * line, unsigned int len)
  48 +{
  49 +}
  50 +
  51 +int
  52 +httpHeaderIsComplete(tHttpHeader * header)
  53 +{
  54 + if (NULL == header->req.method) {
  55 + return 0;
  56 + }
  57 +
  58 + return 1;
  59 +}
  60 +
  61 +unsigned char
  62 +httpHeaderIsStarted(tHttpHeader * header) {
  63 + return 1;
  64 +}
  65 +
  66 +static void
  67 +httpRequestStrip(char ** buffer, unsigned int * readPos)
  68 +{
  69 + char * end = *buffer;
  70 +
  71 + /* remove all surrounding CRLF */
  72 + while (('\r' == *end || '\n' == *end) && *end) {
  73 + end++;
  74 + }
  75 +
  76 + if (end != *buffer) {
  77 + memmove(*buffer, end, *readPos - (end - *buffer));
  78 + memset(*buffer, 0, end - *buffer);
  79 +
  80 + *readPos -= (end - * buffer);
  81 + }
  82 +}
  83 +
  84 +int
  85 +httpHeaderGet(char ** buffer, unsigned int * readPos, tHttpHeader * request)
  86 +{
  87 + char * end = *buffer;
  88 + unsigned int readPosNew;
  89 +
  90 + httpRequestStrip(buffer, readPos);
  91 + end = strstr(*buffer, "\r\n\r\n");
  92 +
  93 + /* get header if not already read and complete */
  94 + if (!httpHeaderIsComplete(request) && NULL != end) {
  95 + /* get request line */
  96 + char * methodEnd = strchr(*buffer, SPACE);
  97 + char * uriEnd = strchr(methodEnd + 1, SPACE);
  98 + char * lineEnd = strstr(*buffer, "\r\n");
  99 +
  100 + request->req.method =
  101 + calloc(methodEnd-*buffer+1, sizeof(char));
  102 + request->req.requestUri =
  103 + calloc(uriEnd-methodEnd, sizeof(char));
  104 + request->req.httpVersion =
  105 + calloc(lineEnd-uriEnd, sizeof(char));
  106 +
  107 + sscanf(*buffer, "%s %s %s\r\n",
  108 + request->req.method,
  109 + request->req.requestUri,
  110 + request->req.httpVersion);
  111 +
  112 + readPosNew = (*buffer + *readPos) - lineEnd - 2;
  113 + memmove(*buffer, lineEnd + 2, readPosNew);
  114 + memset(*buffer + readPosNew, 0, *readPos - readPosNew);
  115 + *readPos = readPosNew;
  116 +
  117 + /* get all header lines */
  118 + do {
  119 + char * keyEnd = strchr(*buffer, ':');
  120 +
  121 + lineEnd = strstr(*buffer, "\r\n");
  122 +
  123 + if (lineEnd != *buffer) {
  124 + tHttpHeaderLine * actHeader;
  125 + char * actKey = NULL;
  126 +
  127 + request->headersCount += 1;
  128 +
  129 + request->headers = realloc(request->headers,
  130 + request->headersCount * sizeof(tHttpHeaderLine));
  131 + actHeader = &(request->headers[request->headersCount-1]);
  132 + memset(actHeader, 0, sizeof(tHttpHeaderLine));
  133 +
  134 + actKey = actHeader->key = calloc(keyEnd-*buffer+1, sizeof(char));
  135 + actHeader->value = calloc(lineEnd-keyEnd-1, sizeof(char));
  136 +
  137 + sscanf(*buffer, "%[^:]:%s\r\n",
  138 + actHeader->key, actHeader->value);
  139 + //while (NULL != actKey && *actKey != '\0' && (*actKey = tolower(*(actKey++)))); // strtolower
  140 + for (; NULL != actKey && *actKey != '\0'; actKey++) {
  141 + *actKey = tolower(*actKey);
  142 + }
  143 +
  144 + if (0 == strncmp("content-length", actHeader->key, strlen(actHeader->key))) {
  145 + request->bodyLength = atoi(actHeader->value);
  146 + }
  147 + }
  148 +
  149 + readPosNew = (*buffer + *readPos) - lineEnd - 2;
  150 + memmove(*buffer, lineEnd + 2, readPosNew);
  151 + memset(*buffer + readPosNew, 0, *readPos - readPosNew);
  152 + *readPos = readPosNew;
  153 + } while (lineEnd != *buffer);
  154 +
  155 + return request->bodyLength;
  156 + }
  157 +
  158 + return 0;
  159 +}
  160 +
  161 +int
  162 +getHttpRequest(char ** buffer, unsigned int * readPos, tHttpRequest * request)
  163 +{
  164 + /* get body if header is read and body incomplete */
  165 + if (request->header.bodyLength != request->length) {
  166 + size_t size = MIN(
  167 + request->header.bodyLength - request->length,
  168 + *readPos);
  169 +
  170 + if (0 != size) {
  171 + if (NULL == request->body) {
  172 + request->body = calloc(request->header.bodyLength, sizeof(char));
  173 + }
  174 +
  175 + memcpy(request->body + request->length, *buffer, size);
  176 + memmove(*buffer, *buffer + size, *readPos - size);
  177 + memset(*buffer + (*readPos - size), 0, size);
  178 + *readPos -= size;
  179 + request->length += size;
  180 + }
  181 + }
  182 +
  183 + return 0;
  184 +}
  185 +
  186 +void
  187 +freeHttpHeader(tHttpHeader * header) {
  188 + unsigned int i;
  189 +
  190 + if (NULL != header->req.method) {
  191 + free(header->req.method);
  192 + }
  193 + if (NULL != header->req.requestUri) {
  194 + free(header->req.requestUri);
  195 + }
  196 + if (NULL != header->req.httpVersion) {
  197 + free(header->req.httpVersion);
  198 + }
  199 +
  200 + for (i=0; i<header->headersCount; i++) {
  201 + if (NULL != header->headers[i].key) {
  202 + free(header->headers[i].key);
  203 + }
  204 + if (NULL != header->headers[i].value) {
  205 + free(header->headers[i].value);
  206 + }
  207 + }
  208 +
  209 + if (NULL != header->headers) {
  210 + free(header->headers);
  211 + }
  212 +
  213 + memset (header, 0, sizeof (tHttpHeader));
  214 +}
  215 +
  216 +void
  217 +freeHttpRequest(tHttpRequest * request) {
  218 + unsigned int i;
  219 +
  220 + if (NULL != request->header.req.method) {
  221 + free(request->header.req.method);
  222 + request->header.req.method = NULL;
  223 + }
  224 + if (NULL != request->header.req.requestUri) {
  225 + free(request->header.req.requestUri);
  226 + request->header.req.requestUri = NULL;
  227 + }
  228 + if (NULL != request->header.req.httpVersion) {
  229 + free(request->header.req.httpVersion);
  230 + request->header.req.httpVersion = NULL;
  231 + }
  232 +
  233 + for (i=0; i<request->header.headersCount; i++) {
  234 + if (NULL != request->header.headers[i].key) {
  235 + free(request->header.headers[i].key);
  236 + request->header.headers[i].key = NULL;
  237 + }
  238 + if (NULL != request->header.headers[i].value) {
  239 + free(request->header.headers[i].value);
  240 + request->header.headers[i].value = NULL;
  241 + }
  242 + }
  243 +
  244 + if (NULL != request->header.headers) {
  245 + free(request->header.headers);
  246 + request->header.headers = NULL;
  247 + }
  248 +
  249 + if (NULL != request->body) {
  250 + free(request->body);
  251 + request->body = NULL;
  252 + }
  253 +
  254 + memset (request, 0, sizeof (tHttpRequest));
  255 +}
  1 +INCLUDE=include
  2 +VPATH=../$(INCLUDE)
  3 +
  4 +OBJECTS=$(server_OBJ)
  5 +
  6 +all: $(OBJECTS)
  7 +
  8 +%.o: %.c
  9 + gcc $(CFLAGS) -c $< -o $@
  10 +
  11 +server.h: client.h
  12 +server%.o: server.h monitor.h
  13 +serverRun.o serverInit.o: socket.h logRotate.h
  14 +serverRun.o serverShutdown.o: writeBuffer.h
  15 +serverRun.o: signalHandling.h httpRequest.h
  16 +
  17 +.PHONY: clean
  18 +clean:
  19 + -rm *.o
  1 +#include <sys/select.h> /* for select system call and related */
  2 +#include <string.h> /* for memset and stuff */
  3 +#include <stdlib.h> /* for getopt */
  4 +
  5 +#include "../include/server.h"
  6 +#include "../include/socket.h"
  7 +#include "../include/monitor.h"
  8 +#include "../include/logRotate.h"
  9 +
  10 +void
  11 +serverInit(
  12 + tServer * server,
  13 + unsigned int port,
  14 + unsigned int pending,
  15 + const char * logPath,
  16 + const char * namePat)
  17 +{
  18 + FD_ZERO(&(server->socks));
  19 +
  20 + server->servSock = initServerSocket(port, pending);
  21 + server->maxFd = server->servSock;
  22 + FD_SET(server->servSock, &(server->socks));
  23 +
  24 + strncpy(server->logPath, logPath, sizeof(server->logPath)-1);
  25 + strncpy(server->namePat, namePat, sizeof(server->namePat)-1);
  26 +
  27 + memset(server->clients, 0, sizeof(server->clients));
  28 +
  29 + /*
  30 + * try to open file (firstrun)
  31 + */
  32 + if (NULL == server->wHandle) {
  33 + logRotate(&(server->wHandle), server->logPath, server->namePat);
  34 + if (NULL == server->wHandle) {
  35 + syslogMonitor(LOG_ERR, MON_INFO, "logfile.rotate",
  36 + "no valid handle for logfile - service terminated");
  37 + exit(EXIT_FAILURE);
  38 + }
  39 + }
  40 +}
  1 +#include <sys/select.h> /* for select system call and related */
  2 +#include <string.h> /* for memset and stuff */
  3 +#include <stdlib.h> /* for exit */
  4 +#include <errno.h> /* for errno */
  5 +#include <unistd.h> /* for write */
  6 +
  7 +#include <expat.h>
  8 +
  9 +#include "../include/appConfig.h"
  10 +#include "../include/server.h"
  11 +#include "../include/client.h"
  12 +#include "../include/socket.h"
  13 +#include "../include/monitor.h"
  14 +#include "../include/logRotate.h"
  15 +#include "../include/signalHandling.h"
  16 +#include "../include/httpRequest.h"
  17 +
  18 +#define RESPONSE " 200 OK\r\nServer: xmlrpc\r\nStatus: 200\r\nContent-Length: 10\r\nContent-Type: text/plain\r\n\r\n0123456789"
  19 +
  20 +int Depth;
  21 +
  22 +void XMLCALL
  23 +start(void *data, const char *el, const char **attr) {
  24 + int i;
  25 +
  26 + for (i = 0; i < Depth; i++)
  27 + printf(" ");
  28 +
  29 + printf("%s", el);
  30 +
  31 + for (i = 0; attr[i]; i += 2) {
  32 + printf(" %s='%s'", attr[i], attr[i + 1]);
  33 + }
  34 +
  35 + printf("\n");
  36 + Depth++;
  37 +} /* End of start handler */
  38 +
  39 +void XMLCALL
  40 +end(void *data, const char *el) {
  41 + int i;
  42 +
  43 + Depth--;
  44 + for (i = 0; i < Depth; i++)
  45 + printf(" ");
  46 + printf("--\n");
  47 +} /* End of end handler */
  48 +
  49 +void
  50 +serverRun(tServer * server)
  51 +{
  52 + syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");
  53 +
  54 + while (!doShutdown) /* until error or signal */
  55 + {
  56 + fd_set rfds;
  57 + fd_set wfds;
  58 + int i;
  59 +
  60 + memcpy(&rfds, &(server->socks), sizeof(fd_set));
  61 +
  62 + FD_ZERO(&wfds);
  63 + for (i=3; i<=server->maxFd; i++) {
  64 + tClient * actClient = &(server->clients)[i];
  65 +
  66 + if (FD_ISSET(i, &(server->socks))
  67 + && NULL != actClient->writeBuffer
  68 + && 0 != strlen(actClient->writeBuffer)) {
  69 + FD_SET(i, &wfds);
  70 + }
  71 + }
  72 +
  73 + /*
  74 + * wait for handles to become ready
  75 + */
  76 + if (-1 == select((server->maxFd)+1, &rfds, &wfds, NULL, NULL))
  77 + {
  78 + switch (errno) {
  79 + default:
  80 + case EBADF:
  81 + case EINVAL:
  82 + case ENOMEM:
  83 + doShutdown = 1;
  84 + /* Fallthrough */
  85 +
  86 + case EINTR:
  87 + syslogMonitor(LOG_ERR, MON_INFO, "select",
  88 + "select systemcall failed: [%s] - service terminated",
  89 + strerror(errno));
  90 + continue; /* in while loop above */
  91 + }
  92 + }
  93 +
  94 + /*
  95 + * handle accept
  96 + */
  97 + if (FD_ISSET(server->servSock, &rfds)) {
  98 + int fd;
  99 + char remoteAddr[16] = "";
  100 +
  101 + if (-1 != (fd = acceptConnection(server->servSock, remoteAddr))) {
  102 + (server->clients)[fd].socket = fd; // save the socket handle within the client struct
  103 + strncpy(
  104 + (server->clients)[fd].remoteAddr,
  105 + remoteAddr,
  106 + sizeof((server->clients)[fd].remoteAddr)-1);
  107 + FD_SET(fd, &(server->socks));
  108 + server->maxFd = MAX(fd, server->maxFd);
  109 +
  110 + (server->clients)[fd].parser = XML_ParserCreate("UTF-8");
  111 + XML_SetElementHandler((server->clients)[fd].parser, &start, &end);
  112 +
  113 + }
  114 +
  115 + FD_CLR(server->servSock, &rfds);
  116 + }
  117 +
  118 + /* handle reads (max 10 before next select, else we block accept for to long) */
  119 + for (i=3; i<=server->maxFd; i++) {
  120 +// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
  121 + tClient * actClient = &(server->clients)[i];
  122 +
  123 + if (FD_ISSET(i, &rfds)) {
  124 + switch (clientRead(actClient)) {
  125 + case -1:
  126 + syslogMonitor(LOG_WARNING, MON_INFO, "socket.read",
  127 + "read on socket for %s returns -1: %s",
  128 + actClient->remoteAddr, strerror(errno));
  129 + /* FALLTHROUGH */
  130 +
  131 + case 0:
  132 + clientClose(actClient);
  133 + FD_CLR(i, &(server->socks));
  134 + break;
  135 +
  136 + default:
  137 + if (! httpHeaderIsComplete(&(actClient->httpHeader))) {
  138 + char delim[] = "\r\n";
  139 + unsigned int len = strlen(delim);
  140 + char * line = clientGetLine(actClient, delim, &len);
  141 +
  142 + /*
  143 + * len might be 0, thus indicatin an empty line
  144 + * this might happen in two cases
  145 + * 1. when a header is not already started
  146 + * (could be identifies by a null req.method
  147 + * 2. if a header is started, then it indicates
  148 + * the end of the header.
  149 + */
  150 +
  151 + while (! httpHeaderIsStarted(&(actClient->httpHeader))) {
  152 +
  153 + if (0 != len) {
  154 + httpHeaderParseRequestLine(&(actClient->httpHeader), line, len);
  155 + // TODO: do some error handling here
  156 + }
  157 +
  158 + len = strlen(delim);
  159 + clientRemoveLine(actClient, delim, &len); // TODO: do some error handling here
  160 + len = strlen(delim);
  161 + line = clientGetLine(actClient, delim, &len);
  162 +
  163 + }
  164 +
  165 + while (NULL != line) {
  166 + if (NULL == actClient->httpHeader.req.method) {
  167 + }
  168 + }
  169 + }
  170 +
  171 + if (!httpHeaderIsComplete(&(actClient->httpHeader))) {
  172 + actClient->bodyLenRemaining = httpHeaderGet(
  173 + &(actClient->readBuffer),
  174 + &(actClient->readPos),
  175 + &(actClient->httpHeader));
  176 + }
  177 +
  178 + if (httpHeaderIsComplete(&(actClient->httpHeader))) {
  179 + size_t size = MIN(actClient->bodyLenRemaining, actClient->readPos);
  180 + unsigned int isLast = !(size - actClient->bodyLenRemaining);
  181 +
  182 + enum XML_Status expatStat;
  183 +
  184 + expatStat = XML_Parse(actClient->parser, actClient->readBuffer, size, isLast);
  185 +
  186 + actClient->readPos -= size;
  187 + actClient->bodyLenRemaining -= size;
  188 + memmove(actClient->readBuffer, actClient->readBuffer + size, actClient->readPos);
  189 + memset(actClient->readBuffer + actClient->readPos, 0, size);
  190 +
  191 + if (isLast && NULL == actClient->writeBuffer) {
  192 +
  193 + actClient->writeBuffer = calloc(
  194 + strlen(actClient->httpHeader.req.httpVersion) +
  195 + strlen(RESPONSE) + 3,
  196 + sizeof(char));
  197 + sprintf(actClient->writeBuffer, "%s%s",
  198 + actClient->httpHeader.req.httpVersion,
  199 + RESPONSE);
  200 +
  201 + freeHttpHeader(&(actClient->httpHeader));
  202 + XML_ParserFree(actClient->parser);
  203 + actClient->parser = NULL;
  204 + }
  205 + }
  206 + break;
  207 + }
  208 + }
  209 + }
  210 +
  211 + /* handle writes */
  212 + for (i=3; i<=server->maxFd; i++) {
  213 +// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
  214 + tClient * actClient = &(server->clients)[i];
  215 +
  216 + // TODO: the && is only symptom fix...need to find real bug.
  217 + if (FD_ISSET(i, &wfds) && NULL != actClient->writeBuffer) {
  218 + int writeSize = 0;
  219 + int toWrite = strlen(actClient->writeBuffer);
  220 +
  221 + writeSize = write(actClient->socket, actClient->writeBuffer, toWrite);
  222 +
  223 + if (0 < writeSize) {
  224 + if (writeSize == toWrite) {
  225 + free(actClient->writeBuffer);
  226 + actClient->writeBuffer = NULL;
  227 +
  228 + clientClose(actClient);
  229 + FD_CLR(i, &(server->socks));
  230 + } else {
  231 + memmove(actClient->writeBuffer, actClient->writeBuffer + writeSize, toWrite - writeSize);
  232 + memset(actClient->writeBuffer + (toWrite - writeSize), 0, writeSize);
  233 + }
  234 + }
  235 + }
  236 + }
  237 + }
  238 +}
  1 +#include <stdio.h> /* for printf() and fprintf() */
  2 +#include <sys/select.h> /* for select system call and related */
  3 +#include <sys/socket.h> /* for select system call and related */
  4 +#include <stdlib.h> /* for exit */
  5 +#include <string.h> /* for memset and stuff */
  6 +#include <unistd.h> /* for getopt */
  7 +#include <errno.h> /* for errno */
  8 +
  9 +#include "../include/server.h"
  10 +#include "../include/monitor.h"
  11 +#include "../include/writeBuffer.h"
  12 +
  13 +
  14 +void
  15 +serverShutdown(tServer * server)
  16 +{
  17 + int i;
  18 +
  19 + for (i=3; i<=server->maxFd; i++) {
  20 + if (FD_ISSET(i, &(server->socks))) {
  21 + if (i == server->servSock) {
  22 + shutdown(server->servSock, SHUT_RDWR);
  23 + close(server->servSock);
  24 + } else {
  25 + /* actual do nothing except closing the client */
  26 + clientClose(&((server->clients)[i]));
  27 + FD_CLR(i, &(server->socks));
  28 + }
  29 + }
  30 + }
  31 +
  32 + if (NULL != server->wHandle) {
  33 + fclose(server->wHandle);
  34 + }
  35 +}
  1 +INCLUDE=include
  2 +VPATH=../$(INCLUDE)
  3 +
  4 +OBJECTS=$(system_OBJ)
  5 +
  6 +all: $(OBJECTS)
  7 +
  8 +%.o: %.c
  9 + gcc $(CFLAGS) -c $< -o $@
  10 +
  11 +logRotate.o signalHandling.o socket.o: monitor.h
  12 +serverRun.o: signalHandling.h httpRequest.h
  13 +handleCmdLine.o: appConfig.h
  14 +
  15 +.PHONY: clean
  16 +clean:
  17 + -rm *.o
  1 +#include <stdio.h> /* for printf() and fprintf() */
  2 +#include <unistd.h> /* for getopt */
  3 +#include <stdlib.h>
  4 +
  5 +
  6 +void daemonize(void) {
  7 + pid_t pid;
  8 +
  9 + if (0 > ((pid = fork()))) {
  10 + perror("deamoinze[fork]");
  11 + exit(EXIT_FAILURE);
  12 + } else if (0 != pid) {
  13 + exit(EXIT_SUCCESS);
  14 + }
  15 +
  16 + /* make new child session leader */
  17 + setsid();
  18 +
  19 + /* connect all standard streams to /dev/null */
  20 + freopen("/dev/null", "w", stderr);
  21 + freopen("/dev/null", "r", stdin);
  22 + freopen("/dev/null", "w", stdout);
  23 +}
  1 +#include <unistd.h> /* for getopt */
  2 +#include <stdlib.h>
  3 +#include <string.h>
  4 +#include <stdio.h>
  5 +
  6 +#include "../include/appConfig.h"
  7 +
  8 +
  9 +int
  10 +handleCmdLine(tAppConfig * config, int argc, char *argv[])
  11 +{
  12 + int opt;
  13 +
  14 + while ((opt = getopt(argc, argv, "Dvp:l:n:b:")) != -1) {
  15 + switch (opt) {
  16 + case 'p':
  17 + /* port */
  18 + config->port = atoi(optarg);
  19 + break;
  20 +
  21 + case 'l':
  22 + /* logPath */
  23 + strncpy(config->logPath, optarg, sizeof(config->logPath)-1);
  24 + break;
  25 +
  26 + case 'n':
  27 + /* logNamePattern */
  28 + strncpy(config->namePat, optarg, sizeof(config->namePat)-1);
  29 + break;
  30 +
  31 + case 'b':
  32 + /* maxPending (connection backlog) */
  33 + config->maxPending = atoi(optarg);
  34 + break;
  35 +
  36 + case 'v':
  37 + /* verbose */
  38 + config->verbose = 1;
  39 + break;
  40 +
  41 + case 'D':
  42 + /* verbose */
  43 + config->doDaemon = 1;
  44 + break;
  45 +
  46 + default:
  47 + /* '?' */
  48 + fprintf(
  49 + stderr,
  50 + "Usage: %s [-p port] [-l logPath] [-n logNamePattern] [-c maxClient] [-b backlog] [-v] [-D]\n"
  51 + "Defaults:\n"
  52 + "\t%-20s: port this service will use [%d]\n"
  53 + "\t%-20s: path where the logfiles will be stored [%s/]\n"
  54 + "\t%-20s: patten used by strftime to create the log filename [%s]\n"
  55 + "\t%-20s: maximum connection backlog [%d]\n"
  56 + "\t%-20s: be more verbose in syslog [off]\n"
  57 + "\t%-20s: deamonize me\n",
  58 + argv[0],
  59 + "-p port", DEFAULTPORT,
  60 + "-l logPath", DEFAULTPATH,
  61 + "-n logNamePattern", LOGNAMEPATTERN,
  62 + "-b backlog", MAXPENDING,
  63 + "-v",
  64 + "-D");
  65 + exit(EXIT_FAILURE);
  66 + }
  67 + }
  68 +
  69 + return 0;
  70 +}
  1 +#include <sys/select.h> /* for select system call and related */
  2 +#include <time.h>
  3 +#include <unistd.h> /* for fork and exec */
  4 +#include <sys/types.h>
  5 +#include <sys/wait.h>
  6 +#include <stdio.h> /* fopen and stuff */
  7 +#include <stdlib.h> /* exit */
  8 +#include <string.h> /* strncpy, memcpy, etc. */
  9 +#include <syslog.h>
  10 +#include <errno.h>
  11 +
  12 +#include "../include/monitor.h"
  13 +
  14 +
  15 +extern int verbose;
  16 +
  17 +void logRotate(FILE ** handle, char * path, char * pattern) {
  18 + static char logName[1024] = "";
  19 +
  20 + char strftimeName[128] = "";
  21 + char newLogName[1024] = "";
  22 +
  23 + time_t t;
  24 + struct tm *tmp;
  25 +
  26 + t = time(NULL);
  27 + tmp = localtime(&t);
  28 + if (tmp == NULL) {
  29 + syslogMonitor(LOG_ERR, MON_INFO, "logrotate.localtime",
  30 + "can't get localtime for new logname. continue with old one");
  31 + return;
  32 + }
  33 +
  34 + if (strftime(strftimeName, sizeof(strftimeName)-1, pattern, tmp) == 0) {
  35 + syslogMonitor(LOG_ERR, MON_INFO, "logrotate.strftime",
  36 + "strftime returned 0 for new logname. continue with old one");
  37 + return;
  38 + }
  39 +
  40 + snprintf(newLogName, sizeof(newLogName)-1, "%s/%s", path, strftimeName);
  41 +
  42 + if (0 != strncmp(logName, newLogName, sizeof(logName)-1)) {
  43 + if (0 != verbose) {
  44 + syslog(LOG_INFO, "actual logfile name: %s", logName);
  45 + syslog(LOG_INFO, "new logfile name: %s", newLogName);
  46 + }
  47 +
  48 + if (NULL != *handle) {
  49 + fclose(*handle);
  50 +
  51 + pid_t gzipPid = fork();
  52 +
  53 + switch(gzipPid) {
  54 + pid_t tmpPid;
  55 +
  56 + case 0:
  57 + // We don't care about finishing of child, so decouple it
  58 + // by using a second child that stop immediatly
  59 + tmpPid = fork();
  60 + if (0 == tmpPid) {
  61 + syslog(LOG_INFO, "gzip: %s", logName);
  62 + if (-1 == execl("/bin/gzip", "/bin/gzip", "-9", logName, (char *) 0)) {
  63 + syslogMonitor(LOG_ERR, MON_INFO, "logrotate.gzip",
  64 + "execl failed for gzip %s: %s", logName, strerror(errno));
  65 + }
  66 + }
  67 + exit(EXIT_SUCCESS);
  68 +
  69 + case -1:
  70 + syslogMonitor(LOG_ERR, MON_INFO, "logrotate.fork",
  71 + "fork failed for gzip %s: %s", logName, strerror(errno));
  72 + break;
  73 +
  74 + default:
  75 + wait(NULL);
  76 + break;
  77 + }
  78 + }
  79 +
  80 + strncpy(logName, newLogName, sizeof(logName)-1);
  81 + *handle = fopen(logName, "w");
  82 + }
  83 +}
  1 +#include <stdlib.h> /* for system() */
  2 +#include <sys/wait.h>
  3 +#include <stdio.h>
  4 +#include <string.h>
  5 +#include <errno.h>
  6 +#include <signal.h>
  7 +#include <stdarg.h> /* for ellipse handling */
  8 +
  9 +#include "../include/signalHandling.h"
  10 +#include "../include/monitor.h"
  11 +
  12 +
  13 +#define MONITORCMD "/usr/bin/monitor"
  14 +#define MONITORTYPE "test"
  15 +#define MONITORNAME "virtualitemlogreceiver"
  16 +
  17 +const char severity[][10] = {
  18 + "info",
  19 + "warning",
  20 + "critical",
  21 + "failure"
  22 +};
  23 +
  24 +
  25 +int
  26 +monitor(
  27 + unsigned int sev,
  28 + const char * pattern,
  29 + const char * message
  30 +) {
  31 + char monCall[1024];
  32 + int ret;
  33 +
  34 + snprintf(monCall, 1023,
  35 + "%s %s %s.%s.%s \"%s\"",
  36 + MONITORCMD,
  37 + severity[sev],
  38 + MONITORTYPE,
  39 + MONITORNAME,
  40 + pattern,
  41 + message);
  42 +
  43 + ret = system(monCall);
  44 +
  45 + if (WIFSIGNALED(ret)) {
  46 + switch (WTERMSIG(ret)) {
  47 + case SIGINT:
  48 + case SIGQUIT:
  49 + syslog(LOG_INFO, "interrupted in monitor call");
  50 + doShutdown=1;
  51 + }
  52 + }
  53 +
  54 + if (-1 == ret || 0 != WEXITSTATUS(ret)) {
  55 + syslog(LOG_ERR, "call monitoring failed: %s", strerror(errno));
  56 + }
  57 +
  58 + return ret;
  59 +}
  60 +
  61 +/* this handles simple %d and %s replacements,
  62 + * complexer stuff must be prepared via snprintf
  63 + * the complete message should not extend 1024
  64 + * Bytes, else it will be truncated silently */
  65 +int
  66 +syslogMonitor(
  67 + unsigned int logLvl,
  68 + unsigned int sev,
  69 + const char * pattern,
  70 + const char * message,
  71 + ...
  72 +) {
  73 + va_list args;
  74 + char buffer[1025];
  75 + int maxBuf = sizeof(buffer)/sizeof(buffer[0]);
  76 +
  77 + memset(buffer, 0, maxBuf);
  78 +
  79 + va_start(args, message);
  80 + vsnprintf(buffer, 1024, message, args);
  81 + va_end(args);
  82 +
  83 + syslog(logLvl, "%s", buffer);
  84 + monitor(sev, pattern, buffer);
  85 +
  86 + return 0;
  87 +}
  1 +#include <signal.h> /* for signal() and signal names */
  2 +
  3 +#include "../include/monitor.h"
  4 +
  5 +volatile int doShutdown;
  6 +
  7 +void terminate(int signum)
  8 +{
  9 + signal(signum, SIG_IGN);
  10 + syslogMonitor(LOG_INFO, MON_INFO, "signals",
  11 + "caugth deadly signal %d, service terminated", signum);
  12 + doShutdown = 1;
  13 +}
  14 +
  15 +void init_signals(void)
  16 +{
  17 + signal(SIGTERM, terminate);
  18 + signal(SIGHUP, SIG_IGN);
  19 + signal(SIGINT, terminate);
  20 + signal(SIGQUIT, terminate);
  21 + signal(SIGABRT, terminate);
  22 + signal(SIGALRM, SIG_IGN);
  23 + signal(SIGURG, SIG_IGN);
  24 +
  25 + signal(SIGPIPE, SIG_IGN);
  26 +}
  1 +#include <stdio.h> /* for printf() and fprintf() */
  2 +#include <sys/socket.h> /* for socket(), bind(), and connect() */
  3 +#include <arpa/inet.h> /* for sockaddr_in and inet_ntoa() */
  4 +#include <stdlib.h> /* for atoi() and exit() */
  5 +#include <string.h> /* for memset() */
  6 +#include <unistd.h> /* for close() */
  7 +#include <errno.h> /* for errno */
  8 +#include <syslog.h>
  9 +
  10 +#include "../include/monitor.h"
  11 +
  12 +
  13 +extern int verbose;
  14 +
  15 +int initServerSocket(in_port_t port, int backlog) {
  16 + int sock; /* socket descriptor for server */
  17 + struct sockaddr_in addr; /* Local address */
  18 +
  19 + /* Create socket for incoming connections */
  20 + if (-1 == (sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
  21 + syslogMonitor(LOG_ERR, MON_INFO, "server.socket",
  22 + "error opening socket: %s - service terminated",
  23 + strerror(errno));
  24 + exit(EXIT_FAILURE);
  25 + }
  26 +
  27 + /* Construct local address structure */
  28 + memset(&addr, 0, sizeof(addr)); /* Zero out structure */
  29 +
  30 + addr.sin_family = AF_INET; /* Internet address family */
  31 + addr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
  32 + addr.sin_port = htons(port); /* Local port */
  33 +
  34 + /* Bind to the local address */
  35 + if (-1 == bind(sock, (struct sockaddr *) &addr, sizeof(addr))) {
  36 + syslogMonitor(LOG_ERR, MON_INFO, "server.bind",
  37 + "error binding socket: %s - service terminated",
  38 + strerror(errno));
  39 + exit(EXIT_FAILURE);
  40 + }
  41 +
  42 + /* Mark the socket so it will listen for incoming connections */
  43 + if (-1 == listen(sock, backlog)) {
  44 + syslogMonitor(LOG_ERR, MON_INFO, "server.listen",
  45 + "error binding socket: %s - service terminated",
  46 + strerror(errno));
  47 + exit(EXIT_FAILURE);
  48 + }
  49 +
  50 + return sock;
  51 +}
  52 +
  53 +int acceptConnection(int servSock, char remoteAddr[16]) {
  54 + int sock; /* Socket descriptor for client */
  55 + struct sockaddr_in addr; /* Client address */
  56 + unsigned int len; /* Length of client address data structure */
  57 +
  58 + /* Set the size of the in-out parameter */
  59 + len = sizeof(addr);
  60 +
  61 + /* Wait for a client to connect */
  62 + if (-1 == (sock = accept(servSock, (struct sockaddr *) &addr, &len))) {
  63 + syslogMonitor(LOG_ERR, MON_INFO, "server.accept",
  64 + "error acception connection: %s", strerror(errno));
  65 + } else {
  66 + strncpy (remoteAddr, inet_ntoa(addr.sin_addr), sizeof(remoteAddr)-1);
  67 + }
  68 +
  69 + /* clntSock is connected to a client! */
  70 + if (0 != verbose) {
  71 + syslog(LOG_INFO, "handling client %s\n", inet_ntoa(addr.sin_addr));
  72 + }
  73 +
  74 + return sock;
  75 +}
  1 +#include <string.h> /* for memset and stuff */
  2 +#include <syslog.h> /* for logging */
  3 +
  4 +#include "include/server.h"
  5 +#include "include/monitor.h"
  6 +#include "include/signalHandling.h"
  7 +#include "include/appConfig.h"
  8 +#include "include/daemonize.h"
  9 +
  10 +int verbose;
  11 +
  12 +
  13 +int main(int argc, char *argv[])
  14 +{
  15 + tServer server;
  16 +
  17 + tAppConfig appConfig = {
  18 + 0,
  19 + 0,
  20 + MAXPENDING,
  21 + DEFAULTPORT,
  22 + DEFAULTPATH,
  23 + LOGNAMEPATTERN
  24 + };
  25 +
  26 + memset(&server, 0, sizeof(server));
  27 +
  28 + handleCmdLine(&appConfig, argc, argv);
  29 + verbose = appConfig.verbose;
  30 +
  31 + /* decouple procss from controlling shell and make it session leader */
  32 + if (appConfig.doDaemon) {
  33 + daemonize();
  34 + }
  35 + init_signals();
  36 + openlog(argv[0], LOG_PID, LOG_USER);
  37 +
  38 + syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");
  39 +
  40 + serverInit(
  41 + &server,
  42 + appConfig.port,
  43 + appConfig.maxPending,
  44 + appConfig.logPath,
  45 + appConfig.namePat);
  46 + serverRun(&server);
  47 + serverShutdown(&server);
  48 +
  49 + return 0;
  50 +}
Please register or login to post a comment