serverRun.c 4.31 KB
#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 "include/server.h"
#include "include/socket.h"
#include "include/monitor.h"
#include "include/signalHandling.h"

#undef  MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))

void
serverRun(tVirtualItemServer * server)
{
    syslogMonitor(LOG_INFO, MON_INFO, "startup", "service started");

    while (!doShutdown) /* until error or signal  */
    {
        fd_set rfds;
        int    i;

        memcpy(&rfds, &(server->socks), sizeof(fd_set));

        /*
         * wait for handles to become ready
         */
        if (-1 == select((server->maxFd)+1, &rfds, NULL, NULL, NULL))
        {
            switch (errno) {
                default:
                case EBADF:
                case EINVAL:
                case ENOMEM:
                     doShutdown = 1;
                     /* Fallthrough */

                case EINTR:
                     syslogMonitor(LOG_ERR, MON_CRITICAL, "select",
                                   "select systemcall failed: [%s]",
                                   strerror(errno));
                     syslogMonitor(LOG_ERR, MON_FAILURE, "select",
                                   "select systemcall failed: [%s] - service terminated",
                                   strerror(errno));
                     continue; /* in while loop above */
            }
        }

        /*
         * update file to actual time
         */
        logRotate(server);
        if (NULL == server->wHandle) {
            syslogMonitor(LOG_ERR, MON_CRITICAL, "logfile.rotate",
                          "no valid handle for logfile - service terminated");
            exit(EXIT_FAILURE);
        }

        /*
         * 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);
            }

            FD_CLR(server->servSock, &rfds);
        }

        /* handle reads */
        for (i=3; i<=server->maxFd; i++) {
            if (FD_ISSET(i, &rfds)) {
                switch (clientRead(&((server->clients)[i]))) {
                    case 0:
                        /*
                         * normal close: write remaining data
                         */
                        writeRemaining(
                                    &((server->clients)[i]),
                                    server->wHandle);
                        /* FALLTHROUGH */

                    case -1: 
                        /*
                         * read failure / close connection
                         * FALLTHROUGH
                         */

                    case READ_ERR_LONGLINE:
                        /*
                         * detected very long line read from client
                         * message is already given now terminate connection
                         * FALLTHROUG
                         */
                        clientClose(&((server->clients)[i]));
                        FD_CLR(i, &(server->socks));
                        break;

                    default:
                        if (0 > writeBuffer(
                                    &((server->clients)[i]),
                                    server->wHandle))
                        {
                            /*
                             * got IO Error or binary data
                             * the message is already monitored in client code
                             */
                            clientClose(&((server->clients)[i]));
                            FD_CLR(i, &(server->socks));
                        }
                        break;
                }
            }
        }
    }
}