Browse Source

changed from select(UNIX) to poll(POSIX)

master
Georg Hopp 14 years ago
parent
commit
c33578329c
  1. 19
      include/server.h
  2. 25
      src/server.c
  3. 12
      src/server_close_conn.c
  4. 67
      src/server_run.c
  5. 12
      src/socket_accept.c
  6. 16
      tests/Makefile.am
  7. 58
      tests/serverTest.c
  8. 3
      tests/socketTest.c

19
include/server.h

@ -2,20 +2,24 @@
#define __SERVER_H__ #define __SERVER_H__
#include <stdio.h> /* for printf() and fprintf() */ #include <stdio.h> /* for printf() and fprintf() */
#include <sys/select.h> /* for select system call and related */
#include <poll.h> /* for select system call and related */
#include "socket.h" #include "socket.h"
#include "logger.h" #include "logger.h"
#include "cclass.h" #include "cclass.h"
#define POLL_FD_NSIZE 1024
#define POLL_FD_SIZE (sizeof(struct pollfd) * POLL_FD_NSIZE)
#define POLL_FD_MOVE(idx) (sizeof(struct pollfd) * (POLL_FD_NSIZE-(idx)+1))
typedef void (*server_read_hook)(const char *); typedef void (*server_read_hook)(const char *);
CLASS(SERVER) { CLASS(SERVER) {
LOGGER logger;
SOCK sock;
unsigned int max_fd;
fd_set fdset;
LOGGER logger;
SOCK sock;
nfds_t nfds;
struct pollfd fds[POLL_FD_NSIZE];
struct { struct {
SOCK sock; SOCK sock;
@ -23,14 +27,13 @@ CLASS(SERVER) {
char * rbuf; char * rbuf;
unsigned int rpos; unsigned int rpos;
unsigned int wpos; unsigned int wpos;
} conns[FD_SETSIZE];
} conns[POLL_FD_NSIZE];
server_read_hook read_hook; server_read_hook read_hook;
}; };
void server_run(SERVER this); void server_run(SERVER this);
//void server_close(SERVER this);
//void server_shutdown(SERVER this);
void server_close_conn(SERVER this, unsigned int handle);
#endif // __SERVER_H__ #endif // __SERVER_H__

25
src/server.c

@ -1,4 +1,4 @@
#include <sys/select.h> /* for select system call and related */
#include <poll.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */ #include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for getopt */ #include <stdlib.h> /* for getopt */
@ -8,7 +8,6 @@
#include "logger.h" #include "logger.h"
#include "cclass.h" #include "cclass.h"
INIT_CLASS(SERVER); INIT_CLASS(SERVER);
__construct(SERVER) __construct(SERVER)
@ -20,27 +19,23 @@ __construct(SERVER)
port = va_arg(* params, int); port = va_arg(* params, int);
backlog = va_arg(* params, unsigned int); backlog = va_arg(* params, unsigned int);
FD_ZERO(&(this->fdset));
this->sock = new(SOCK, port);
this->sock = new(SOCK, this->logger, port);
sock_listen(this->sock, backlog); sock_listen(this->sock, backlog);
this->max_fd = this->sock->handle;
FD_SET(this->sock->handle, &(this->fdset));
(this->fds)[0].fd = this->sock->handle;
(this->fds)[0].events = POLLIN;
this->nfds = 1;
} }
__destruct(SERVER) __destruct(SERVER)
{ {
int i; int i;
for (i=3; i<=this->max_fd; i++) {
if (FD_ISSET(i, &(this->fdset)) && i != this->sock->handle) {
/*
* @TODO do some finalization...buffer handling...etc.
*/
delete(&(this->conns[i]).sock);
FD_CLR(i, &(this->fdset));
}
for (i=1; i<this->nfds; i++) {
/*
* @TODO do some finalization...buffer handling...etc.
*/
delete(&(this->conns[i]).sock);
} }
delete(&this->sock); delete(&this->sock);

12
src/server_close_conn.c

@ -0,0 +1,12 @@
#include "server.h"
void
server_close_conn(SERVER this, unsigned int i)
{
memmove(&((this->fds)[i]), &((this->fds)[i+1]), POLL_FD_MOVE(i+1));
this->nfds--;
delete(&((this->conns)[i].sock));
}
// vim: set ts=4 sw=4:

67
src/server_run.c

@ -1,4 +1,4 @@
#include <sys/select.h> /* for select system call and related */
#include <poll.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */ #include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for exit */ #include <stdlib.h> /* for exit */
#include <errno.h> /* for errno */ #include <errno.h> /* for errno */
@ -13,17 +13,14 @@
#define MAX(x,y) ((x) > (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y))
static static
fd_set
int
server_select(SERVER this) { server_select(SERVER this) {
fd_set rfds;
memcpy(&rfds, &(this->fdset), sizeof(fd_set));
int events;
/* /*
* wait for handles to become ready * wait for handles to become ready
*/ */
if (-1 == select((this->max_fd)+1, &rfds, NULL, NULL, NULL))
{
if (-1 == (events = poll(this->fds, this->nfds, -1))) {
switch (errno) { switch (errno) {
default: default:
case EBADF: case EBADF:
@ -36,56 +33,48 @@ server_select(SERVER this) {
logger_log(this->logger, LOGGER_CRIT, logger_log(this->logger, LOGGER_CRIT,
"select systemcall failed: [%s] - service terminated", "select systemcall failed: [%s] - service terminated",
strerror(errno)); strerror(errno));
exit(EXIT_FAILURE); /* @TODO do real shutdown here */
//exit(EXIT_FAILURE); /* @TODO do real shutdown here */
} }
} }
return rfds;
return events;
} }
static static
void void
server_handle_accept(SERVER this, fd_set * rfds)
server_handle_accept(SERVER this)
{ {
if (FD_ISSET(this->sock->handle, rfds)) {
int fd;
if (0 != ((this->fds)[0].revents & POLLIN)) {
char remoteAddr[16] = ""; char remoteAddr[16] = "";
SOCK acc; SOCK acc;
acc = sock_accept(this->sock, remoteAddr); acc = sock_accept(this->sock, remoteAddr);
if (-1 != acc->handle) { if (-1 != acc->handle) {
((this->conns)[acc->handle].sock)->handle = fd; // save the socket handle
FD_SET(fd, &(this->fdset));
this->max_fd = MAX(fd, this->max_fd);
(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 { } else {
delete(&acc); delete(&acc);
} }
FD_CLR(this->sock->handle, rfds);
(this->fds)[0].revents |= POLLIN;
} }
} }
static
void
server_close_conn(SERVER this, unsigned int handle)
{
delete(&((this->conns)[handle].sock));
FD_CLR(handle, &(this->fdset));
}
static static
int int
server_read(SERVER this, fd_set * rfds)
server_read(SERVER this)
{ {
unsigned int i; unsigned int i;
size_t _read;
char buffer[1024];
size_t _read;
char buffer[1024];
for (i=3; i<=this->max_fd; i++) {
if (FD_ISSET(i, rfds)) {
for (i=1; i<this->nfds; i++) {
if (0 != ((this->fds)[i].revents & POLLIN)) {
memset(buffer, 0, 1024); memset(buffer, 0, 1024);
switch (_read = read(i, buffer, 1023)) {
switch (_read = read((this->fds)[i].fd, buffer, 1023)) {
case 0: case 0:
/* /*
* normal close: write remaining data * normal close: write remaining data
@ -101,6 +90,7 @@ server_read(SERVER this, fd_set * rfds)
break; break;
default: default:
(this->fds)[i].revents |= POLLIN;
if (NULL != this->read_hook) { if (NULL != this->read_hook) {
this->read_hook(buffer); this->read_hook(buffer);
} }
@ -116,24 +106,27 @@ void
server_run(SERVER this) server_run(SERVER this)
{ {
/* /*
* @TODO again a hint...add verbosity to logger....
* @TODO again...add verbosity to logger....
*/ */
logger_log(this->logger, LOGGER_INFO, "service started"); logger_log(this->logger, LOGGER_INFO, "service started");
while (!doShutdown) /* until error or signal */ while (!doShutdown) /* until error or signal */
{ {
fd_set rfds;
int i;
rfds = server_select(this);
int events;
/*
* @TODO take return value of poll into account with
* further handling!
*/
events = server_select(this);
if (doShutdown) break;
/* /*
* handle accept * handle accept
*/ */
server_handle_accept(this, &rfds);
server_handle_accept(this);
/* handle reads */ /* handle reads */
server_read(this, &rfds);
server_read(this);
} }
} }

12
src/socket_accept.c

@ -32,17 +32,9 @@ sock_accept(SOCK this, char remoteAddr[16])
logger_log(this->logger, LOGGER_WARNING, logger_log(this->logger, LOGGER_WARNING,
"error acception connection: %s", strerror(errno)); "error acception connection: %s", strerror(errno));
} else { } else {
strncpy (remoteAddr, inet_ntoa((sock->addr).sin_addr), sizeof(remoteAddr)-1);
}
/* clntSock is connected to a client! */
/**
* @TODO add verbosity level to logger
*/
// if (0 != this->logger->verbose) {
logger_log(this->logger, LOGGER_INFO, logger_log(this->logger, LOGGER_INFO,
"handling client %s\n", inet_ntoa((this->addr).sin_addr));
// }
"handling client %s\n", inet_ntoa((sock->addr).sin_addr));
}
return sock; return sock;
} }

16
tests/Makefile.am

@ -4,18 +4,24 @@ TESTS_ENVIRONMENT = valgrind --error-exitcode=123 --leak-check=full --quiet
TESTS = cclassTest loggerTest socketTest serverTest TESTS = cclassTest loggerTest socketTest serverTest
check_PROGRAMS = cclassTest loggerTest socketTest serverTest check_PROGRAMS = cclassTest loggerTest socketTest serverTest
SOURCES = runtest.c ../src/cclass.c
COMMON = runtest.c ../src/cclass.c
CCLASS = $(COMMON) mock/class.c
LOGGER = $(COMMON) ../src/logger.c
SOCKET = $(LOGGER) ../src/socket.c ../src/socket_listen.c \
../src/socket_accept.c ../src/socket_connect.c
SERVER = $(SOCKET) ../src/server.c ../src/server_run.c \
../src/server_close_conn.c ../src/signalHandling.c
cclassTest_SOURCES = $(SOURCES) cclassTest.c mock/class.c
cclassTest_SOURCES = $(CCLASS) cclassTest.c
cclassTest_CFLAGS = -Wall -ggdb -O0 -finline-functions -I ../include -I .. -I . cclassTest_CFLAGS = -Wall -ggdb -O0 -finline-functions -I ../include -I .. -I .
loggerTest_SOURCES = $(SOURCES) loggerTest.c ../src/logger.c
loggerTest_SOURCES = $(LOGGER) loggerTest.c
loggerTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I . loggerTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I .
socketTest_SOURCES = $(SOURCES) socketTest.c ../src/logger.c ../src/socket.c ../src/socket_listen.c ../src/socket_accept.c ../src/socket_connect.c
socketTest_SOURCES = $(SOCKET) socketTest.c
socketTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I . socketTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I .
serverTest_SOURCES = $(SOURCES) serverTest.c ../src/logger.c ../src/socket.c ../src/socket_listen.c ../src/socket_accept.c ../src/server.c ../src/server_run.c ../src/signalHandling.c
serverTest_SOURCES = $(SERVER) serverTest.c
serverTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I . serverTest_CFLAGS = -Wall -ggdb -O0 -I ../include -I .. -I .
EXTRA_DIST = runtest.h mock/class.h EXTRA_DIST = runtest.h mock/class.h

58
tests/serverTest.c

@ -1,34 +1,38 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "runtest.h" #include "runtest.h"
#include "logger.h" #include "logger.h"
#include "cclass.h" #include "cclass.h"
#include "server.h" #include "server.h"
#include "signalHandling.h"
#define TEST_PORT 11212
#define TEST_PORT 11218
#define TEST_DATA "test"
int level = -1;
char * msg = NULL;
char * buffer = NULL;
int level = -1;
char msg[1024];
char buffer[1024];
static void static void
read_hook(const char * _buffer) read_hook(const char * _buffer)
{ {
if (NULL != _buffer) { if (NULL != _buffer) {
buffer = malloc(strlen(_buffer) + 1);
strcpy(buffer, _buffer);
strncpy(buffer, _buffer, 1023);
} }
doShutdown = 1;
} }
static void static void
logfnct_mock(int _level, const char * _msg) logfnct_mock(int _level, const char * _msg)
{ {
level = _level; level = _level;
msg = malloc(strlen(_msg) + 1);
strcpy(msg, _msg);
strncpy(msg, _msg, 1023);
} }
const char testname[] = "serverTest"; const char testname[] = "serverTest";
@ -48,7 +52,6 @@ __setUp()
ASSERT_INSTANCE_OF(LOGGER, server->logger); ASSERT_INSTANCE_OF(LOGGER, server->logger);
ASSERT_INSTANCE_OF(SOCK, server->sock); ASSERT_INSTANCE_OF(SOCK, server->sock);
ASSERT_EQUAL(TEST_PORT, server->sock->port); ASSERT_EQUAL(TEST_PORT, server->sock->port);
ASSERT_EQUAL(server->max_fd, server->sock->handle);
server->read_hook = read_hook; server->read_hook = read_hook;
@ -62,9 +65,9 @@ __tearDown()
{ {
level = -1; level = -1;
if (NULL != msg) {
free(msg);
msg = NULL;
if (NULL != server) {
ASSERT_OBJECT(server);
delete(&server);
} }
if (NULL != logger) { if (NULL != logger) {
@ -72,11 +75,6 @@ __tearDown()
delete(&logger); delete(&logger);
} }
if (NULL != server) {
ASSERT_OBJECT(server);
delete(&server);
}
return TEST_OK; return TEST_OK;
} }
int (* const tearDown)() = __tearDown; int (* const tearDown)() = __tearDown;
@ -85,6 +83,32 @@ static
int int
testDummy() testDummy()
{ {
SOCK con;
pid_t pid;
int status;
pid = fork();
switch(pid) {
case 0:
con = new(SOCK, logger, TEST_PORT);
sleep(1);
sock_connect(con, "127.0.0.1");
write(con->handle, TEST_DATA, strlen(TEST_DATA)+1);
delete(&con);
__tearDown();
exit(EXIT_SUCCESS);
case -1:
return TEST_FAILED;
default:
init_signals();
server_run(server);
}
ASSERT_STRING_EQUAL(TEST_DATA, buffer);
return TEST_OK; return TEST_OK;
} }

3
tests/socketTest.c

@ -8,7 +8,7 @@
#include "socket.h" #include "socket.h"
#define TEST_PORT 11212
#define TEST_PORT 11213
int level = -1; int level = -1;
@ -98,7 +98,6 @@ testAccept()
delete(&con); delete(&con);
__tearDown(); __tearDown();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break;
case -1: case -1:
return TEST_FAILED; return TEST_FAILED;

Loading…
Cancel
Save