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