Showing
32 changed files
with
1687 additions
and
0 deletions
Makefile
0 → 100644
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 |
TODO
0 → 100644
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... |
include/appConfig.h
0 → 100644
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__ |
include/client.h
0 → 100644
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__ |
include/daemonize.h
0 → 100644
include/httpRequest.h
0 → 100644
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__ |
include/logRotate.h
0 → 100644
include/monitor.h
0 → 100644
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__ */ |
include/my.patch
0 → 100644
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__ |
include/server.h
0 → 100644
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__ |
include/signalHandling.h
0 → 100644
include/socket.h
0 → 100644
include/writeBuffer.h
0 → 100644
reader/Makefile
0 → 100644
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 |
reader/commonReader/Makefile
0 → 100644
reader/commonReader/clientClose.c
0 → 100644
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 | +} |
reader/commonReader/clientRead.c
0 → 100644
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 | +} |
reader/commonReader/writeBuffer.c
0 → 100644
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 | +} |
reader/httpReader/Makefile
0 → 100644
reader/httpReader/httpRequest.c
0 → 100644
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 | +} |
server/Makefile
0 → 100644
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 |
server/serverInit.c
0 → 100644
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 | +} |
server/serverRun.c
0 → 100644
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 | +} |
server/serverShutdown.c
0 → 100644
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 | +} |
system/Makefile
0 → 100644
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 |
system/daemonize.c
0 → 100644
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 | +} |
system/handleCmdLine.c
0 → 100644
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 | +} |
system/logRotate.c
0 → 100644
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 | +} |
system/monitor.c
0 → 100644
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 | +} |
system/signalHandling.c
0 → 100644
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 | +} |
system/socket.c
0 → 100644
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 | +} |
xmlrpc.c
0 → 100644
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