server_run.c 2.49 KB
#include <poll.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 <unistd.h>

#include "include/logger.h"
#include "include/server.h"
#include "include/socket.h"
#include "include/signalHandling.h"

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

static
int
server_select(SERVER this) {
	int events;

	/*
	 * wait for handles to become ready
	 */
	if (-1 == (events = poll(this->fds, this->nfds, -1))) {
		switch (errno) {
			default:
			case EBADF:
			case EINVAL:
			case ENOMEM:
				doShutdown = 1;
				/* Fallthrough */

			case EINTR:
				logger_log(this->logger, LOGGER_CRIT,
						"poll systemcall failed: [%s] - service terminated",
						strerror(errno));
				//exit(EXIT_FAILURE); /* @TODO do real shutdown here */
		}
	}

	return events;
}

static
void
server_handle_accept(SERVER this)
{
	if (0 != ((this->fds)[0].revents & POLLIN)) {
		char remoteAddr[16] = "";
		SOCK acc;

		acc = sock_accept(this->sock, remoteAddr);

		if (-1 != acc->handle) {
			(this->conns)[this->nfds].sock = acc; // save the socket handle
			(this->fds)[this->nfds].fd     = acc->handle;
			(this->fds)[this->nfds].events = POLLIN;
			this->nfds++;
		} else {
			delete(&acc);
		}

		(this->fds)[0].revents |= POLLIN;
	}
}

static
int
server_read(SERVER this)
{
	unsigned int i;
	size_t       _read;
	char         buffer[1024];

	for (i=1; i<this->nfds; i++) {
		if (0 != ((this->fds)[i].revents & POLLIN)) {
			memset(buffer, 0, 1024);
			switch (_read = read((this->fds)[i].fd, buffer, 1023)) {
				case 0:
					/*
					 * normal close: write remaining data
					 */
					/* FALLTHROUGH */

				case -1: 
					/*
					 * read failure / close connection
					 * FALLTHROUGH
					 */
					server_close_conn(this, i);
					break;

				default:
					(this->fds)[i].revents |= POLLIN;
					if (NULL != this->read_hook) {
						this->read_hook(buffer);
					}
					break;
			}
		}
	}
	
	return 0;
}

void
server_run(SERVER this)
{
	/*
	 * @TODO again...add verbosity to logger....
	 */
    logger_log(this->logger, LOGGER_INFO, "service started");

    while (!doShutdown) /* until error or signal  */
    {
		int events;
		/*
		 * @TODO take return value of poll into account with
		 * further handling!
		 */
		events = server_select(this);
		if (doShutdown) break;

        /*
         * handle accept
         */
		server_handle_accept(this);

        /* handle reads */
		server_read(this);
    }
}

// vim: set ts=4 sw=4: