An xmlrpc test project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

238 lines
8.8 KiB

#include <sys/select.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for exit */
#include <errno.h> /* for errno */
#include <unistd.h> /* for write */
#include <expat.h>
#include "../include/appConfig.h"
#include "../include/server.h"
#include "../include/client.h"
#include "../include/socket.h"
#include "../include/monitor.h"
#include "../include/logRotate.h"
#include "../include/signalHandling.h"
#include "../include/httpRequest.h"
#define RESPONSE " 200 OK\r\nServer: xmlrpc\r\nStatus: 200\r\nContent-Length: 10\r\nContent-Type: text/plain\r\n\r\n0123456789"
int Depth;
void XMLCALL
start(void *data, const char *el, const char **attr) {
int i;
for (i = 0; i < Depth; i++)
printf(" ");
printf("%s", el);
for (i = 0; attr[i]; i += 2) {
printf(" %s='%s'", attr[i], attr[i + 1]);
}
printf("\n");
Depth++;
} /* End of start handler */
void XMLCALL
end(void *data, const char *el) {
int i;
Depth--;
for (i = 0; i < Depth; i++)
printf(" ");
printf("--\n");
} /* End of end handler */
void
serverRun(tServer * server)
{
syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");
while (!doShutdown) /* until error or signal */
{
fd_set rfds;
fd_set wfds;
int i;
memcpy(&rfds, &(server->socks), sizeof(fd_set));
FD_ZERO(&wfds);
for (i=3; i<=server->maxFd; i++) {
tClient * actClient = &(server->clients)[i];
if (FD_ISSET(i, &(server->socks))
&& NULL != actClient->writeBuffer
&& 0 != strlen(actClient->writeBuffer)) {
FD_SET(i, &wfds);
}
}
/*
* wait for handles to become ready
*/
if (-1 == select((server->maxFd)+1, &rfds, &wfds, NULL, NULL))
{
switch (errno) {
default:
case EBADF:
case EINVAL:
case ENOMEM:
doShutdown = 1;
/* Fallthrough */
case EINTR:
syslogMonitor(LOG_ERR, MON_INFO, "select",
"select systemcall failed: [%s] - service terminated",
strerror(errno));
continue; /* in while loop above */
}
}
/*
* handle accept
*/
if (FD_ISSET(server->servSock, &rfds)) {
int fd;
char remoteAddr[16] = "";
if (-1 != (fd = acceptConnection(server->servSock, remoteAddr))) {
(server->clients)[fd].socket = fd; // save the socket handle within the client struct
strncpy(
(server->clients)[fd].remoteAddr,
remoteAddr,
sizeof((server->clients)[fd].remoteAddr)-1);
FD_SET(fd, &(server->socks));
server->maxFd = MAX(fd, server->maxFd);
(server->clients)[fd].parser = XML_ParserCreate("UTF-8");
XML_SetElementHandler((server->clients)[fd].parser, &start, &end);
}
FD_CLR(server->servSock, &rfds);
}
/* handle reads (max 10 before next select, else we block accept for to long) */
for (i=3; i<=server->maxFd; i++) {
// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
tClient * actClient = &(server->clients)[i];
if (FD_ISSET(i, &rfds)) {
switch (clientRead(actClient)) {
case -1:
syslogMonitor(LOG_WARNING, MON_INFO, "socket.read",
"read on socket for %s returns -1: %s",
actClient->remoteAddr, strerror(errno));
/* FALLTHROUGH */
case 0:
clientClose(actClient);
FD_CLR(i, &(server->socks));
break;
default:
if (! httpHeaderIsComplete(&(actClient->httpHeader))) {
char delim[] = "\r\n";
unsigned int len = strlen(delim);
char * line = clientGetLine(actClient, delim, &len);
/*
* len might be 0, thus indicatin an empty line
* this might happen in two cases
* 1. when a header is not already started
* (could be identifies by a null req.method
* 2. if a header is started, then it indicates
* the end of the header.
*/
while (! httpHeaderIsStarted(&(actClient->httpHeader))) {
if (0 != len) {
httpHeaderParseRequestLine(&(actClient->httpHeader), line, len);
// TODO: do some error handling here
}
len = strlen(delim);
clientRemoveLine(actClient, delim, &len); // TODO: do some error handling here
len = strlen(delim);
line = clientGetLine(actClient, delim, &len);
}
while (NULL != line) {
if (NULL == actClient->httpHeader.req.method) {
}
}
}
if (!httpHeaderIsComplete(&(actClient->httpHeader))) {
actClient->bodyLenRemaining = httpHeaderGet(
&(actClient->readBuffer),
&(actClient->readPos),
&(actClient->httpHeader));
}
if (httpHeaderIsComplete(&(actClient->httpHeader))) {
size_t size = MIN(actClient->bodyLenRemaining, actClient->readPos);
unsigned int isLast = !(size - actClient->bodyLenRemaining);
enum XML_Status expatStat;
expatStat = XML_Parse(actClient->parser, actClient->readBuffer, size, isLast);
actClient->readPos -= size;
actClient->bodyLenRemaining -= size;
memmove(actClient->readBuffer, actClient->readBuffer + size, actClient->readPos);
memset(actClient->readBuffer + actClient->readPos, 0, size);
if (isLast && NULL == actClient->writeBuffer) {
actClient->writeBuffer = calloc(
strlen(actClient->httpHeader.req.httpVersion) +
strlen(RESPONSE) + 3,
sizeof(char));
sprintf(actClient->writeBuffer, "%s%s",
actClient->httpHeader.req.httpVersion,
RESPONSE);
freeHttpHeader(&(actClient->httpHeader));
XML_ParserFree(actClient->parser);
actClient->parser = NULL;
}
}
break;
}
}
}
/* handle writes */
for (i=3; i<=server->maxFd; i++) {
// for (i=3, count=0; i<=server->maxFd && count<10; i++, count++) {
tClient * actClient = &(server->clients)[i];
// TODO: the && is only symptom fix...need to find real bug.
if (FD_ISSET(i, &wfds) && NULL != actClient->writeBuffer) {
int writeSize = 0;
int toWrite = strlen(actClient->writeBuffer);
writeSize = write(actClient->socket, actClient->writeBuffer, toWrite);
if (0 < writeSize) {
if (writeSize == toWrite) {
free(actClient->writeBuffer);
actClient->writeBuffer = NULL;
clientClose(actClient);
FD_CLR(i, &(server->socks));
} else {
memmove(actClient->writeBuffer, actClient->writeBuffer + writeSize, toWrite - writeSize);
memset(actClient->writeBuffer + (toWrite - writeSize), 0, writeSize);
}
}
}
}
}
}