clientRead.c 5.18 KB
#include <unistd.h>     /* for getopt */
#include <stdlib.h>     /* for exit */
#include <string.h>     /* for memset and stuff */
#include <errno.h>      /* 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;
}