writeBuffer.c 3.51 KB
#include <stdio.h>      /* for ferror() */
#include <string.h>     /* for memset and stuff */
#include <errno.h>      /* for errno */
#include <ctype.h>      /* for isprint */

#include "include/client.h"
#include "include/monitor.h"

int
_handleIoError(FILE * wHandle)
{
    if (ferror(wHandle)) {
        switch (errno) {
            case EIO:
                /* FALLTHROUGHT */

            case ENOSPC:
                syslogMonitor(LOG_ERR, MON_CRITICAL, "io.fatal",
                        "fatal IO error [%s]",
                        strerror(errno));

                syslogMonitor(LOG_ERR, MON_FAILURE, "io.fatal",
                        "fatal IO error [%s] - service terminated",
                        strerror(errno));

                break;
        }

        return 1;
    }

    return 0;
}

int
_isPrintableBuffer(const char * buffer, size_t size, char * found)
{
    while (isprint(*(buffer++)) && 1 < size--);

    if (0 == size) {
        return 1;
    } else {
        *found = *(buffer-1);
        return 0;
    }
}

int
_doWrite(tClient * client, size_t size, FILE * wHandle)
{
    char found = '\0';

    if (NULL != client->buffer) {

        if (!_isPrintableBuffer(client->buffer, size, &found)) {
            syslogMonitor(LOG_ERR, MON_WARNING, "data.binary",
                    "got non printable character[0x%02x] from client[%s] - connection closed",
                    found,
                    client->remoteAddr);

            return WRITE_ERR_NOPRINT;
        }

        /* write remaining stuff to file */
        fwrite(client->buffer, size, 1, wHandle);
        if (_handleIoError(wHandle)) {
            return WRITE_ERR_IO;
        }

        fputc('\n', wHandle);
        if (_handleIoError(wHandle)) {
            return WRITE_ERR_IO;
        }

        fflush(wHandle);
        if (_handleIoError(wHandle)) {
            return WRITE_ERR_IO;
        }

        return size + 1;

    } else {

        return 0;

    }
}

/*
 * write all data that remains in buffer, even if its not terminated by
 * a newline. Anyway ignore trailing newlines.
 */
int
writeRemaining(tClient * client, FILE * wHandle)
{
    int written = writeBuffer(client, wHandle);

    if (0 < client->readPos) {
        unsigned int wLen = client->readPos;

        /* ignore trailing newlines */
        while (0 < client->readPos && '\n' == client->buffer[wLen]) {
            wLen--;
        }

        written += _doWrite(client, wLen, wHandle);
    }

    memset(client->buffer, 0, client->readPos);
    client->readPos = 0;

    return written;
}

/*
 * write buffer till last newline is reached.
 * If no newline is in buffer, nothing is written.
 */
int
writeBuffer(tClient * client, FILE * wHandle)
{
    char * nlpos   = memchr(client->buffer, '\n', client->readPos);
    int    written = 0;

    while (NULL != nlpos) {
        unsigned int moveSize, clearSize;
        char *       actAddr;

        if (nlpos > client->buffer) {
            unsigned int wLen  = nlpos - client->buffer;
            int          wTemp = _doWrite(client, wLen, wHandle);

            if (0 > wTemp) {
                return wTemp;
            }

            written += wTemp;
        }

        actAddr    = client->buffer + client->readPos;
        moveSize   = actAddr - nlpos - 1;
        clearSize  = actAddr - client->buffer - moveSize;

        memmove(client->buffer, nlpos+1, moveSize);
        memset(client->buffer + moveSize, 0, clearSize);

        client->readPos = moveSize;

        nlpos = memchr(client->buffer, '\n', client->readPos);
    }

    return written;
}