#include /* for getopt */ #include /* for exit */ #include /* for memset and stuff */ #include /* for errno */ #include "../../include/client.h" #include "../../include/monitor.h" #define GET_MULTIPLIER(size) (((size) - 1) / READBUFSIZE + 1) static int _clientReallocBuffer(tClient * client, unsigned int newSize) { unsigned int newMult = GET_MULTIPLIER(newSize); if (CLIENTMULTMAX < newMult) { /* line exceeds maximum line length */ return 0; } if (client->readBufMult < newMult) { char * newBuffer = calloc(newMult * READBUFSIZE, sizeof(char)); if (NULL == newBuffer) { syslogMonitor(LOG_ERR, MON_CRITICAL, "calloc", "calloc for readbuffer[%s] failed", client->remoteAddr); exit(EXIT_FAILURE); } if (NULL != client->readBuffer) { memcpy(newBuffer, client->readBuffer, client->readPos); free(client->readBuffer); client->readBuffer = newBuffer; client->readBufMult = newMult; } else { /* * we can't get the resized buffer so return the * old multiplier */ newMult = client->readBufMult; } } return newMult; } int clientRead(tClient * client) { int readSize; char readBuf[READBUFSIZE]; /* * initialize values // read data from socket */ memset(readBuf, 0, READBUFSIZE); readSize = read(client->socket, readBuf, READBUFSIZE); switch (readSize) { case -1: syslogMonitor(LOG_WARNING, MON_WARNING, "socket.read", "read returns -1 for client[%s]: %s - connection closed", client->remoteAddr, strerror(errno)); break; case 0: break; default: if (!_clientReallocBuffer(client, client->readPos + readSize)) { syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline", "got to long line from client[%s] - connection closed", client->remoteAddr); return READ_ERR_LONGLINE; } if (client->readPos +readSize > client->readBufMult *READBUFSIZE) { syslogMonitor(LOG_WARNING, MON_WARNING, "data.longline", "can't allocate enough memory for read on client[%s]" " - connection closed", client->remoteAddr); return READ_ERR_MEMORY; } memcpy(client->readBuffer+client->readPos, readBuf, readSize); client->readPos += readSize; break; } return readSize; } #define EOB(client,addr) ((addr) -(client)->readBuffer >= (client)->readPos) #define REMAINING(client,addr) ((client)->readPos - ((addr) - (client)->readBuffer)) static char * _clientGetLineDelimiter(tClient * client, const char * delim, unsigned int len) { char * foundDelim = memchr(client->readBuffer, delim[0], client->readPos); while (NULL != foundDelim && !EOB(client, foundDelim)) { unsigned int i = 0; while (i < len && !EOB(client, &(foundDelim[i])) && foundDelim[i] == delim[i]) i++; if (i == len) { return foundDelim; } else { if (!EOB(client, ++foundDelim)) { foundDelim = memchr(foundDelim, delim[0], REMAINING(client, foundDelim)); } } } return NULL; } /* * this returns a newly allocate buffer, with the found line * copied to it. * The caller has to take care to free this buffer again, * after he uses it. */ char * clientConsumeLine(tClient * client, const char * delim, unsigned int * len) { char * found = clientGetLine(client, delim, len); char * line = NULL; if (NULL != found) { line = calloc(*len +1, sizeof(char)); clientRemoveLine(client, delim, len); memcpy(line, found, *len); } return line; } /* * as a side effect this gives sets length of the found line in len */ char * clientGetLine(tClient * client, const char * delim, unsigned int * len) { char * foundDelim = _clientGetLineDelimiter(client, delim, *len); if (NULL != foundDelim) { *len = foundDelim -client->readBuffer -1; return client->readBuffer; } return NULL; } char * clientRemoveLine(tClient * client, const char * delim, unsigned int * len) { unsigned int lineLen; char * foundDelim = _clientGetLineDelimiter(client, delim, &lineLen); if (NULL != foundDelim) { char * actAddr = client->readBuffer +client->readPos; if (actAddr == foundDelim +*len) { memset(client->readBuffer, 0, client->readPos); *len = client->readPos = 0; } else { unsigned int moveSize = actAddr -foundDelim -*len; unsigned int clearSize = actAddr -client->readBuffer -moveSize; memmove(client->readBuffer, foundDelim +*len, moveSize); memset(client->readBuffer +moveSize, 0, clearSize); *len = client->readPos = moveSize; } return client->readBuffer; } return NULL; }